Apache顶级项目介绍9-Thrift

作者: erixhao | 来源:发表于2016-12-31 11:23 被阅读511次

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

    年末最后一弹,我们来简单介绍一下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。

    通信机制

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

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

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

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

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

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

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

    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 堆栈架构

    可以看到整体架构图很清晰,对应整个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所需数据结构及服务,老古董们应该似曾相识或者老友重逢。

    接下来就是服务的定义:

    还有一些异常的定义:

    5.2 Thrift Types

    看到这里,我们应该了解一下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

    5.4 Java Server

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

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

    5.5 Java Client

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

    5.6 部署架构

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

    6. 性能对比

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

    6.1 Payload

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

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

    6.2 Runtime Performance

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

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

    6.3 CPU

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

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

    具体数据如下:

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

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

    7. Thrift 设计

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

    7.1 Network Stack

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

    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来实现:

    7.3 Protocol

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

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

    TBinaryProtocol, 二进制

    TJsonProtocol

    TCompactprocotol, 压缩二进制

    TDebugProtocol

    TSimpleJsonProtocol

    VLQ

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

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

    Variable-Length Quantity(VLQ)

    通过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

      本文链接:https://www.haomeiwen.com/subject/vivvvttx.html