Apache顶级项目介绍9-Thrift

原创2016-12-31erixhao技术极客TechBooster

《Apache顶级项目介绍9-Thrift》

年末最后一弹,我们来简单介绍一下Apache顶级项目Thrift并尝试了解其内部实现机制。

1. Thrift介绍

Thrift最初是由Facebook操刀实现的一个内部项目,主要用于Facebook内部各系统之间的RPC调用。2007年开源,2008年进入Apache孵化器,现在是Apache顶级项目之一。

官网极简,文档匮乏,简直不忍直视。

官网介绍Thrift是一个可伸缩,跨语言服务RPC框架,集成了强大的软件堆栈及代码生成引擎,使得各种语言做到无障碍,高效通信,目前支持C++, Java, Python, PHP, Ruby, Erlang, Perl, Hashkell, C#, Go, Cocoa,JavaScript,Node.js,Smalltalk等等。

RPC框架并非新鲜事物,十几二十年前在非互联网时代已经有了;目前流行的RPC框架也很多,如Google的gRPC,JBoss的Wildfly以及基于Go的rpcx。 国内则较知名有阿里Dubbo,新浪微博的Montan等众多优秀框架,试问Thrift有何能耐可以独树一帜?

2. RPC 机制

我们先简要了解一下RPC的原理与机制。

RPC远程过程调用,简单来说如即两台服务器A,B。A服务器上的应用需要调用B服务器上的应用提供的函数,比如说查询服务器B的实时内存使用率。

现代计算技术受限于内存空间,进程,无法直接调用,需要通过网络跨机器,系统,进程进行通信,这个过程统称RPC。

通信机制

《Apache顶级项目介绍9-Thrift》

客户端与服务器通信,如TCP连接,包括按需端连接或者长连接

寻址问题,如IP地址 + 端口号;如果基于Web服务协议则需要URI,或者依赖于UDDI服务

序列化,需要把所调用的方法参数进行序列化成二进制通过如TCP协议进行传输

服务端收到请求后进行反序列化,恢复为内存中的表达,寻址对应方法进行本地调用

服务端返回调用结果,类似通过序列化返回客户端使用。

CPU方面Thrift综合来看也非常卓越。

其实任何异构平台的通信大抵如此,如与数据库交互,消息中间件等,都需要经历首先建立通信连接作为通信的基石,桥梁;其次对于双方交互的具体应用/系统通过IP与端口进行寻址,进行握手;之后则把通信的信息按照通信协议要求封装,如序列化/反序列化,收到信息方则进行本地寻址调用并返回调用结果。

《Apache顶级项目介绍9-Thrift》

3. RPC协议

如上文所述,RPC协议并非新鲜事物,十几二十年前工程师们就开始探索跨机器,网络通信机制了。

如果你有用过,或者听过这些著名的协议:

CORBA, COM/DCOM/COM+, .NET Remoting, RMI, SOAP, Web Service,  Hessian, HTTP/REST等。

可能上述协议很多人都没有听说过,尤其是新新人类,享受在互联网/大数据的海洋里。

CORBA, COM(仅限Windows),. Net Remoting(仅限.NET), RMI(仅限Java) SOAP早已或者逐步推出历史舞台。

对于相对较近几年流行如基于XML的Web Service与基于JSON的RESTful服务,其数据传输方式以XML, JSON为主,然而各有利弊。XML相对体积较大,传输效率低;JSON则表现能力等不够完善。

通信协议描述

维护服务/客户端契约

包装类

解析XML/JSON开销

存储空间相对较多

基于HTTP协议,性能受限

基于HTTP协议的RPC天生有良好的跨平台性,然而在严重依赖,需要高性能通信的情况下,如集群内部通信,Hadoop集群,HBase各个Region之间通信,Cassandra存储服务器

等等,使用高性能TCP协议的RPC框架是上选。

4. Thrift 架构

了解回顾RPC整体机制后,我们看一下Thrift如何封装整合,做到其称之为完整堆栈结构的。

4.1 堆栈架构

《Apache顶级项目介绍9-Thrift》

可以看到整体架构图很清晰,对应整个RPC过程。其中显示了应用本身代码,以及根据Thrift定义服务接口描述自动生成代码框架,红色部分一下则为Thrift内部传输体系,协议及底层I/O通信。

Thrift包含了用于绑定协议,传输层的基础架构,提供阻塞/非阻塞,单线程/多线程模式,当然也可以配合服务器/容器一起运行,与J2EE服务器/Web容器无缝整合。

5. 简单示例

看一个简单事例吧以方便后续讲解RPC实现过程。 以学校课程管理吧:

Thrift的编码规范遵循以下Martin理念:

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.– Martin Flower, 1999

5.1 IDL / .thrift文件

编写Thrift要首先使用Thrift类型编写IDL(Interface Definition)定义RPC所需数据结构及服务,老古董们应该似曾相识或者老友重逢。

《Apache顶级项目介绍9-Thrift》

接下来就是服务的定义:

《Apache顶级项目介绍9-Thrift》

还有一些异常的定义:

《Apache顶级项目介绍9-Thrift》

5.2 Thrift Types

看到这里,我们应该了解一下Thrift支持的数据类型了:

《Apache顶级项目介绍9-Thrift》

还真是与以前的IDL一样啊,基本使用C风格的定义与风格。

http://thrift.apache.org/docs/idl

IDL支持描述,Header/Namespace/Package , include, Const, Typedef, Enum, Struct, Union, Service, Exception, Field, XSD Options, Functions, Types等,囊括了程序交互各种需求。

5.3 Code Generation

随后,我们可以进行代码生成,支持C/C++, C#, Java, Erlang, Perl, PHP, Python, Ruby, Go等等。

thrift –gen java course.thrift

《Apache顶级项目介绍9-Thrift》

5.4 Java Server

好了,开始写一个Java的服务端吧:

《Apache顶级项目介绍9-Thrift》

这是一个简单的单线程同步阻塞式I/O,其中的processor需要传入我们自己定义实习的服务接口实现类:

《Apache顶级项目介绍9-Thrift》

5.5 Java Client

客户端则更为精简,创建基本socket,通信连接后直接调用代码接口即可,客户端无须实现接口。

《Apache顶级项目介绍9-Thrift》

5.6 部署架构

《Apache顶级项目介绍9-Thrift》

可以看到,与经典RPC框架类似,客户端与服务器需要用到中间绿色区域公共的jar包与java文件,服务器端则实现.Iface接口,包括Server;客户端则实现调用代码;其中间通信则通过Thrift生成的API类实现远程服务调用。

6. 性能对比

我们来开始对比一下Thrift与其它RPC框架的性能:

6.1 Payload

Payload展现各序列化及压缩的功底:

《Apache顶级项目介绍9-Thrift》

Google的Protocol Buffer独领风骚,Thrift也优势尽显。

6.2 Runtime Performance

整体RPC性能则考察RPC框架的整体协作战斗力:

《Apache顶级项目介绍9-Thrift》

Thrift一枝独秀,几乎5倍于传统XML/JSON的性能。

6.3 CPU

《Apache顶级项目介绍9-Thrift》

6.4 Thrift v.s. gRPC v.s. Dubbo

我们再来看一下Thrift与Google最新力作,基于HTTP2.0协议,底层依赖于Netty 5的gRPC协议,以及阿里的老牌产品Dubbo较力吧:

《Apache顶级项目介绍9-Thrift》

具体数据如下:

《Apache顶级项目介绍9-Thrift》

有图有数据,基本上Thrift领先一个数量级,Dubbo则也第二阶梯中领头羊。

好吧,看来人家官网极度精简是有资本的。

7. Thrift 设计

来看一下Thrift的底层设计吧:

7.1 Network Stack

Thrift为了更好的支持多种语言,底层则用了更为抽象简单的四层网络stack:

《Apache顶级项目介绍9-Thrift》

7.2 Transport

Transport层封装抽象,或者解耦了具体底层传输(序列化/反序列化),包含了open/close/read/write/flush等方法。

其基础类为Transport类以及C实现TVirtualTransport类。

TSocket, 阻塞I/O

THttpTransport, HTTP

TFileTransport, 文件

TZlibTransport, 压缩数据

除此之外,还封装了批量的高效的TFramedTransport, TMemoryTransport(ByteArrayOutputStream)等。

TSocket底层也是直接使用Java IOStream来实现:

《Apache顶级项目介绍9-Thrift》

7.3 Protocol

Protocol主要定义了如何在内存与IDL数据结构映射及序列化/反序列。

Thrift也支持文本及二进制流传输,以TVirtualProtocol为基类分为:

TBinaryProtocol, 二进制

TJsonProtocol

TCompactprocotol, 压缩二进制

TDebugProtocol

TSimpleJsonProtocol

VLQ

我们详细看一下TCompactProtocol, 压缩二进制,这个可是Thrift高效率的秘籍啊。

其内部则使用了Tag + Data, 通过VLQ(Variable-Length Quantity)编码。

《Apache顶级项目介绍9-Thrift》

Variable-Length Quantity(VLQ)

《Apache顶级项目介绍9-Thrift》

通过VLQ编码,上图数字106903 32bits的时候可以节省1个byte的长度。

https://en.wikipedia.org/wiki/Variable-length_quantity

7.4 Processor

Processor则封装了客户端/服务端对应Service的序列化与反序列化操作。

7.5 Server

Server则相当于一个容器,工厂,创建TProcessor, TTransport, TProtocol对象并整合通信。

TSimpleServer, 阻塞Blocking Server

TThreadPoolServer, 阻塞多线程处理Server

TThreadSelectorServer, NonBlockingServer

8. 总结

时间较紧,简单介绍了一下Thrift的架构,实现及优势。总体来说,虽然Thrift继承了一些传统,陈旧的思想如IDL,代码生成(猜想作者应该经历过原始的RPC协议调用)等, 但其优秀的性能表现,跨多语言的支持,对于很多程序需要高新能RPC调用来说,还是比较推荐的。

感谢大家一年来的支持,也祝大家新年快乐!

◆ ◆ ◆ ◆

2017新年快乐

HAPPY NEW YEAR

◆ ◆ ◆ ◆

公众号:技术极客TechBooster

《Apache顶级项目介绍9-Thrift》

    原文作者:erixhao
    原文地址: https://www.jianshu.com/p/04e43432adf8
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞