网站开发与应用案例,做集团网站应注意什么,网站做自适应,社保网站上怎么做减员一、 概念 Apache的Thrift软件框架#xff0c;是用来进行可伸缩的、跨语言的服务开发#xff0c;它通过一个代码生成引擎来构建高效、无缝的服务#xff0c;这些服务能够实现跨语言调度#xff0c;目前支持的语言有#xff1a; C, Java, Python, PHP, Ruby, Erlang, Perl,…一、 概念 Apache的Thrift软件框架是用来进行可伸缩的、跨语言的服务开发它通过一个代码生成引擎来构建高效、无缝的服务这些服务能够实现跨语言调度目前支持的语言有 C, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi 等。 二、 安装Thrift 目前官网最新的版本是v0.10.0。下面主要介绍基于mac os系统的Thrift的安装。windows系统可参考官网教程进行安装。
mac os官网提供的安装方法比较复杂这里介绍下mac 下的home brew的安装方法。
打开终端如果你的mac还没有安装home brew那么先要安装home brew使用以下命令
/usr/bin/ruby -e $(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)然后安装最新版本的Thrift
brew install thrift然后安装最新版本的Thrift
brew install thrift等待安装完成然后输入以下命令如果打印了Thrift的版本信息表示安装成功
thrift -version三、 Thrift支持的类型 基本类型 bool布尔值true或者false byte8位的有符号字节java的byte类型 i1616位的有符号整数java的short类型 i3232位的有符号整数java的int类型 i6464位的有符号长整型java的long类型 double一个64位的浮点数java的double类型 string 一个utf8编码的字符串文本java的String Structs Thrift的structs用来定义一个通用对象但是没有继承关系。 集合类型 list一个有序的元素列表。元素可以重复。 set一个无序的元素集合集合中元素不能重复。 map一个键值对的数据结构相当于Java中的HashMap。 异常类型Exceptions Thrift的异常类型除了是继承于静态异常基类以外其他的跟struct是类似的。表示的是一个异常对象。 服务类型Services Thrift 的service类型相当于定义一个面向对象编程的一个接口。Thrift的编译器会根据这个接口定义来生成服务端和客户端的接口实现代码。
四、一个简单的Thrift调用实例
编写.thrift文件也就是IDL接口描述语言文件 以下是data.thrift文件
namespace java thrift.generated
namespace py py.thrift.generatedtypedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string Stringstruct Person {1: optional String username,2: optional int age,3: optional boolean married
}exception DataException {1: optional String message,2: optional String callStack,3: optional String date
}service PersonService {Person getPersonByUsername(1: required String username) throws (1: DataException dataException),void savePerson(1: required Person person) throws (1: DataException dataException)
}使用thrift的编译器生成客户端和服务端的代码 生成java的客户端服务端代码
thrift --gen java src/thrift/data.thrift生成Python的客户端服务端代码
thrift --gen py src/thrift/data.thrift其他语言的生成也是类似。
Thrift的调用 以java作为服务端java作为客户端以及Python作为客户端对服务端进行请求。 java服务端代码
public class PersonServiceImpl implements PersonService.Iface {Overridepublic Person getPersonByUsername(String username) throws DataException, TException {System.out.println(Got client param: username);Person person new Person();person.setUsername(username);person.setAge(20);person.setMarried(false);return person;}Overridepublic void savePerson(Person person) throws DataException, TException {System.out.println(Got client param: );System.out.println(person.getUsername());System.out.println(person.getAge());System.out.println(person.isMarried());}
}java客户端代码
public class ThriftClient {public static void main(String[] args) {TTransport transport new TFramedTransport(new TSocket(localhost, 8899), 600);TProtocol protocol new TCompactProtocol(transport);PersonService.Client client new PersonService.Client(protocol);try {transport.open();Person person client.getPersonByUsername(张三);System.out.println(person.getUsername());System.out.println(person.getAge());System.out.println(person.isMarried());System.out.println(------------);Person person1 new Person();person1.setUsername(李四);person1.setAge(30);person1.setMarried(true);client.savePerson(person1);} catch (Exception e) {throw new RuntimeException(e.getMessage(), e);} finally {transport.close();}}}python客户端代码
__author__ 作者from py.thrift.generated import PersonService
from py.thrift.generated import ttypesfrom thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TCompactProtocolimport sysreload(sys)
sys.setdefaultencoding(utf8)try:tSocket TSocket.TSocket(localhost, 8899)tSocket.setTimeout(600)transport TTransport.TFramedTransport(tSocket)protocol TCompactProtocol.TCompactProtocol(transport)client PersonService.Client(protocol)transport.open()person client.getPersonByUsername(张三)print person.usernameprint person.ageprint person.marriedprint ------------------newPerson ttypes.Person()newPerson.username 李四newPerson.age 30newPerson.married Trueclient.savePerson(newPerson)except Thrift.TException, tx:print %s % tx.message先运行服务端然后再运行客户端观察服务端和客户端的输出来理解下thrift的一个调用流程是什么样的。
五、Thrift的架构原理 以下是thrift的客户端和服务端交互的一个原理图 如上图客户端在进行远程方法调用时首先是通过Thrift的编译器生成的客户端将调用信息方法名参数信息以指定的协议进行封装而传输层TTransport是对协议层的封装进行处理比如封装成帧frame并通过网络发送出去。服务端这边流程跟客户端相反收到客户端发过来的数据后首先经过传输层对传过来的数据进行处理然后使用特定的协议跟客户端是一一对应的进行解析然后再通过生成的Processor调用用户编写的代码如果有返回值的话返回值以逆向的顺序即通过协议层封装然后传输层处理对数据进行发送到了客户端那边就是对服务端返回的数据进行处理使用特定协议进行解析然后得到一个调用个的结果。
以上就是Thrift的RPC调用的一个完整流程。
六、 Thrift的传输格式协议层 Thrift之所以被称为一种高效的RPC框架其中一个重要的原因就是它提供了高效的数据传输。 以下是Thrift的传输格式种类
TBinaryProtocol: 二进制格式。效率显然高于文本格式。 TCompactProtocol压缩格式。在二进制基础上进一步压缩。 TJSONProtocolJSON格式。 TSimpleJSONProtocol提供JSON只写协议缺少元数据信息生成的文件很容易用过脚本语言解析。 TDebugProtocol使用易懂的刻度文本格式以便于调试。 以上可以看到在线上环境使用TCompactProtocol格式效率是最高的同等数据传输占用网络带宽是最少的。
七、Thrift的数据传输方式传输层 TSocket阻塞式socket。 TFramedTransport以frame为单位进行传输非阻塞式服务中使用。 TFileTransport以文件形式进行传输。 TMemoryTransport将内存用于I/OJava是现实内部实际使用了简单的ByteArrayOutputStream。 TZlibTransport使用zlib进行压缩与其他传输方式联合使用。当前无java实现。 八、Thrift的服务模型 TSimpleServer 简单的单线程服务模型常用于测试。只在一个单独的线程中以阻塞I/O的方式来提供服务。所以它只能服务一个客户端连接其他所有客户端在被服务器端接受之前都只能等待。 TNonblockingServer 它使用了非阻塞式I/O使用了java.nio.channels.Selector通过调用select()它使得程序阻塞在多个连接上而不是单一的一个连接上。TNonblockingServer处理这些连接的时候要么接受它要么从它那读数据要么把数据写到它那里然后再次调用select()来等待下一个准备好的可用的连接。通用这种方式server可同时服务多个客户端而不会出现一个客户端把其他客户端全部“饿死”的情况。缺点是所有消息是被调用select()方法的同一个线程处理的服务端同一时间只会处理一个消息并没有实现并行处理。 THsHaServer半同步半异步server 针对TNonblockingServer存在的问题THsHaServer应运而生。它使用一个单独的线程专门负责I/O同样使用java.nio.channels.Selector通过调用select()。然后再利用一个独立的worker线程池来处理消息。只要有空闲的worker线程消息就会被立即处理因此多条消息能被并行处理。效率进一步得到了提高。 TThreadedSelectorServer 它与THsHaServer的主要区别在于TThreadedSelectorServer允许你用多个线程来处理网络I/O。它维护了两个线程池一个用来处理网络I/O另一个用来进行请求的处理。 TThreadPoolServer 它使用的是一种多线程服务模型使用标准的阻塞式I/O。它会使用一个单独的线程来接收连接。一旦接受了一个连接它就会被放入ThreadPoolExecutor中的一个worker线程里处理。worker线程被绑定到特定的客户端连接上直到它关闭。一旦连接关闭该worker线程就又回到了线程池中。 这意味着如果有1万个并发的客户端连接你就需要运行1万个线程。所以它对系统资源的消耗不像其他类型的server一样那么“友好”。此外如果客户端数量超过了线程池中的最大线程数在有一个worker线程可用之前请求将被一直阻塞在那里。 如果提前知道了将要连接到服务器上的客户端数量并且不介意运行大量线程的话TThreadPoolServer可能是个很好的选择。 九、 其他 Facebook开源了一个简化thrift java开发的一个库——swift。swift是一个易于使用的、基于注解的java库主要用来创建thrift可序列化类型和服务。
github地址https://github.com/facebook/swift
十、 总结 Thrift是一个跨语言的RPC框架如果有跨语言交互的业务场景Thrift可能是一个很好的选择。如果使用恰当thrift将是一个非常高效的一个RPC框架。开发时应根据具体场景选择合适的协议传输方式以及服务模型。缺点就是Thrift并没有像dubbo那样提供分布式服务的支持如果要支持分布式需要开发者自己去开发集成。