Facebook 的 Thrift
更多内容,前往个人博客
Thrift 源于 Facebook,在 2007 年 Facebook 将 Thrift 作为一个开源项目提交给了 Apache 基金会。对于当时的 Facebook 来说,创造 Thrift 是为了解决 Facebook 各系统间大数据量的传输通信以及系统之间语言环境不同需要跨平台的特性,因此 Thrift 可以支持多种程序语言,如 C++、C#、Cocoa、Erlang、Haskell、Java、Ocami、Perl、PHP、Python、Ruby 和 Smalltalk。它被当作一个远程过程调用(RPC)框架来使用。
在多种不同的语言之间通信,Thrift 可以作为高性能的通信中间件使用,它支持数据(对象)序列化和多种类型的 RPC 服务。Thrift 适用于静态的数据交换,需要先确定好它的数据结构,当数据结构发生变化时,必须重新编辑 IDL 文件、生成代码和编译,这一点跟其他 IDL 工具相比可以视为是 Thrift 的弱项。Thrift 适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输,相对于 JSON 和 XML 在性能和传输大小上都有明显的优势。
一、Thrift 主要由5部分组成
1)、语言系统以及 IDL 编译器:负责由用户给定的 IDL 文件生成相应语言的接口代码;
2)、TProtocol:RPC 的协议层,可以选择多种不同的对象序列化方法,如 JSON 和 Binary;
3)、TTransport:RPC 的传输层,同样可以选择不同的传输层实现,如 Socket、NIO、MemoryBuffer 等;
4)、TProcessor:作为协议层和用户提供的服务实现之间的纽带,负责调用服务实现的接口;
5)、TServer:聚合TProtocol、TTransport 和 TProcessor 等对象;
我们重点关注的是编解码框架,与之对应的就是 TProtocol。由于 Thrift 的 RPC(Remote Procedure Call) 服务调用和编解码框架绑定在一起,所以 ,通常使用 Thrift 的时候会采取 RPC 框架的方式。但是,它的 TProtocol 编解码框架还是可以以类库的方式独立使用的。
与 Protobuf(Google的Protobuf) 比较类似的是,Thrift 通过 IDL 描述接口和数据结构定义,它支持 8种 Java 基本类型、Map、Set和 List,支持可选和必须定义,功能非常强大。因为可以定义数据结构中字段的顺序,所以它也可以支持协议的前向兼容。
二、Thrift 支持三种比较典型的编解码方式
■ 通用的二进制编解码;
■ 压缩二进制编解码;
■ TJSONProtocol:JSON 格式;
■ 优化的可选字段压缩编解码;
由于支持二进制压缩编解码,Thrift 的编解码性能表现也相当优异,远远超过 Java序列化和 RMI等。
Thrift 工作原理(实现多语言间的通信):数据的传输使用 socket(多种语言均支持),数据在以特定的格式(String等)发送,接收方按对应的格式进行解析。定义 thrift 文件,有 thrift 文件(IDL)生成双方语言的接口、Model,在生成接口和 Model 的代码中包含编解码的代码。
三、Thrift 数据/容器类型
Thrift 通过中间件语言IDL(接口定义语言)来定义 RPC 的数据类型和接口,这些内容写在以 .thrift 结尾的文件中。然后通过特殊的编译器来生成不同语言的代码,以满足不同需求的开发者。比如 java开发者,就可以生成 java代码,c++开发者可以生成 c++代码,生成的代码中不但包含目标语言的接口定义、方法、数据类型,还包含有 RPC协议层和传输层的实现代码。
Thrift 不支持无符号类型,因为很多语言不存在无符号类型,比如 Java。
■ byte:有符号字节;
■ i16:16位有符号整数;
■ i32:32位有符号整数;
■ i64:64位有符号整数;
■ double:64位浮点数;
■ string:字符串
容器类型:List、Set、Map:与 Java 中的类型类似。
四、Thrift 的协议栈结构
Thrift 是一种 C/S 的架构体系。TServer 主要任务是高效的接受客户端请求,并将请求转发给 TProcessor 处理。
■ 最上层是用户自行实现的业务逻辑代码;
■ Processor 是由 thrift 编译器自动生成的代码,它封装了从输入流中读取数据和向数据流中写数据的操作,它的主要工作是:从连接中读取数据,把处理交给用户实现 impl,最后把结果写入连接;
■ TProtocol 是用于数据类型解析的,将结构化数据转化为字节流给 TTransport进行传输。从 TProtocol以下部分是 thirft的传输协议和底层 I/O通信;
■ TTransport 是与底层数据传输密切相关的传输层,负责以字节流方式接收和发送消息体,不关注是什么数据类型;
■ 底层 IO 负责实际的数据传输,包括 socket、文件和压缩数据流等;
五、Thrift IDL 文件
1 namespace java com.test.thrift.demo
2
3 struct News {
4 1:i32 id;
5 2:string titie;
6 3:string content;
7 4:string mediaFrom;
8 5:string autor;
9 }
10
11 service IdenxNewsCreratorServices {
12 bool indexNews(1:NewsModel indexNews),
13 bool removeNewsById(1:i32 id)
14 }
15
16 enum Gender {
17 MALE,
18 FEMALE
19 }
20
21 exception RequestExce {
22 1:i32 id;
23 2:string titie;
24 }
【1】结构体(struct):就像 C语言一样,Thrift 支持 Struct 类型,目的就是将一些数据聚合在一起方便传输管理。
【2】枚举(enum):定义形式与 Java 的定义形式类似。
【3】异常(exception):支持自定义 exception,规则与 Struct 一致。
【4】服务(service):Thrift 定义服务相当于 java 中创建 interface 一样,创建的 service 经过代码命名之后就会生成客户端和服务端的框架代码。相当于若干个方法的集合。
【5】类型定义:支持类型C++ 一样的 typedef 定义:typedef i32 int ,后续的操作就可以使用 int 代替 i32
【6】常量(const):使用 const 关键字:const i32 MAX_RETRIES_TIME = 10
【7】命名空间:相当于 java中的 package的意思,主要的目的是组织代码。thrift 的关键字 namespace:namespace 语言名(java) 路径(com.test.thrit.demo)
【8】文件包含:Thrift 也支持文件包含,相当于C/C++ 中的 include,Java 中的 import。
include "test.thrift"
【9】注释:Thrift 注释支持 shell 风格的注释,支持 C/C++ 风格的注释,既#和//开头的都可以当注释,/**/包裹的可以当做注释。
【10】可选和必选:Thrift 提供了两个关键字:required 和 optional 分别用于字段的必填和可选。
六、Thrift 安装
官网下载地址:http://thrift.apache.org/download
将下载的*.exe 所处的目录,配置在 path 环境变量中,并重命名为 thrift.exe 即可(测试:thrift -version)
七、代码生成
【1】定义一个 .thrift 文件:data.thrift
1 namespace java com.thrift
2 #数据类型转化
3 typedef i16 short
4 typedef i32 int
5 typedef i64 log
6 typedef bool boolean
7 typedef string String
8 #定义类
9 struct Person {
10 1: optional String username,
11 2: optional int age,
12 3: optional boolean married
13 }
14 #定义异常类
15 exception DataException {
16 1:optional String message,
17 2:optional String callStack,
18 3:optional String date
19 }
20
21 #定义方法
22 service PersionService {
23 Person getPersonByUsername(1:required String username) throws (1:DataException dataException),
24 void savePerson(1:required Person person) throws (1:DataException dataException)
25 }
【2】执行命令格式: thrift --gen java 文件路径
【3】生成目录结构如下:
【4】导入依赖的 jar 包:
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.12.0</version>
</dependency>
八、数据传输方式
【1】TSocket:阻塞式 socket(效率底);
【2】(常用)TFramedTransport:以 Frame 为单位进行传输,非阻塞式服务中使用;
【3】TFileTransport:以文件形式进行传输;
【4】TMemoryTransport:将内存用于I/O,Java 实现时内容实际使用了简单的 ByteArraryOutPutStream;
【5】TZlibTransport:使用 Zlib 进行压缩与其他传输方式联合使用,当前无 Java 实现;
九、 Thrift 支持的服务模式
【1】TSimpleServer:简单的单线程服务模型,常用语测试;
【2】TThreadPoolServer:多线程服务模型,使用标准的阻塞式IO;
【3】TNonblockingServer:多线程服务模型,使用非阻塞式IO(需使用 TFramedTransport 传输数据)
【4】THsHaServer:(常用)THsHa 引入了线程池去处理,其模型把读写任务放到线程池去处理;Half-sync/Half-async 的处理模式,Half-aysnc 是在处理IO事件上(accept/read/write io),Half-sync 用于 handler 对 rpc 的同步处理。
十、Thrift 服务端与客户端交互
【1】服务端实现类
1 public class PersionServiceImpl implements PersionService.Iface {
2 @Override
3 public Person getPersonByUsername(String username) throws DataException, TException {
4 Person person = new Person();
5 person.setAge(2);
6 person.setUsername("zhengzhaoxiang");
7 person.setMarried(false);
8 return person;
9 }
10
11 @Override
12 public void savePerson(Person person) throws DataException, TException {
13 System.out.printf("服务端");
14 System.out.printf(person.getUsername());
15
16 }
17 }
【2】thrift 服务端程序编写
1 public class Server {
2 public static void main(String[] args) throws Exception {
3 TNonblockingServerSocket socket = new TNonblockingServerSocket(8899);
4 //服务 引入了线程池去处理
5 THsHaServer.Args arg = new THsHaServer.Args(socket).minWorkerThreads(2).maxWorkerThreads(4);
6 PersionService.Processor<PersionServiceImpl> processor = new PersionService.Processor<>(new PersionServiceImpl());
7
8 arg.protocolFactory(new TCompactProtocol.Factory());
9 arg.transportFactory(new TFramedTransport.Factory());
10 arg.processorFactory(new TProcessorFactory(processor));
11 TServer server = new THsHaServer(arg) ;
12 System.out.println("服务端启动。。。。");
13 server.serve();
14 }
15 }
【3】thrift 客户端程序编写
1 public class PersionClient {
2 public static void main(String[] args) {
3 TTransport tTransport = new TFramedTransport(new TSocket("localhost",8899),600);
4 TProtocol protocol = new TCompactProtocol(tTransport);
5 PersionService.Client client = new PersionService.Client(protocol);
6
7 try {
8 tTransport.open();
9 Person person = client.getPersonByUsername("zhangsan");
10 System.out.println(person.getUsername());
11 System.out.println(person.getAge());
12 System.out.println(person.isMarried());
13 System.out.println("---------");
14
15 Person person1 = new Person();
16 person1.setMarried(true);
17 person1.setAge(20);
18 person1.setUsername("李四");
19 client.savePerson(person1);
20 } catch (Exception e) {
21 e.printStackTrace();
22 tTransport.close();
23 }
24 }
25 }
【4】测试结果(客户端/服务端)展示:
----关注公众号,获取更多内容----
Facebook 的 Thrift的更多相关文章
- thrift:swift项目笔记
先声明:此swift不是Apple公司的那个swift开发语言,而是facebook的另一个开源项目. facebook的thrift IDL文件,如果默认用thrift -gen java生成jav ...
- 【thrift】thrift详解
转载:http://zheming.wang/thrift-rpcxiang-jie.html Thrift Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年 ...
- Thrift 原理与使用实例
一.Thrift 框架介绍 1.前言 Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目.Thrift通过一个中间语言(IDL, 接口定 ...
- [thrift] thrift基本原理及使用
参考文章RPC 基本原理与 Apach Thrift 初体验 RPC基本原理 RPC(Remote Procedure Call),远程过程调用,大部分的RPC框架都遵循如下三个开发步骤: 1. 定义 ...
- java序列化框架(protobuf、thrift、kryo、fst、fastjson、Jackson、gson、hessian)性能对比
我们为什么要序列化 举个栗子:下雨天我们要打伞,但是之后我们要把伞折叠起来,方便我们存放.那么运用到我们java中道理是一样的,我们要将数据分解成字节流,以便存储在文件中或在网络上传输,这叫序列 ...
- RPC远程协议之Thrift入门
在上一篇文章<RPC远程协议之原理分析>中,我介绍了RPC的工作原理及欲实现RPC框架功能应该做哪些事情,因为要做的事情太多,完全由开发人员研发实现,不是很现实,所以市面上出现了诸多RPC ...
- RPC原理及RPC实例分析
在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 1 2 3 4 5 6 public class ...
- 大型web系统数据缓存设计
1. 前言 在高访问量的web系统中,缓存几乎是离不开的:但是一个适当.高效的缓存方案设计却并不容易:所以接下来将讨论一下应用系统缓存的设计方面应该注意哪些东西,包括缓存的选型.常见缓存系统的特点和数 ...
- RPC
那是N年前的一天,老王在看一本讲java的技术书(可惜忘了叫啥名字了),突然看到有一章讲RMI的,立马就觉得很好奇.于是乎,就按书上所讲,写了demo程序.当时也就只知道怎么用,却不知道什么原理.直到 ...
- golang下的grpc
facebook的thrift也是开源rpc库,性能高出grpc一倍以上,grpc发展的较晚,期待以后有长足的进步.简单来说thrift = grpc + protobuf gRPC基于HTTP/2标 ...
随机推荐
- 什么是跨域及如何解决、json和jsonp
1.跨域: 出于浏览器的同源策略限制,同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互. 同源:即指在同一个域中,就是两个页面具有相同的协议(protocol),主机(host ...
- fiddler everywhere 抓包工具的使用
1.功能 手机微信或者浏览器访问网址都可以在fidder里面抓到http请求 2.配置 电脑fidder setting->允许安卓手机远程访问 安卓手机 设置->wifi代理 主机名是电 ...
- Debug --> CICFlowMeter的java版本安装及使用
一. 首先,给出一个很详细的配置链接!使用IDEA进行配置~ https://blog.csdn.net/BananaMan45/article/details/105473151?utm_mediu ...
- Navicat Premium 12 安装破解过程 (经过测试)
@ 目录 下载安装 下载 解压文件目录 安装使用步骤截图 1. 安装navicat120_premium_cs_x64.exe 软件 2. 解压Navicat.Premium 破解补丁.rar 3. ...
- Python 去掉文本内容中的\xa0字符
爬取网页时,不可避免会遇到\xa0字符串,就会发现,正则re.sub(r'\xa0', '')和字符串的replace都不管用. 通常地,我们所用的空格的ASCII码是 \x20 ,是在标准ASCII ...
- Selenium 自动化中实现双击操作
在selenium中,以name定位为例,单击元素的代码为:driver.find_element_by_name("name").click(),那么,实现双击操作的代码能不能写 ...
- transition实现元素动画平移
效果: 将灰色背景区域移除屏幕,并实现动画效果 代码: 使用transition属性可定义平移的时间,巧用calc得出非确定高度元素的平移距离
- Spring Boot 中处理跨域
HTML 5中新增的跨域资源访问(Cross-Origin Resource Sharing)特性可以让我们在开发后端系统的时候决定资源是否允许被跨域访问.所谓跨域指的是域名不同或者端口不同或者协议不 ...
- excel制作表格
我们这个表格举例: 1. 序号列自动生成序号.选中数字"1"所在的单元格,将鼠标停留在图片中标红的区域向下拖动即可 ...
- intellij idea修改背景图片
上方菜单栏选择 File -> settings -> plugins,搜索Backgroung Image Plus插件 下载之后restart 菜单栏上选择view 设置好后选择O ...