285572001 发表于 2016-12-29 11:13:41

Apache Thrift 学习

  Apache Thrift 是跨语言服务访问的框架。最早由Facebook 开发,贡献给了Apache。

通过接口定义语言(IDL),定义和创建服务,Thrift生成特定语言的可供server和client 访问的代码。

Thrfit 有着非常优秀的效率,无论是内存还是 传输效率上。
  Cassandra 支持多种语言的编程接口,正式由于使用了Thrift。

架构






以上是创建server和client的stack。最上面的是IDL,然后生成Client和Processor。红色的是发送的数据。protocol和transport 是Thrift运行库的一部分。

通过Thrift 你只需要关心服务的定义,而不需要关心protocol和transport。


Thrift允许你选择 protocol ,transport和server。因为Thrift 最早是有C++开发的,Thrift在C++实现中有最大的变化。


Thrift支持 text 和 binary protocols,binary protocols要比text protocols,但是有时候 text protocols比较有用(例如:调试的时候)。支持的协议有:

TBinaryProtocol  -直接的二进制格式

TCompactProtocol  效率和高压缩编码数据

TDenseProtocoal  和TCompactProtocol相似,但是省略了meta信息,从哪里发送的,增加了receiver。还在实验中,java实现还不可用。

TJSONProtocoal 使用JSON

TSImpleJSONProtocoal  只写的protocol使用JSON。适合被脚本语言转化

TDebugProtocoal  使用人类可读的text 格式 帮助调试


上面的protocol 说明了 什么被传送,Thrift  transports 说明了怎样传送。支持的transport:

TSocket  使用 blocking socket I/O

TFramedTransport   以帧的形式发送,每帧前面是一个长度。要求服务器来non-blocking server

TFileTransport   写到文件。没有包括在java实现中。

TMemoryTransport   使用内存 I/O 。java实现中在内部使用了ByteArrayOutputStream

TZlibTransport 压缩 使用zlib。在java实现中还不可用


最后,thrift 提供了servers:

TSimpleServer  单线程 server,使用标准的blocking IO。用于测试

TThreadPoolServer  多线程  使用标准的blocking IO

TNonblockingServer  多线程  使用 non-blocking IO (java实现中使用了NIO channels)。TFramedTransport必须使用在这个服务器。


一个server只允许定义一个接口服务。这样的话多个接口需要多个server。这样会带来资源的浪费。同意通过继承接口的方式。

创建服务



1创建user.thrift

namespace java thrift.demo.gen
namespace py thrift.demo
struct User{
1: i32 id,
2: string username,
3: string password
}
exception UserNotFound{
1:string message
}
service UserService{
list<User> getUsers(),
User getUserByName(1:string username) throws(1:UserNotFound unf)
}

  


定义了一个User ,一个UerNotFound异常,一个UserService服务接口
  服务定义主要使用了 类C的语法
  Types

  Thrift 定义的类型
  base type:bool,byte,i16,i32,i64,double,string(UTF-8 编码)
  binary
  structs
  Contains:list<type>,set<type>,map<type>
  exception
  services:包含了一组接口方法
  注意定义的时候 序号是不可省略的,使用序号可以提升序列化和反序列对象的速度。
  


2.生成代码

命令行下执行

生成java代码

thrift-0.6.1.exe --gen javauser.thrift

  


生成python代码

thrift-0.6.1.exe --gen py user.thrift

  


3.实现服务端

3.1接口服务实现

package thrift.demo.server;
import java.util.ArrayList;
import java.util.List;
import org.apache.thrift.TException;
import thrift.demo.gen.User;
import thrift.demo.gen.UserNotFound;
import thrift.demo.gen.UserService.Iface;
public class UserServiceHandler implements Iface {
@Override
public List<User> getUsers() throws TException {
List<User> list = new ArrayList<User>();
User user = new User();
user.setId(1);
user.setUsername("user1");
user.setPassword("pwd1");
list.add(user);
User user2 = new User();
user2.setId(1);
user2.setUsername("user2");
user2.setPassword("pwd2");
list.add(user2);
return list;
}
@Override
public User getUserByName(String username) throws UserNotFound, TException {
if ("user1".equals(username)) {
User user = new User();
user.setId(1);
user.setUsername("user1");
user.setPassword("pwd1");
return user;
} else {
throw new UserNotFound();
}
}
}

  



3.2 Server启动类

package thrift.demo.server;
import org.apache.thrift.TProcessorFactory;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.server.THsHaServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TTransportException;
import thrift.demo.gen.UserService;
public class UserServer {
public final static int PORT = 8989;
/**
* @param args
*/
public static void main(String[] args) {
try {
TNonblockingServerSocket socket = new TNonblockingServerSocket(PORT);
final UserService.Processor processor = new UserService.Processor(
new UserServiceHandler());
THsHaServer.Args arg = new THsHaServer.Args(socket);
arg.protocolFactory(new TCompactProtocol.Factory());
arg.transportFactory(new TFramedTransport.Factory());
arg.processorFactory(new TProcessorFactory(processor));
TServer server = new THsHaServer(arg);
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}

}
}

  



4.实现客户端

package thrift.demo.client;
import org.apache.thrift.TApplicationException;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TCompactProtocol;
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.apache.thrift.transport.TTransportException;
import thrift.demo.gen.UserNotFound;
import thrift.demo.gen.UserService;
public class UserClient {
public static void main(String[] arsg) {
String address = "127.0.0.1";
int port = 8989;
int clientTimeout = 30000;
TTransport transport = new TFramedTransport(new TSocket(address, port,
clientTimeout));
TProtocol protocol = new TCompactProtocol(transport);
UserService.Client client = new UserService.Client(protocol);
try {
transport.open();
System.out.println(client.getUserByName("user1"));
} catch (TApplicationException e) {
System.out.println(e.getMessage() + " " + e.getType());
} catch (TTransportException e) {
e.printStackTrace();
} catch (UserNotFound e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
transport.close();
}
}

  



注意 客户端和服务端要使用同一中 Protocol 和 Transport,否则会抛出异常
页: [1]
查看完整版本: Apache Thrift 学习