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

Apache Thrift – 可伸缩的跨语言服务开发框架

RPC技术及实现简介

《Apache Thrift - 可伸缩的跨语言服务开发框架》 RPC框架原理图.png

首先思考一下分布式系统中的 RPC (Remote Procedure Call) 问题,一个完整的 RPC 模块需要可以分为三个层次

  • 服务层(service):RPC 接口定义与实现
  • 协议层(protocol):RPC 报文格式和数据编码格式
  • 传输层(transport):实现底层的通信(如 socket)以及系统相关的功能(如事件循环、多线程)
    在实际的大型分布式系统中,不同的服务往往会使用不同的语言来实现,所以一般的 RPC 系统会提供一种跨语言的过程调用功能,比如一段用C++实现的客户端代码可以远程调用一个用 Java 实现的服务。实现跨语言 RPC 有两种方法:
  • 静态代码生成:开发者用一种中间语言(IDL,接口定义语言)来定义 RPC 的接口和数据类型,然后通过一个编译器来生成不同语言的代码(如C++, Java, Python),并由生成的代码来负责 RPC 协议层和传输层的实现。例如,服务的实现用C++,则服务端需要生成实现RPC协议和传输层的C++代码,服务层使用生成的代码来实现与客户端的通信;而如果客户端用 Python,则客户端需要生成Python代码。
  • 基于“自省”的动态类型系统来实现:协议和传输层可以只用一种语言实现成一个库,但是这种语言需要关联一个具备“自省”或者反射机制的动态类型系统,对外提供其他语言的绑定,客户端和服务端通过语言绑定来使用 RPC。比如,可以考虑用 C 和 GObject 实现一个 RPC 库,然后通过 GObject 实现其他语言的绑定。

第一种方法的优点是RPC的协议层和传输层的实现不需要和某种动态类型系统(如GObject)绑定在一起,同时避免了动态类型检查和转换,程序效率比较高,但是它的缺点是要为不同语言提供不同的 RPC 协议层和传输层实现。第二种方法的主要难度在于语言绑定和通用的对象串行化机制的实现,同时也需要考虑效率的问题。
Thrift 是一个基于静态代码生成的跨语言的RPC协议栈实现,它可以生成包括C++, Java, Python, Ruby, PHP 等主流语言的代码,这些代码实现了 RPC 的协议层和传输层功能,从而让用户可以集中精力于服务的调用和实现。Cassandra 的服务访问协议是基于 Thrift 来实现的

Thrift介绍

《Apache Thrift - 可伸缩的跨语言服务开发框架》 111947340627376.png

Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基金会将Thrift作为一个开源项目,对于当时的facebook来说创造thrift是为了解决facebook系统中各系统间大数据量的传输通信以及系统之间语言环境不同需要跨平台的特性。所以thrift可以支持多种程序语言,例如: C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk. 在多种不同的语言之间通信thrift可以作为二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。Thrift适用于程序对程 序静态的数据交换,需要先确定好他的数据结构,他是完全静态化的,当数据结构发生变化时,必须重新编辑IDL文件,代码生成,再编译载入的流程,跟其他IDL工具相比较可以视为是Thrift的弱项,Thrift适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输相对于JSON和xml无论在性能、传输大小上有明显的优势。

Thrift 主要由5个部分组成:

  • 类型系统以及 IDL 编译器:负责由用户给定的 IDL 文件生成相应语言的接口代码
  • TProtocol:实现 RPC 的协议层,可以选择多种不同的对象串行化方式,如 JSON, Binary。
  • TTransport:实现 RPC 的传输层,同样可以选择不同的传输层实现,如socket, 非阻塞的 socket, MemoryBuffer 等。
  • TProcessor:作为协议层和用户提供的服务实现之间的纽带,负责调用服务实现的接口。
  • TServer:聚合 TProtocol, TTransport 和 TProcessor 几个对象。

上述的这5个部件都是在 Thrift 的源代码中通过为不同语言提供库来实现的,这些库的代码在 Thrift 源码目录的 lib 目录下面,在使用 Thrift 之前需要先熟悉与自己的语言对应的库提供的接口。

Thrift 包含一个完整的堆栈结构用于构建客户端和服务器端。下图描绘了 Thrift 的整体架构。

《Apache Thrift - 可伸缩的跨语言服务开发框架》 674508-20160314134028537-1307650758.jpg

数据类型
Thrift 脚本可定义的数据类型包括以下几种类型:

  • 基本类型
    bool:布尔值,true 或 false,对应 C#的 bool
    byte:8 位有符号整数,对应 C#的 byte
    i16:16 位有符号整数,对应 C#的 short
    i32:32 位有符号整数,对应 C#的 int
    i64:64 位有符号整数,对应 C#的 long
    double:64 位浮点数,对应 C#的 double
    string:未知编码文本或二进制字符串,对应 C#的 string

  • 结构体类型
    struct:定义公共的对象,类似于 C 语言中的结构体定义,在 C#中是一个实体类

  • 容器类型
    list:对应 C#的 List<T> 有序集合
    set:对应 C#的 HashSet<T>无序但是不能重复的集合
    map:对应 C#的 Dictionary<TKey,TValue>键值对集合,键不能重复

  • 异常类型
    exception:对应 C#的 Exception

  • 服务类型
    service:对应服务的类

Thrift的协议栈结构

《Apache Thrift - 可伸缩的跨语言服务开发框架》 Thrift的协议栈结构.png

Thrift是一种c/s的架构体系.在最上层是用户自行实现的业务逻辑代码.第二层是由thrift编译器自动生成的代码,主要用于结构化数据的解析,发送和接收。TServer主要任务是高效的接受客户端请求,并将请求转发给Processor处理。Processor负责对客户端的请求做出响应,包括RPC请求转发,调用参数解析和用户逻辑调用,返回值写回等处理。从TProtocol以下部分是thirft的传输协议和底层I/O通信。TProtocol是用于数据类型解析的,将结构化数据转化为字节流给TTransport进行传输。TTransport是与底层数据传输密切相关的传输层,负责以字节流方式接收和发送消息体,不关注是什么数据类型。底层IO负责实际的数据传输,包括socket、文件和压缩数据流等。

Thrift支持的传输协议

Thrift支持多种传输协议,我们可以根据自己的需要来选择合适的类型,总体上来说,分为文本传输和二进制传输,由于二进制传输在传输速率和节省带宽上有优势,所以大部分情况下使用二进制传输是比较好的选择.

  • TBinaryProtocol:使用二进制编码格式传输,是thrift的默认传输协议
  • TCompactProtocol:使用压缩格式传输
  • TJSONProtocol :使用JSON格式传输
  • TDebugProtocol – 使用易懂可读的文本格式进行传输,以便于debug
  • TSimpleJSONProtocol – 提供JSON只写的协议,适用于通过脚本语言解析

Thrift支持的服务模型

  • TSimpleServer:
    这种工作模式只有一个线程,循环监听传过来的请求并对其进行处理,处理完才能接受下一个请求,是一种阻塞式IO的实现,因为效率比较低,实际线上环境一般用不到.一般用于开发时候演示工作流程时使用.

  • TNonblockingServer:
    这种模式与TsimpleServer最大的区别就是使用NIO,也就是非阻塞是IO的方式实现IO的多路复用,它可以同时监听多个socket的变化,但因为业务处理上还是单线程模式,所以在一些业务处理比较复杂耗时的时候效率还是不高,因为多个请求任务依然需要排队一个一个进行处理.

  • TThreadPoolServer:
    这种模式引入了线程池,主线程只负责accept,即监听Socket,当有新的请求(客户端Socket)来时,就会在线程池里起一个线程来处理业务逻辑,这样在并发量比较大的时候(但不超过线程池的数量)每个请求都能及时被处理,效率比较高,但一旦并发量很大的时候(超过线程池数量),后面来的请求也只能排队等待.

  • TThreadedSelectorServer:
    这是一种多线程半同步半异步的服务模型,是Thrift提供的最复杂最高级的服务模型,内部有一个专门负责处理监听Socket的线程,有多个专门处理业务中网络IO的线程,有一个专门负责决定将新Socket连接分配给哪一个线程处理的起负载均衡作用的线程,还有一个工作线程池.这种模型既可以响应大量并发连接的请求又可以快速对wangluoIO进行读写,能适配很多场景,因此是一种使用比较高频的服务模型.

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