Thrift

初识Thrift

Thrift是一个跨语言通信的RPC软件,最初是由FaceBook开发的,现在是Apache的一个顶级项目。

Thrift概念:

Thrift 最初是由 Facebook 开发用做系统内各语言之间的 RPC 通信的一个可扩展且跨语言的软件框架,它结合了功能强大的软件堆栈和代码生成引擎,允许定义一个简单的定义文件中的数据类型和服务接口,以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。Thrift 是 IDL 描述性语言的一个具体实现,适用于程序对程序静态的数据交换,需要先确定好数据结构。Thrift 是完全静态化的,当数据结构发生变化时,必须重新编辑IDL文件、代码生成再编译载入的流程,跟其他IDL工具相比较可以视为是 Thrift 的弱项。Thrift 适用于搭建大型数据交换及存储的通用工具,在大型系统中的内部数据传输上相对于 JSON 和 XML 无论在性能、传输大小上有明显的优势。

什么是RPC

Remote Procedure Call Protocol 远程过程调用协议,我们 举个例子说明:

本地调用

public void invoke() {String param1="string1";String param2="string2";String res = getStr(param1,param2);System.out.println("res = " + res);
}private String getStr(String str1, String str2) {return str1 + str2;
}

调用方和被调用方都在一个程序内部,属于进程内调用。CPU 在执行调用时切换去执行被调用函数,执行完后再切换回来执行后续的代码。对调用方而言,执行被调用函数时会阻塞(非异步情况下)直到调用函数执行完毕。

RPC调用

public void test() {
TestQry.Client client = getClient("192.168.4.222", 7800, 5000);String param1="string1";String param2="string2";String res = client.getStr(param1,param2);System.out.println("res = " + res);
}

这里进程间调用,但是调用方和被调用方不再同一个进程,甚至不同的服务器和机房。进程间调用需要通过网络来传输数据,调用方在执行 RPC 调用时会阻塞(非异步情况下)直到调用结果返回才继续执行后续代码。

小结

现在应该知道什么是RPC了,概括一下就是:RPC是一种通过网络从远程计算机程序上请求服务的方式,它使得开发包括网络分布式多程序在内的应用程序更加容易。

Thrift结构

  • 代码框架层

Thrift 定义的服务接口描述文件生成的客户端和服务器端代码框架。

  • 数据读写操作层

是根据Thrift 文件生成代码实现数据的读写操作。Thrift允许定义一个简单的定义文件中的数据类型和服务接口,以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。

Thrift通信

一张图说明服务端启动与提供服务的流程:

程序调用了 TThreadPoolServer 的 serve() 方法后,server 进入阻塞监听状态,其阻塞在 TServerSocket 的accept()方法上。当接收到来自客户端的消息后,服务器发起一个新线程处理这个消息请求,原线程再次进入阻塞状态。在新线程中,服务器通过 TBinaryProtocol 协议读取消息内容,调用 HelloServiceImpl 的helloVoid() 方法,并将结果写入 helloVoid_result 中传回客户端。

 再来一张图说明服务端启动服务以后,客户端请求服务的流程:

程序调用了 Hello.Client 的 helloVoid() 方法,在 helloVoid() 方法中,通过 send_helloVoid() 方法发送对服务的调用请求,通过 recv_helloVoid() 方法接收服务处理请求后返回的结果。

Thrift数据类型

它支持这几大数据结构:基本类型、结构体和异常类型、容器类型、服务类型。

基本类型

  • ​ bool: 布尔值(true or false)

  • ​ byte: 有符号字节

  • ​ i16: 16位有符号整型

  • ​ i32: 32位有符号整型

  • ​ i64: 64位有符号整型

  • ​ double:64位浮点型

  • ​ string: 二进制字符串

结构体类型

struck UserDemo{1: i32 id;2: string name;3: i32 age = 25;4: string phone
}

结构体有几点要注意:

1:在java中,结构体会被转换成对象的类;

2:其成员都有明确的类型;

3:成员都是被正整数编号过的,这个编号不能重复;

4:在结构体中,可以直接设置默认值;

服务类型

service querySrv {/** 根据名字和年龄来查找用户 */UserDemo qryUser(1:string name, 2:i32 age);
​/** 根据id查找对应的手机号 */string queryPhone(1:i32 id);
}

服务类型说明:服务类型语法等同于Java中的接口。

小结

除了上面所提到的四大类型外,Thrift还支持枚举和常量类型。当然,它也有不支持的类型,典型的就是Date类型不支持。

Thrit组件

下面我们将围绕这三个组件展开介绍,内容略显枯燥,但是是使用Thrift的关键。

Protocol:数据通信协议

定义了消息是怎样序列化的,主要有二进制、文本。

常见的有:

◆TBinaryProtocol:这是Thrift的默认协议,使用二进制编码格式进行数据传输。

◆TCompactProtocol:压缩格式。

◆TJSONProtocol:以JSON数据编码协议进行数据传输。

◆TDebugProtocol:常常用以编码人员测试,以文本的形式展现方便阅读。

用户可以根据自己的实际需求选择合适的类型,生产环境一般用二进制类型的多

Transport:传输方式

定义了消息是怎样在客户端和服务器端之间通信的。

常见的有:

◆TSocket::采用TCP Socket进行数据传输。

◆ TFileTransport:文件(日志)传输类,允许client将文件传给server,允许server 将收到的数据写到文件中。

◆ THttpTransport:采用Http传输协议进行数据传输

◆ TZlibTransport:压缩后对数据进行传输,或者将收到的数据解压

下面几个类主要是对上面几个类的修饰(采用装饰模式),提高传输效率

◆ TBufferedTransport:对某个Transport对象操作的数据进行buffer,即从buffer中读取数据进行传输,或者将数据直接写入buffer◆ TFramedTransport:以frame(帧)为单位进行传输,非阻塞式服务中使用。同 TBufferedTransport类似,也会对相关数据进行buffer,同时,它支持定长数据发送和接收。◆ TMemoryBuffer:从一个缓冲区中读写数据◆ TTransport是所有Transport类的父类,为上层提供了统一的接口而且通过 TTransport 即可访问各个子类不同实现,类似多态。

Server Type: 服务端类型

server 用于从 transport 接收序列化的消息,根据 protocol 反序列化之,调用用户定义的消息处理器,并序列化消息处理器(接口实现类)的响应,然后再将它们写回 transport。

常用的server实现有:

◆ TSimpleServer:接受一个连接,处理连接请求,直到客户端关闭了连接,它才回去接受一个新的连接。正因为它只在一个单独的线程中以阻塞 I/O 的方式完成这些工作,所以它只能服务一个客户端连接,其他所有客户端在被服务器端接受之前都只能等待。

◆ TSimpleServer:主要用于测试目的,不要在生产环境中使用它。

◆ TNonblockingServer:阻塞在多个连接上,而不是阻塞在单一的连接上。 server 可同时服务多个客户端。

缺点:在业务处理上还是采用单线程顺序来完成,在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。

◆ THsHaServer:是TNonblockingServer类的子类,主线程负责数据读取,然后引入一个线程池来专门进行业务处理,缓解TNonblockingServer类的缺点。

缺点:主线程需要完成对所有socket的监听以及数据读写的工作,当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。

◆ TThreadPoolServer TThreadPoolServer模式采用阻塞socket方式工作,主线程负责阻塞式监听“监听socket”中是否有新socket到来,数据读取和业务处理都交由线程池完成,主线程只负责监听新连接。

缺点:线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。

◆ TThreadedSelectorServer: TThreadedSelectorServer模式是目前Thrift提供的最高级的模式。看图

TThreadedSelectorServer对于大部分应用场景性能都不会差,因此,如果实在不知道选择哪种工作模式,使用TThreadedSelectorServer就可以。

如何使用Thrift

Step1

使用IDL语言建立.thrift文件,示例:

/**文件名 TestQry.thrift实现的功能:创建一个查询结果struct和一个服务接口service。基于:thrift-0.9.2
*/
namespace java com.thrift
​
struct QryResult {/**返回码:1成功,0失败*/1:i32 code;/**响应信息*/2:string msg;
}
​
service TestQry {/**测试查询的接口,当qryCode值为1时候返回”成功”的响应信息,qryCode值为其他值时返回”失败”*/QryResult qryTest(1:i32 qryCode)
}

Step2

利用Thrift代码生成程序生成相应的java代码

1:将我们建立的TestQry.thrift文件与thrift-0.9.2.exe放在同一目录,如下:

2:执行命令,生成相应的java代码: thrift.exe -gen java TestQry.thrift

Step3

生成的java代码导入到你的maven项目中,添加相应的依赖包

Step4

创建QueryImp.java实现TestQry.Iface接口,这里写业务。

/**文件名 TestQry.thrift实现的功能:创建一个查询结果struct和一个服务接口service。基于:thrift-0.9.2
*/
namespace java com.thrift
​
struct QryResult {/**返回码:1成功,0失败*/1:i32 code;/**响应信息*/2:string msg;
}
​
service TestQry {/**测试查询的接口,当qryCode值为1时候返回”成功”的响应信息,qryCode值为其他值时返回”失败”*/QryResult qryTest(1:i32 qryCode)
}

Step5

创建ThriftServerDemo实现服务端,这里用TNonblockingServerSocket

public class ThriftServerDemo {private final static int DEFAULT_PORT = 30001;private static TServer server = null;public static void main(String[] args) {try {TNonblockingServerSocket socket = new TNonblockingServerSocket(DEFAULT_PORT);//1. 基于Handler创建ProcesserTestQry.Processor processor = new TestQry.Processor(new QueryImp());TNonblockingServer.Args arg = new TNonblockingServer.Args(socket);//2.创建protocolarg.protocolFactory(new TBinaryProtocol.Factory());//3.创建tansportarg.transportFactory(new TFramedTransport.Factory());arg.processorFactory(new TProcessorFactory(processor));//4.基于三者创建serverserver = new TNonblockingServer(arg);//5.运行serverserver.serve();} catch (TTransportException e) {e.printStackTrace();}}
}

Step6

public class ThriftClientDemo {private final static int DEFAULT_QRY_CODE = 1;public static void main(String[] args) {//1.创建transportTTransport tTransport = getTTransport();//2.创建protocolTProtocol protocol = new TBinaryProtocol(tTransport);//3.创建clientTestQry.Client client = new TestQry.Client(protocol);QryResult result = null;try {//运行client的方法result = client.qryTest(DEFAULT_QRY_CODE);} catch (TException e) {e.printStackTrace();}System.out.println("code="+result.code+" "+"msg="+result.msg);}
​public static TTransport getTTransport() {TTransport tTransport = getTTransport("127.0.0.1", 30001, 5000);if (!tTransport.isOpen()){try {tTransport.open();} catch (TTransportException e) {e.printStackTrace();}}return tTransport;}
​private static TTransport getTTransport(String host, int port, int timeout) {final TSocket tSocket = new TSocket(host, port, timeout);final TTransport transport = new TFramedTransport(tSocket);return transport;}
}

Step7

所有准备工作都已经做好了,接下来我们就来进行 Client 和 Server 的通信。

先运行 ThriftServerDemo 启动 Server,然后运行 ThriftClientDemo.java 创建 Client进行调用,以上步骤都是我自己写过的,可以得到结果。

结语

Thrift有什么优势?

Thrift是一个跨语言通信的服务框架,不同语言开发的程序可以通过Thrift来进行通信:通过编译一个后缀名为.thrift的文件来生成指定语言的代码,通过生成的代码我们就可以编写出跨语言通信的代码了:如服务端是用Thrift生成的Java代码,客户端使用Thrift生成的C++/C#代码,用Thtift可以完成C++代码到Java代码的调用,而不需要关心其他如网络通信等内容,可以让开发人员专注于业务实现。

Thrift为什么这么好用?

网络编程需要关注很多数据传输中的细节,比如数据如何序列化、如何在字节数组里建立结构、如何在两端解析字节数组、如何处理Handler里的事件状态、如何把多个Handler按顺序串起来,Thrift掩盖了数据传输这件事情,开发者使用的时候就是纯纯的RPC的使用感受。

Thrift基本原理以及使用介绍相关推荐

  1. 乒乓RAM基本原理和操作介绍

    引言      乒乓操作是一个非常常用的数据流控制处理技巧,乒乓RAM源于乒乓操作的基本原理,本节将对乒乓RAM作一个简单的介绍,也作为平常学习笔记的一个记录,等忘记后可以回来复习复习. 主要内容 乒 ...

  2. 计算机开关电源基本原理,开关电源基本原理与设计介绍——第一讲

    一.开关电源基本概念 开关电源是利用现代电力电子技术,控制开关管开通和关断的时间比率,维持稳定输出电压的一种电源.随着电力电子技术的发展和创新,使得开关电源技术也在不断地创新.目前,开关电源以小型.轻 ...

  3. IPv6 基本原理详解介绍

    文章目录 一.IPv6报文格式 基本报头 扩展报头 IPv6和IPv4报头比较 二.IPv6编址技术 IPv6地址表示 IPv6地址结构 地址类型 EUI-64 单播地址 IPv6组播地址 IPv6任 ...

  4. VIP_OSP--基于Thrift的RPC框架的基本原理

    公司(VIP)从2015年开始在内部推动Venus框架的使用,这是一款基于Apache Thrift远程调用框架二次开发的高性能.高可扩展的.服务治理的RPC框架.服务端使用IDL进行服务的定义,客户 ...

  5. 大脑结构和功能复杂网络的图论分析——回顾复杂大脑网络的各种实验方法(包括人类的结构和功能MRI,扩散张量成像,磁脑图和脑电图),介绍图论的基本原理

    复杂大脑网络:结构和功能系统的图论分析 文章Complex brain networks: graph theoretical analysis of structural and functiona ...

  6. Thrift框架介绍

    1.前言 Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目.Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和 ...

  7. 多线程系列之学习多线程下载的基本原理和基本用法(1)

    多线程下载在我们生活中非常常见,比如迅雷就是我们常用的多线程的下载工具,当然还有断点续传,断点续传我们在下一节来讲,android手机端下载文件时也可以用多线程下载,我们这里是在java中写一个测试, ...

  8. Thirft框架介绍

    http://dongxicheng.org/search-engine/thrift-framework-intro/ 1.前言 Thrift是一个跨语言的服务部署框架,最初由Facebook于20 ...

  9. Apache Thrift - 可伸缩的跨语言服务开发框架

    简介: Apache Thrift 是 Facebook 实现的一种高效的.支持多种编程语言的远程服务调用的框架.本文将从 Java 开发人员角度详细介绍 Apache Thrift 的架构.开发和部 ...

最新文章

  1. 解决Redhat Linux AS使用yum时出现This system is not registered with RHN的问题(改用CentOS的yum)...
  2. 计算机专业学生却被强迫工厂实习?结果发生意外手指被截肢,学校回应:会治到满意为止...
  3. 优化mysql数据库_MySQL数据库十大优化技巧
  4. 因为难看的签名尴尬?Python爬虫制作艺术签名软件!
  5. 不止是 Oracle 读物
  6. python虚拟环境安装包_Python虚拟环境的创建和包下载过程分析
  7. Centos7开放及查看端口
  8. 用户体验标准_产品体验问题评级标准——如何给产品体验问题定级?
  9. 卷积神经网络第四周作业2: Art Generation with Neural Style Transfer - v1
  10. MediaCoder压缩参数设置
  11. 推荐支持 azw3 、epub 和 mobi 格式的阅读器:FBReader
  12. 两种MBR分区表恢复方法
  13. PS 图层的基本操作
  14. 点云配准1-ICP算法 原理代码实现
  15. 关于Pytorch中detach
  16. java batter_android电池管理系统从上层的java到底层驱动的调用(转载)
  17. 条件概率公式图解推导
  18. 开源GIS浅谈 【转】
  19. java 模拟登录58同城,Java项目实战之同城信息网站(类似58同城)开发
  20. 拍卖行做VC,第一次出手就投了个Web3

热门文章

  1. pdf文件被加密怎么解开,pdf不能复制打印、pdf忘记密码怎么办?
  2. 战争艺术鸿蒙返场,战争艺术 SS2赛季隆重登场 且看大神如何替你排忧解难
  3. 皮肤检测算法三种,示例与代码
  4. eclispe安装windowBuilder出错问题解决
  5. 网工必备工具,你用过几个??
  6. WIN32学习——鼠标消息
  7. jasperreport mysql_一步一步学iReport + JasperReports(二) :JasperReport初级教
  8. Git 冲突的解决方法
  9. python找人脚本_python 自动刷人气脚本
  10. Android自学笔记 第四天(下)