https://www.jianshu.com/p/10b7cf0a384e
https://thrift.apache.org/tutorial/java
https://www.jianshu.com/p/397d7b278e65
Thrift创建步骤
- 服务端编码基本步骤
- 实现服务处理接口impl
- 创建TProcessor
- 创建TServerTransport
- 创建TProtocol
- 创建TServer
- 启动Server
- 客户端编码基本步骤
- 创建Transport
- 创建TProtocol
- 基于TTransport和TProtocol创建Client
- 调用Client的相应方法
Thrift服务类型
- Thrift的Server类型有TSimpleServer、TNonblockingServer、THsHaServer、TThreadedSelectorServer、TThreadPoolServer
- TSimpleServer是单线程阻塞IO的方式,仅用于demo
- TNonblockingServer是单线程非阻塞IO的方式,通过java.nio.channels.Selector的select()接收连接请求,但是处理消息仍然是单线程,吞吐量有限不可用于生产
- THsHaServer使用一个单独的线程处理IO,一个独立的worker线程池处理消息, 可以并行处理所有请求
- TThreadPoolServer使用一个专用连接接收connection,一旦接收到请求就会放入ThreadPoolExecutor中的一个worker里处理,当请求处理完毕该worker释放并回到线程池中,可以配置线程最大值,当达到线程最大值时请求会被阻塞。TThreadPoolServer性能表现优异,代价是并发高时会创建大量线程
- TThreadedSelectorServer是thrift 0.8引入的实现,处理IO也使用了线程池,比THsHaServer有更高的吞吐量和更低的时延,与TThreadPoolServer比性能相近且能应对网络IO较多的情况
- 对于客户端较少的情况,TThreadPoolServer也有优异的性能表现,但是考虑到未来SOA可能的高并发,决定采用TThreadedSelectorServer
实现过程
- 创建thrift文件
thrift文件的功能是提供KV查询服务,接口中定义了四个方法如下,分别按照单key,多key查询value;也可以按照单key,多key设置value值
namespace java sc.leveldb
service KvService{
string getValue(1: string key),
list<string> mgetValues(1: list<string> keys),
bool setValue(1: string key, 2: string value),
bool msetValues(1: list<string> keys, 2: list<string> values)
}
- 将thrift描述文件转成java接口
在Mac上执行命令如下
/usr/local/Cellar/thrift/0.10.0/bin/thrift -r –gen java ./kv.thrift
将生成的KvService.java文件拷贝到相应的java工程中 - 实现KvService接口
package sc.leveldb;
import org.apache.thrift.TException;
import java.util.ArrayList;
import java.util.List;
public class KvImpl implements KvService.Iface {
public KvImpl(){};
@Override
public String getValue(String key) throws TException{
return key + ":super clocks";
}
@Override
public java.util.List<String> mgetValues(java.util.List<String> keys) throws TException{
List<String> r = new ArrayList<String>();
for(int i = 0; i < keys.size(); i++){
r.add(keys.get(i) + ":super clocks");
}
return null;
}
@Override
public boolean setValue(String key, String value) throws TException{
System.out.print(key + ":" + value + "\n");
return true;
}
@Override
public boolean msetValues(List<String> keys, java.util.List<String> values) throws TException{
for(int i = 0; i < keys.size(); i++){
System.out.print(keys.get(i) + ":" + values.get(i) + "\n");
}
return true;
}
}
- 定义服务端启动程序
实现TSimpleServer和TThreadedSelectorServer
package sc.leveldb;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TBinaryProtocol.Factory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.server.TThreadedSelectorServer;
import org.apache.thrift.transport.*;
/**
* Created by zhongchao03 on 2018/1/20.
*/
public class ThriftServer {
public void simpleServerStart(){
TServerSocket serverTransport = null;
try {
System.out.println("Starting Thrift Server......");
TProcessor processor = new KvService.Processor<KvService.Iface>(new KvImpl());
serverTransport = new TServerSocket(8191);
TTransportFactory transportFactory = new TFramedTransport.Factory();
Factory factory = new TBinaryProtocol.Factory();
TServer.Args tArgs = new TServer.Args(serverTransport);
tArgs.protocolFactory(factory);
tArgs.transportFactory(transportFactory);
tArgs.processor(processor);
// 简单的单线程服务模型,一般用于测试
TServer server = new TSimpleServer(tArgs);
server.serve();
} catch (TTransportException e) {
System.out.println("Starting Thrift Server......Error!!!");
e.printStackTrace();
} finally {
serverTransport.close();
}
}
public void threadedSelectorServerStart(){
try {
System.out.println("HelloWorld TNonblockingServer start ....");
TNonblockingServerTransport serverSocket=new TNonblockingServerSocket(8888);
TThreadedSelectorServer.Args serverParams=new TThreadedSelectorServer.Args(serverSocket);
serverParams.protocolFactory(new TBinaryProtocol.Factory());
serverParams.processor(new KvService.Processor<KvService.Iface>(new KvImpl()));
TServer server=new TThreadedSelectorServer(serverParams); //简单的单线程服务模型,常用于测试
server.serve();
} catch (Exception e) {
System.out.println("Server start error!!!");
e.printStackTrace();
}
}
}
- 客户端调用
对应实现对TSimpleServer和TThreadedSelectorServer的调用
package sc.leveldb;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.*;
/**
* Created by zhongchao03 on 2018/1/20.
*/
public class ThriftClient {
public static void a()
{
try {
TTransport transport = new TFramedTransport(new TSocket("127.0.0.1", 8191, 5000));
// 协议要和服务端一致
TProtocol protocol = new TBinaryProtocol(transport);
KvService.Client client = new KvService.Client(protocol);
transport.open();
boolean string = client.setValue("fuck", "haha");
System.out.println(string);
transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
public static void nonblockingSocket() throws Exception{
TTransport transport = new TFramedTransport(new TSocket("localhost", 8888));
TProtocol protocol = new TBinaryProtocol(transport);
KvService.Client client = new KvService.Client(protocol);
transport.open();
int i = 5;
while (i > 0) {
System.out.println("client调用返回:" + client.getValue("张三"));
i--;
}
transport.close();
}
public static void main(String[] args)throws Exception{
nonblockingSocket();
}
}
Thrift客户端连接池设计
Thrift连接池优化:http://blog.csdn.net/chen7253886/article/details/52779471
Thrift客户端连接池设计:http://blog.csdn.net/lansebolangcjl/article/details/52788198