thrift 的简单实用案例
thrift是由facebook 开发的一套跨语言的rpc服务框架,在2007年捐献给Apache软件基金会,它结合了软件堆栈和强大的代码生成引擎。以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些语言无缝的结合与高效的服务。
目前流行的服务调用方式有很多种,例如:基于SOAP的消息格式的webservice,基于json消息格式的Restful服务、基于java的远程方法调用服务等。然而XML 相对体积过大,传输效率非常低,json体积小,不够完善,现在我们要试试apache thrift 其传输数据为二进制传输,支持可扩展的跨语言的服务开发,它的代码生成器引擎非常强大,例如生成java、c++ 、c、php、go等语言创建无缝而又高效的服务。对高并发、大数据和多语言的环境更有优势。如果你只用java语言请看下阿里巴巴的dubbo 框架。下面我们来看下thrift的入门。
1、利用thrift的接口描述语言(IDL)写一个简单的xxx.thrift
/********************* thrift ld ***/ namespace cpp org.dongtian.sys.thrift namespace java org.dongtian.sys.thrift namespace go org.dongtian.sys.thrift exception UserServiceThriftException { 1: i32 whatOp, 2: string why } struct User { 1: i32 userId, 2: string userName, 3: string password, 4: i32 state, 5: i32 age, 6: i32 sex, 7: string address, 8: string mobile, 9: string email, 10: i32 userType, 11: string nickName, 12: string createTime, 13: string updateTime, 14: string regTime } service UserServiceThrift { User login(1:string userName) throws (1:UserServiceThriftException error), list<User> findUserList(1:string userName,2:string nickName,3:string email,4:string mobile,5:string startTime,6:string endTime) throws (1:UserServiceThriftException error), i32 findUserCount(1:string userName,2:string nickName,3:string email,4:string mobile,5:string startTime,6:string endTime) throws (1:UserServiceThriftException error), bool checkEmail(1:string email,2:i32 userId) throws (1:UserServiceThriftException error), bool checkMobile(1:string mobile,2:i32 userId) throws (1:UserServiceThriftException error), bool addUser(1:User user) throws (1:UserServiceThriftException error), User findUserByUserId(1:i32 userId) throws (1:UserServiceThriftException error), bool updateUser(1:User user) throws (1:UserServiceThriftException error), bool deleteUserByUserId(1:i32 userId) throws (1:UserServiceThriftException error), bool checkNickName(1:string nickName, 2:i32 userId) throws (1:UserServiceThriftException error), bool checkUserName(1:string userName, 2:i32 userId) throws (1:UserServiceThriftException error) }
说明 其中在服务名称为UserServiceThrift定义了几个服务方法,每个方法都包含有方法名、参数、返回值。并且每个方法参数都要有从1开始的序号,thrift就是根据IDL 接口描述语言的实现。我们使用thrift开发流程:1、通过上面的IDL语言的语法编写xxx.thrift服务描述文件。2、通过thrift的代码生成工具编译对应的xxx.thrift生成对应语言的代码(比如:我们生成java 代码 thrift --gen java UserServiceThrift.thrift,就生成了UserServiceThrift.java 以及对应自定义类型的类。UserServiceThrift.java包含有UserServiceThrift.Iface接口 以及底层调用通讯细节 包括客户端的调用逻辑 UserServiceThrift.Client 服务端的处理逻辑 UserServiceThrift.Processor 这两个由于构建客户端和服务端的功能。)。把生成的代码复制到我们要使用thrift项目中。下面以java语言为例:
1、服务端服务接口具体实现的类实现(UserServiceThrift.Iface接口)
package org.dongtian.sys.thrift.server; import java.util.ArrayList; import java.util.List; import org.apache.thrift.TException; import org.dongtian.sys.thrift.User; import org.dongtian.sys.thrift.UserServiceThrift; import org.dongtian.sys.thrift.UserServiceThriftException; public class UserHandler implements UserServiceThrift.Iface { @Override public User login(String userName) throws UserServiceThriftException, TException { // TODO Auto-generated method stub return new User(); } @Override public List<User> findUserList(String userName, String nickName, String email, String mobile, String startTime, String endTime) throws UserServiceThriftException, TException { return new ArrayList<User>(); } @Override public int findUserCount(String userName, String nickName, String email, String mobile, String startTime, String endTime) throws UserServiceThriftException, TException { return 0; } @Override public boolean checkEmail(String email, int userId) throws UserServiceThriftException, TException { System.err.println("============================="); return false; } @Override public boolean checkMobile(String mobile, int userId) throws UserServiceThriftException, TException { return false; } @Override public boolean addUser(User user) throws UserServiceThriftException, TException { return false; } @Override public User findUserByUserId(int userId) throws UserServiceThriftException, TException { return new User(); } @Override public boolean updateUser(User user) throws UserServiceThriftException, TException { return false; } @Override public boolean deleteUserByUserId(int userId) throws UserServiceThriftException, TException { return false; } @Override public boolean checkNickName(String nickName, int userId) throws UserServiceThriftException, TException { return false; } @Override public boolean checkUserName(String userName, int userId) throws UserServiceThriftException, TException { return false; } }
2、创建服务端用于启动服务
package org.dongtian.sys.thrift.server; import org.apache.thrift.server.TServer; import org.apache.thrift.server.TThreadedSelectorServer; import org.apache.thrift.transport.TNonblockingServerSocket; import org.dongtian.sys.thrift.UserServiceThrift; import org.dongtian.sys.thrift.UserServiceThrift.Processor; public class TestServer { public static void main(String[] args) throws Exception { //设置服务端口 TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090); //具体服务实现 UserHandler handler = new UserHandler(); //服务端具体实现的处理器 Processor<UserServiceThrift.Iface> processor = new UserServiceThrift.Processor<UserServiceThrift.Iface>(handler); org.apache.thrift.server.TThreadedSelectorServer.Args args2 = new org.apache.thrift.server.TThreadedSelectorServer.Args(serverTransport); //关联处理器与服务类的实现 args2.processor(processor); TServer server = new TThreadedSelectorServer(args2); server.serve(); } }
3、客户端具体调用代码
package org.dongtian.sys.thrift.client; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import org.dongtian.sys.thrift.UserServiceThrift.Client; public class TestClient { public static void main(String[] args) { TTransport transport = null; try { TTransport socket = new TSocket("127.0.0.1", 9090,5000); transport = new TFramedTransport(socket); TProtocol protocol = new TBinaryProtocol(transport); Client client = new Client(protocol); transport.open(); boolean has = client.checkEmail("xx", 0); System.err.println(has); transport.close(); } catch (Exception e) { e.printStackTrace(); }finally { if(transport != null) { transport.close(); } } } }
4、启动服务器端再启动客户端测试调用会打印一个false
二、Thrift架构
thrift 包含有一个完整的堆栈结构用于构建服务端和客户端,下面看下它的架构图
黄色部分为我们开发者实现的代码业务逻辑,褐色部分是根据 Thrift 定义的服务接口描述文件生成的客户端和服务器端代码框架,红色部分是根据 Thrift 文件生成代码实现数据的读写操作。红色部分以下是 Thrift 的传输体系、协议以及底层 I/O 通信,使用 Thrift 可以很方便的定义一个服务并且选择不同的传输协议和传输层而不用重新生成代码。thrift服务器包含用于绑定协议和传输层基础架构,它提供阻塞、非阻塞、单线程、多线程的模式运行在服务器中。
三、数据类型
Thrift 脚本可定义的数据类型包括以下几种类型:
- 基本类型:
- bool:布尔值,true 或 false,对应 Java 的 boolean
- byte:8 位有符号整数,对应 Java 的 byte
- i16:16 位有符号整数,对应 Java 的 short
- i32:32 位有符号整数,对应 Java 的 int
- i64:64 位有符号整数,对应 Java 的 long
- double:64 位浮点数,对应 Java 的 double
- string:未知编码文本或二进制字符串,对应 Java 的 String
- 结构体类型:
- struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
- 容器类型:
- list:对应 Java 的 ArrayList
- set:对应 Java 的 HashSet
- map:对应 Java 的 HashMap
- 异常类型:
- exception:对应 Java 的 Exception
- 服务类型:
- service:对应服务的类
四、传输协议
thrift做到很好的让用户在服务器端与客户端选择对应的传输协议,总体上一般为2中传输协议二进制或者文本,但是为了节省带宽大多数采用二进制的协议。开发者可用根据自己的项目需求选择对应的协议。
1、TCompactProtocol-紧凑的、高效的二进制传输协议。构建协议非常简单:
TTransport transport = null; TCompactProtocol tCompactProtocol = new TCompactProtocol(transport); new Client(tCompactProtocol);
2、TBinaryProtocol-基于二进制传输的协议,使用方法与TCompactProtocol 相同
3、TJSONProtocol-使用json格式编码传输协议
4、TSimpleJSONProtocol-仅仅是写入的json格式编码传输协议-适用于通过脚本语言解析
五、传输层
1、TSocket -使用阻塞io进行传输最常见模式
try { // 设置调用的服务地址为本地,端口为 9090 TTransport transport = new TSocket("localhost", 9090); transport.open(); // 设置传输协议为 TBinaryProtocol TProtocol protocol = new TBinaryProtocol(transport); UserServiceThrift.Client client = new UserServiceThrift.Client(protocol); // 调用服务的 helloVoid 方法 client.checkEail("XX",0); transport.close(); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); }
2、TFramedTransport-非阻塞方式按照块的大小进行传输,类似java的NIO,如果使用了TFramedTransport作为传输层,则服务端必须改成非阻塞服务类型,TNonblockingServerTransport 用于构建非阻塞socket 下面具体代码用于构建非阻塞socket:
//设置服务端口 TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090);
客户端修改为TFramedTransport 传输
TTransport transport = null; try { TTransport socket = new TSocket("127.0.0.1", 9090,5000); transport = new TFramedTransport(socket); TProtocol protocol = new TBinaryProtocol(transport); Client client = new Client(protocol); transport.open(); boolean has = client.checkEmail("xx", 0); System.err.println(has); } catch (Exception e) { e.printStackTrace(); }finally { if(transport != null) { transport.close(); } }
六、服务端类型
1、TSimpleServer-单线程类型的服务类型使用标准的阻塞io 结合tsocket
TSimpleServer server2 = new TSimpleServer(args2); server2.serve();
2、TThreadPoolServer -多线程服务类型采用标准的阻塞IO
Args arg = new Args(serverTransport); arg.executorService(Executors.newFixedThreadPool(15)); arg.processor(processor); TThreadPoolServer poolServer = new TThreadPoolServer(arg); poolServer.serve();
3、TThreadedSelectorServer-非阻塞服务类型 使用非阻塞io 结合TFramedTransport使用
//设置服务端口 TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090); //具体服务实现 UserHandler handler = new UserHandler(); //服务端具体实现的处理器 Processor<UserServiceThrift.Iface> processor = new UserServiceThrift.Processor<UserServiceThrift.Iface>(handler); org.apache.thrift.server.TThreadedSelectorServer.Args args2 = new org.apache.thrift.server.TThreadedSelectorServer.Args(serverTransport); //关联处理器与服务类的实现 args2.processor(processor); TServer server = new TThreadedSelectorServer(args2); server.serve();
七、构建异步客户端
比如有这样一个场景-我们需要调用对应的一个服务进行数据备份操作,而且备份的数据非常大,一般在几分钟或者几个小时无法完成,但是我们客户端想要知道服务端备份完成之后做出相应给客户端。那么我们只能做异步了,值得庆幸的是thrift支持异步的客户端的构建操作。TAsyncClientManager这个类用于管理客户端的请求,它能够在一个线程上进行追踪请求和响应,在此类中包含有一个任务队列private final ConcurrentLinkedQueue<TAsyncMethodCall> pendingCalls = new ConcurrentLinkedQueue<TAsyncMethodCall>(); 在TAsyncMethodCall抽象类中包含一个 private final AsyncMethodCallback<T> callback; callback 。通过AsyncMethodCallback<T> 传递参数和callback对象.callback提供服务端调用完成后的返回结果或者出现异常响应异常方法,我们在客户端实现AsyncMethodCallback 接口
package org.dongtian.sys.thrift.client; import org.apache.thrift.async.AsyncMethodCallback; public class ClientAsyncMethod implements AsyncMethodCallback { private Object obj = null; /*** * 服务端处理完成调用 */ @Override public void onComplete(Object response) { obj = response; } /*** * 服务端抛出异常 */ @Override public void onError(Exception exception) { obj = exception; } /*** * 客户端判断是否服务端已经响应完成调用此方法 * @return */ public Object returnObj() { return obj; } }
修改客户端方法
package org.dongtian.sys.thrift.client; import org.apache.thrift.async.TAsyncClientManager; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.protocol.TProtocolFactory; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TNonblockingServerSocket; import org.apache.thrift.transport.TNonblockingSocket; import org.apache.thrift.transport.TNonblockingTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import org.dongtian.sys.thrift.UserServiceThrift; import org.dongtian.sys.thrift.UserServiceThrift.Client; public class TestClient { public static void main(String[] args) { TNonblockingTransport transport = null; try { transport = new TNonblockingSocket("127.0.0.1", 9090,5000); TAsyncClientManager clientManager = new TAsyncClientManager(); TProtocolFactory factory = new TBinaryProtocol.Factory(); UserServiceThrift.AsyncClient client = new UserServiceThrift.AsyncClient(factory, clientManager, transport); transport.open(); ClientAsyncMethod asyncMethod = new ClientAsyncMethod(); client.checkEmail("xx", 0,asyncMethod); while (asyncMethod.returnObj() != null) { System.err.println(asyncMethod.returnObj()); } } catch (Exception e) { e.printStackTrace(); }finally { if(transport != null) { transport.close(); } } } }
八、总结
apache thrift是一个非常优秀的跨语言高性能的服务框架,thrift基于RPC (远程过程调用)服务框架,比如现在很多的框架都有很好的整合到去,比如hadoop和habase 提供thrift接口 来解决为支撑不同语言客户端跨语言的服务调用。跨语言方面解决了,但是thrift也有不足的地方,比如做服务集群的时候,需要自己进行设置解决。没有像阿里巴巴的dubbo那样基于服务注册中心: 服务的发布与订阅 审计功能解决高并发环境中负载均衡的功能。不过这点我们可以利用zookeeper服务协调框架来实现简单基于thrift的RPC服务集群。最后,不管哪个框架都有好坏,自己根据自己的项目产品使用对应的框架和技术那样才好,不会人家叫你做一个仓库管理系统 你把单点、集群等都考虑在内吧?下面例子在附件可以对照着例子和官方文档自己多动动手!
相关推荐
以下是一个简单的ThriftServlet示例: ```java public class ThriftServlet extends HttpServlet { private final TProcessor processor; public ThriftServlet(MyService.Processor processor) { this....
Thrift是一种开源的跨语言服务开发框架,由Facebook于2007年设计并发布,其目的是为了在各种编程语言之间提供高效的、轻量级的通信机制。Thrift通过定义一种中间表示(IDL,Interface Definition Language)来描述...
《Thrift实战案例详解》 Thrift是一种高性能、语言无关、平台无关的远程过程调用(RPC)框架,由Facebook于2007年开源。它最初设计的目的是解决大规模分布式系统中的通信问题,现在已经成为业界广泛使用的跨语言...
在"Thrift简单调用demo代码"中,我们可以看到Thrift如何用于构建简单的服务和客户端应用。以下是对Thrift及其在示例中的应用的详细解释: 1. **Thrift IDL(接口定义语言)**:Thrift IDL文件通常以`.thrift`为扩展...
### Thrift中文简易教程 #### 一、简介 Thrift 是一个跨语言的服务开发框架,由 Facebook 开发并开源。它允许开发者构建可扩展的跨平台服务,支持多种编程语言如 C++, Java, Python, PHP 等。Thrift 的核心特性...
- "thrift-server 最简单的测试案例"表明,项目可能包含一个简单的服务器实现和对应的测试用例,用来验证Thrift服务的正确性。 - 测试通常使用JUnit或类似框架,模拟客户端调用,检查服务器的响应是否符合预期。 ...
生成的代码支持多种编程语言,如Java、Python、C++等,使得跨平台通信变得简单。 2. **Wireshark配置** - 安装Wireshark:首先确保你的系统上已经安装了Wireshark。如果尚未安装,可以从其官方网站下载适合你操作...
这种跨语言的能力使得开发多语言服务变得简单,同时Thrift还提供了一种轻量级的二进制协议,确保了通信效率。 二、Thrift IDL Thrift接口定义语言(IDL)是一种简单的结构化语言,用于定义服务、数据结构和常量。...
Thrift是一种开源的跨语言服务开发框架,由Facebook于2007年创建,现在是Apache软件基金会的项目。它的主要目标是通过定义一种中间语言(IDL,Interface Definition Language)来简化不同编程语言之间的通信,使得...
Thrift是一种开源的跨语言服务开发框架,由Facebook于2007年开源,现在由Apache软件基金会维护。它的主要功能是定义数据结构和服务接口,然后自动生成多种编程语言的代码,实现这些接口,使得不同语言之间可以进行...
Thrift是一个软件框架,用来进行...thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。 官网地址:thrift.apache.org
在IT行业中,Thrift是一种高性能、可扩展的跨语言服务开发框架,由Facebook开源,用于构建分布式服务。它通过定义一种中间表示(IDL,接口定义语言)来描述服务,然后自动生成不同编程语言的代码,使得不同语言之间...
`ThriftHelloClient`可能是一个简单的Thrift客户端示例,展示了如何调用Thrift服务的方法。 在学习这个实例时,你需要理解Thrift的IDL语法,如何使用Thrift编译器生成代码,以及如何在Java环境中集成和使用Thrift库...
mac 想安装低版本thrift 0.9.3太难了,高版本比较简单 直接执行 brew install thrift.rb 即可安装
### Netty+Thrift 实现高并发高性能的关键技术解析 #### 一、引言 在当前互联网技术高速发展的背景下,高性能、高并发的服务框架成为众多企业和开发者追求的目标。Netty作为一款高性能、异步事件驱动的网络应用...
Thrift 的优势在于它的高效、轻量级和易于集成,使得不同语言和平台之间的通信变得简单。 SASL 是一种标准化的接口,用于在网络协议中添加认证和加密功能。它提供了一种灵活的方式,使各种网络协议(如SMTP、IMAP、...
一个简单的Thrift IDL文件例子如下: ```thrift service MyService { void ping(), string echo(1:string message) } ``` - **编译器**:Thrift编译器读取这些IDL文件,并生成对应编程语言的客户端和服务器端...
Thrift Delphi实例详解 Thrift,全称为“Transportation Layer Security”,是由Facebook开源的一款高性能、跨语言的服务框架。它最初设计的目的是解决大规模分布式系统中的数据通信问题,通过定义一种中间表示...
例如,你可以定义一个简单的服务,包含一个远程调用的方法,以及一些基本的数据结构,如结构体(struct)或枚举(enum)。服务定义如下: ```thrift service MyService { string sayHello(1: string name) } ``` ...