一、Thrift介绍

    Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎。其允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。
二、Thrift基础架构                                                           
  • Thrift 支持的数据类型
1、基本类型
  bool: 布尔值
  byte: 8位有符号整数
  i16: 16位有符号整数
  i32: 32位有符号整数
  i64: 64位有符号整数
  double: 64位浮点数
  string: UTF-8编码的字符串
  binary: 二进制串
2、结构体类型
  struct: 定义的结构体对象
3、容器类型
Thrift容器与类型密切相关,它与当前流行编程语言提供的容器类型相对应,采用java泛型风格表示。Thrift提供了3种容器类型:
  list<t1>: 一系列t1类型的元素组成的有序表,元素可以重复
  set: <t1>:一系列t1类型的元素组成的无序表,元素唯一
  map<t1,t2>:key/value对(key的类型是t1且唯一,value类型是t2)
容器中的元素类型可以是除了service意外的任何合法thrift类型(包括结构体和异常)
4、异常类型:
  exception: 异常类型
5、服务类型:
  service: 具体对应服务的类
  • 协议
     Thrift可以让你选择客户端与服务端之间传输通信协议的类别,在传输协议上总体上划分为文本(text)和二进制(binary)传输协议, 为节约带宽,提供传输效率,一般情况下使用二进制类型的传输协议为多数,但有时会还是会使用基于文本类型的协议,这需要根据项目/产品中的实际需求:
    1、TBinaryProtocol – 二进制编码格式进行数据传输。
    2、TCompactProtocol – 这种协议非常有效的,使用Variable-Length Quantity (VLQ) 编码对数据进行压缩。
    3、TJSONProtocol – 使用JSON的数据编码协议进行数据传输。
    4、TSimpleJSONProtocol – 这种节约只提供JSON只写的协议,适用于通过脚本语言解析
    5、TDebugProtocol – 在开发的过程中帮助开发人员调试用的,以文本的形式展现方便阅读。
  • 传输层
    1、TSocket- 使用堵塞式I/O进行传输,也是最常见的模式。
    2、TFramedTransport- 使用非阻塞方式,按块的大小,进行传输,类似于Java中的NIO。
    3、TFileTransport- 顾名思义按照文件的方式进程传输,虽然这种方式不提供Java的实现,但是实现起来非常简单。
    4、TMemoryTransport- 使用内存I/O,就好比Java中的ByteArrayOutputStream实现。
    5、TZlibTransport- 使用执行zlib压缩,不提供Java的实现。
三、Thrift网络服务模型                                                   
   Thrif 提供网络模型:单线程、多线程、事件驱动。从另一个角度划分为:阻塞服务模型、非阻塞服务模型。

  • 阻塞服务
  1. TSimpleServer:简单的单线程服务模型,主要用于测试
  2. TThreadPoolServer:多线程服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求
  • 非阻塞服务模型
  1. TNonblockingServer:多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式),只有一个线程来处理消
  2. THsHaServer:半同步半异步的服务模型,一个单独的线程用来处理网络I/O,一个worker线程池用来进行消息的处理
  3. TThreadedSelectorServer:允许你用多个线程来处理网络I/O。它维护了两个线程池,一个用来处理网络I/O,另一个用来进行请求的处理
     1、TSimpleServer
      TSimpleServer实现是非常的简单,循环监听新请求的到来并完成对请求的处理,是个单线程阻塞模型。由于是一次只能接收和处理一个socket连接,效率比较低,在实际开发过程中很少用到它。
/** * 注册服务端 *  单线程服务模型,使用标准的阻塞式IO,只有一个线程处理请求 */
public static void startSimpleServer(AdditionService.Processor<AdditionServiceHandler> processor) {try {TServerTransport serverTransport = new TServerSocket(9090);// 设置服务端口// 单线程服务模型TSimpleServer.Args tArgs = new TSimpleServer.Args(serverTransport);tArgs.processor(processor);// 客户端协议要一致tArgs.protocolFactory(new TBinaryProtocol.Factory());TServer server = new TSimpleServer(tArgs);System.out.println("Starting the simple server...");server.serve();} catch (Exception e) {e.printStackTrace();}
}

   2、TThreadPoolServer

       ThreadPoolServer为解决了TSimpleServer不支持并发和多连接的问题, 引入了线程池。但仍然是多线程阻塞模式即实现的模型是One Thread Per Connection。
       线程池采用能线程数可伸缩的模式,线程池中的队列采用同步队列(SynchronousQueue)。
       ThreadPoolServer拆分了监听线程(accept)和处理客户端连接的工作线程(worker), 监听线程每接到一个客户端, 就投给线程池去处理。
/*** 注册服务端*     线程池服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求*/
public static void startMultipleServer(AdditionService.Processor<AdditionServiceHandler> processor) {try {TServerTransport serverTransport = new TServerSocket(9090);// 设置服务端口//线程池服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求。TThreadPoolServer.Args tArgs = new TThreadPoolServer.Args(serverTransport);tArgs.processor(processor);// 客户端协议要一致tArgs.protocolFactory(new TBinaryProtocol.Factory());TServer server = new TThreadPoolServer(tArgs);System.out.println("Hello TThreadPoolServer....");server.serve(); // 启动服务} catch (Exception e) {e.printStackTrace();}
}

这两个服务端可以处理同样的客户端:

/*** 客户端调用* 阻塞* Created by Administrator on 2017/1/12.*/
public class AdditionClient {public static void main(String[] args) {try {TTransport transport;// 设置传输通道transport = new TSocket("localhost", 9090);//使用堵塞式I/O进行传输transport.open();// 协议要和服务端一致// 使用二进制协议TProtocol protocol = new TBinaryProtocol(transport);AdditionService.Client client = new AdditionService.Client(protocol);System.out.println(client.add(100, 200));transport.close();} catch (TTransportException e) {e.printStackTrace();} catch (TException x) {x.printStackTrace();}}}
  TThreadPoolServer模式优点:
       线程池模式中,数据读取和业务处理都交由线程池完成,主线程只负责监听新连接,因此在并发量较大时新连接也能够被及时接受。线程池模式比较适合服务器端能预知最多有多少个客户端并发的情况,这时每个请求都能被业务线程池及时处理,性能也非常高。
    TThreadPoolServer模式缺点:
       线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。
3、TNonblockingServer
       TNonblockingServer采用单线程非阻塞(NIO)的模式, 借助Channel/Selector机制, 采用IO事件模型来处理。所有的socket都被注册到selector中,在一个线程中通过seletor循环监控所有的socket,每次selector结束时,处理所有的处于就绪状态的socket,对于有数据到来的socket进行数据读取操作,对于有数据发送的socket则进行数据发送,对于监听socket则产生一个新业务socket并将其注册到selector中。
/*** TNonblockingServer采用单线程非阻塞(NIO)的模式* @param processor*/
public static void nonBlockingServer(AdditionService.Processor<AdditionServiceHandler> processor) {try {// 传输通道 - 非阻塞方式TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090);// 设置服务端口// 异步IO,需要使用TFramedTransport,它将分块缓存读取。TNonblockingServer.Args tArgs = new TNonblockingServer.Args(serverTransport);tArgs.processor(processor);tArgs.transportFactory(new TFramedTransport.Factory());// 使用高密度二进制协议tArgs.protocolFactory(new TCompactProtocol.Factory());// 使用非阻塞式IO,服务端和客户端需要指定TFramedTransport数据传输的方式TServer server = new TNonblockingServer(tArgs);System.out.println("Starting the simple server...");server.serve();// 启动服务} catch (Exception e) {e.printStackTrace();}
}

查看TNonblockingServer的源码,我们可以看到select()方法:

private void select() {try {this.selector.select();Iterator e = this.selector.selectedKeys().iterator();while(!TNonblockingServer.this.stopped_ && e.hasNext()) {SelectionKey key = (SelectionKey)e.next();e.remove();if(!key.isValid()) {this.cleanupSelectionKey(key);} else if(key.isAcceptable()) {this.handleAccept();} else if(key.isReadable()) {this.handleRead(key);} else if(key.isWritable()) {this.handleWrite(key);} else {TNonblockingServer.this.LOGGER.warn("Unexpected state in select! " + key.interestOps());}}} catch (IOException var3) {TNonblockingServer.this.LOGGER.warn("Got an IOException while selecting!", var3);}}
select代码里对accept/read/write等IO事件进行监控和处理, 但由于这是单线程处理,所以当遇到handler里有阻塞的操作时, 会导致整个服务被阻塞住。
 TNonblockingServer模式优点:
  相比于TSimpleServer效率提升主要体现在IO多路复用上,TNonblockingServer采用非阻塞IO,同时监控多个socket的状态变化;
 TNonblockingServer模式缺点:
  TNonblockingServer模式在业务处理上还是采用单线程顺序来完成,在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。
4、THsHaServer
     THsHaServer类是TNonblockingServer类的子类,为解决TNonblockingServer的缺点, THsHa引入了线程池去处理, 其模型把读写任务放到线程池去处理即多线程非阻塞模式。HsHa是: Half-sync/Half-async的处理模式, Half-aysnc是在处理IO事件上(accept/read/write io), Half-sync用于handler对rpc的同步处理上。因此可以认为THsHaServer半同步半异步。
/***  THsHaServer*  THsHaServer类是TNonblockingServer类的子类* @param processor*/
public static void startTHsHaServer(AdditionService.Processor<AdditionServiceHandler> processor) {try {// 传输通道 - 非阻塞方式TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090);// 设置服务端口// 异步IO,需要使用TFramedTransport,它将分块缓存读取。THsHaServer.Args tArgs = new THsHaServer.Args(serverTransport);tArgs.processor(processor);tArgs.transportFactory(new TFramedTransport.Factory());// 使用高密度二进制协议tArgs.protocolFactory(new TCompactProtocol.Factory());// 使用非阻塞式IO,服务端和客户端需要指定TFramedTransport数据传输的方式TServer server = new THsHaServer(tArgs);System.out.println("Starting the simple server...");server.serve();// 启动服务} catch (Exception e) {e.printStackTrace();}
}
     THsHaServer的优点:
      与TNonblockingServer模式相比,THsHaServer在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升;
    THsHaServer的缺点:
     主线程需要完成对所有socket的监听以及数据读写的工作,当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。
 5、TThreadedSelectorServer
     TThreadedSelectorServer是大家广泛采用的服务模型,其多线程服务器端使用非堵塞式I/O模型,是对TNonblockingServer的扩充, 其分离了Accept和Read/Write的Selector线程, 同时引入Worker工作线程池。
    (1)一个AcceptThread线程对象,专门用于处理监听socket上的新连接;
    (2)若干个SelectorThread对象专门用于处理业务socket的网络I/O操作,所有网络数据的读写均是有这些线程来完成;
    (3)一个负载均衡器SelectorThreadLoadBalancer对象,主要用于AcceptThread线程接收到一个新socket连接请求时,决定将这个新连接请求分配给哪个SelectorThread线程。
    (4)一个ExecutorService类型的工作线程池,在SelectorThread线程中,监听到有业务socket中有调用请求过来,则将请求读取之后,交给ExecutorService线程池中的线程完成此次调用的具体执行
MainReactor就是Accept线程, 用于监听客户端连接, SubReactor采用IO事件线程(多个), 主要负责对所有客户端的IO读写事件进行处理. 而Worker工作线程主要用于处理每个rpc请求的handler回调处理(这部分是同步的)。因此其也是Half-Sync/Half-Async(半异步-半同步)的 。
    TThreadedSelectorServer模式对于大部分应用场景性能都不会差,因为其有一个专门的线程AcceptThread用于处理新连接请求,因此能够及时响应大量并发连接请求;另外它将网络I/O操作分散到多个SelectorThread线程中来完成,因此能够快速对网络I/O进行读写操作,能够很好地应对网络I/O较多的情况。
/***  TThreadedSelectorServer*  是多线程服务器端使用非堵塞式I/O模型* @param processor*/public static void startTThreadedSelectorServer(AdditionService.Processor<AdditionServiceHandler> processor) {try {// 传输通道 - 非阻塞方式TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090);// 设置服务端口// 异步IO,需要使用TFramedTransport,它将分块缓存读取。TThreadedSelectorServer.Args tArgs = new TThreadedSelectorServer.Args(serverTransport);tArgs.processor(processor);tArgs.transportFactory(new TFramedTransport.Factory());// 使用高密度二进制协议tArgs.protocolFactory(new TCompactProtocol.Factory());// 使用非阻塞式IO,服务端和客户端需要指定TFramedTransport数据传输的方式TServer server = new TThreadedSelectorServer(tArgs);System.out.println("Starting the simple server...");server.serve();// 启动服务} catch (Exception e) {e.printStackTrace();}}

上面三种非阻塞服务模型可以处理这样的客户端:

public static void main(String[] args) {try {// 设置传输通道,对于非阻塞服务,需要使用TFramedTransport,它将数据分块发送TSocket socket = new TSocket("localhost", 9090);//使用堵塞式I/O进行传输//使用非阻塞方式,按块的大小,进行传输,类似于Java中的NIOTTransport transport = new TFramedTransport(socket);// 协议要和服务端一致// 使用高密度二进制协议TProtocol protocol = new TCompactProtocol(transport);AdditionService.Client client = new AdditionService.Client(protocol);transport.open();System.out.println(client.add(100, 100));transport.close();} catch (TTransportException e) {e.printStackTrace();} catch (TException x) {x.printStackTrace();}
}
由于能力有限,文章有很多不足之处,请大家不吝赐教,剩下的代码我会上传源码,大家可以下载下来查看
源代码
参考:

http://www.cnblogs.com/exceptioneye/p/4945073.html
https://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/
http://blog.csdn.net/chen8238065/article/details/50846104
http://wenku.baidu.com/link?url=gXi2VOh-92R6T-ByYm7penf4KDj9riEfLKkai3Y0SjTkd_qKl2PIgnnStjnsjNbEmZDcs9KJt1BBYDQ1hS5ukzn2y7ZE397_AOm_eF3G-QC

Thrift协议的服务模型相关推荐

  1. go通过thrift连接hbase_关于thrift协议改进畅想

    Thrift简介 thrift协议你主要提供3种编解码格式协议,Binary.Compact.SimpleJson(还有debug.virtual):其中最常用的是Binary协议,其传输层一般以Bu ...

  2. Thrift协议与传输选择

    1 协议 Thrift 可以让用户选择客户端与服务端之间传输通信的消息协议类别,如我们前面所讲总体划分为文本 (text) 和二进制 (binary) ,为节约带宽,提高传输效率,一般情况下使用二进制 ...

  3. go语言使用thrift协议实现客户端和服务端报not enough arguments in call to oprot.WriteMessageBegin错误解决方案

    正常步骤: 安装golang的Thrift包: go get git.apache.org/thrift.git/lib/go/thrift 安装 Thrift 的 IDL 编译工具: http:// ...

  4. Thrift介绍以及Java中使用Thrift实现RPC示例

    场景 Thrift Thrift最初由Facebook研发,主要用于各个服务之间的RPC通信,支持跨语言,常用的语言比如C++, Java, Python,PHP, Ruby, Erlang,Perl ...

  5. 10-20-000-简介-Thrift

    1. Thrift传输格式 TBinaryProtocol一二进 制格式 TCompactProtocol -压缩 格式 TJSONProtocol - JSON格式 TSimpleJSONProto ...

  6. SpringBoot整合RPC框架---Thrift

    文章目录 什么是Thrift 架构 支持的通讯协议 支持的传输协议 支持的服务模型 Thrift的优点 SpringBoot整合Thrift 为什么会出现RPC框架 常见的RPC框架集成套路 开撸 官 ...

  7. springboot整合Thrift

    什么是Thrift Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务.它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为"大规模跨语言服务开发 ...

  8. RPC协议之争和选型要点

    <Netty 进阶之路>.<分布式服务框架原理与实践>作者李林锋深入剖析RPC协议之争和选型问题.李林锋此后还将在 InfoQ 上开设 Netty 专题持续出稿,感兴趣的同学可 ...

  9. java服务端开发 php_PHP使用thrift做服务端开发

    php中文网最新课程 每日17点准时技术干货分享 php使用thrift做服务端开发 thrift采用接口描述语言定义和创建服务,用二进制格式传输数据,体积更小.效率更高,对于高并发.数据量大和多语言 ...

最新文章

  1. 【连载】优秀程序员的 45 个习惯之习惯27
  2. 将一个PPT文档按页分割成多个PPT文档的代码
  3. 《LeetCode力扣练习》第64题 最小路径和 Java
  4. linux 怎么改授权用户权限,linux – systemd:授予非特权用户权限以更改某个特定服务...
  5. 利用RSM和RSFC配置VLAN间路由
  6. 剑指offer面试题26. 树的子结构(链表)
  7. 把标清视频转高清Video Enhance AI for mac
  8. 层间距离对ct图像的影响_CT图像影响因素
  9. qq企业邮箱登录服务器,腾讯邮箱登录入口(腾讯企业邮箱免费用户申请)
  10. 看看阿里双十一970P数据处理得,那叫一个牛啤!
  11. 关于 “总机服务” 新增功能来电弹屏的功能说明
  12. 一个读者大佬精心总结的阿里、腾讯、宇宙条大厂 Offer 面经和硬核面试攻略
  13. model.train()与model.eval()的用法、Dropout原理、relu,sigmiod,tanh激活函数、nn.Linear浅析
  14. SocialBoo出海指南 || 海外网红营销深度报告
  15. 模压硅胶产品成型后加工工艺
  16. 【网络】解释Http协议,URL,Http的格式。
  17. 网络游戏外挂制作(3)-1
  18. kibana启动报错 Elasticsearch cluster did not respond with license information
  19. iOS - 需求 - 微信扫描二维码支付(草稿)
  20. 基于差分进化算法(DE)改进的jDE2 处理约束优化问题

热门文章

  1. mac. mysql 设置root_Mac平台重新设置MySQL的root密码
  2. 怎么用python爬豆瓣_python爬虫16 | 你,快去试试用多进程的方式重新去爬取豆瓣上的电影...
  3. 在python中、如果异常并未被处理或捕捉_Python异常处理总结
  4. python商品会员打折_Python微项目分享之双十一优惠计算器
  5. java默认virtual_mac jdk配置(系统默认or自己配置)
  6. oracle有条件插入数据,Oracle有条件地插入数据
  7. vue3中v-model的重大更新
  8. mysql求利润_SQL分析超市数据
  9. python找出只出现一次的数字_【LeetCode 136】只出现一次的数字(Python)
  10. android alertdialog view,Android AlertDialog 方法setView(view,0,0,0,0)开发自定义对话框