Thrift软件栈分层从下向上分别为:传输层(Transport Layer)、协议层(Protocol Layer)、处理层(Processor Layer)和服务层(Server Layer)。
- 传输层(TTransport):定义了具体的网络协议;比如说TCP/IP传输等。
- **协议层(TProtocol):**协议层定义了数据传输格式,负责网络传输数据的序列化和反序列化;比如说JSON、XML、二进制数据等。
- 处理层(TProcessor ):处理层是由具体的IDL(接口描述语言)生成的(Generated Code),封装了具体的底层网络传输和序列化方式,并委托给用户实现的Handler进行处理。
- **服务层(Server Layer):**整合上述组件,提供具体的网络线程/IO服务模型,形成最终的服务。
thrift的传输层
常用的传输层有:(传输层的顶层类是TTransport)
- TSocket:使用阻塞式I/O进行传输,是最常见的模式
- TNonblockingTransport:使用非阻塞方式,用于构建异步客户端
- TFramedTransport:使用非阻塞方式,按块的大小进行传输,类似于Java中的NIO
- 具体传输层
Thrift的服务端类型(网络服务模型):(顶层类是TServer)
- TSimpleServer:单线程服务器端,使用标准的阻塞式I/O
- TThreadPoolServer:多线程服务器端,使用标准的阻塞式I/O
- TNonblockingServer:单线程服务器端,使用非阻塞式I/O
- THsHaServer:半同步半异步服务器端,基于非阻塞式IO读写和多线程工作任务处理
- TThreadedSelectorServer:多线程选择器服务器端,对THsHaServer在异步IO模型上进行增强
TSimpleServer源码
public void serve() {
try {
serverTransport_.listen(); //阻塞监听端口
} catch (TTransportException ttx) {
LOGGER.error("Error occurred during listening.", ttx);
return;
}
// Run the preServe event
if (eventHandler_ != null) {
eventHandler_.preServe();
}
setServing(true);
while (!stopped_) {
TTransport client = null;
TProcessor processor = null;
TTransport inputTransport = null;
TTransport outputTransport = null;
TProtocol inputProtocol = null;
TProtocol outputProtocol = null;
ServerContext connectionContext = null;
try {
client = serverTransport_.accept();
if (client != null) {
processor = processorFactory_.getProcessor(client);
inputTransport = inputTransportFactory_.getTransport(client);
outputTransport = outputTransportFactory_.getTransport(client);
inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);
outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);
if (eventHandler_ != null) {
connectionContext = eventHandler_.createContext(inputProtocol, outputProtocol);
}
while (true) {
if (eventHandler_ != null) {
eventHandler_.processContext(connectionContext, inputTransport, outputTransport);
}
if(!processor.process(inputProtocol, outputProtocol)) {
break;
}
}
}
} catch (TTransportException ttx) {
// Client died, just move on
} catch (TException tx) {
if (!stopped_) {
LOGGER.error("Thrift error occurred during processing of message.", tx);
}
} catch (Exception x) {
if (!stopped_) {
LOGGER.error("Error occurred during processing of message.", x);
}
}
if (eventHandler_ != null) {
eventHandler_.deleteContext(connectionContext, inputProtocol, outputProtocol);
}
if (inputTransport != null) {
inputTransport.close();
}
if (outputTransport != null) {
outputTransport.close();
}
}
setServing(false);
}
1.服务开启后,调用listen方法会一直见阻塞监听,接入连接后就创建TTransport对象,
2.使用accept接受客户端传来的的数据,再为客户端创建处理器对象、输入传输通道对象、输出传输通道对象、输入协议对象和输出协议对象
3.最后通过TServerEventHandler对象处理具体的业务请求。
ThreadPoolServer
public void serve() {
try {
serverTransport_.listen();
} catch (TTransportException ttx) {
LOGGER.error("Error occurred during listening.", ttx);
return;
}
// Run the preServe event
if (eventHandler_ != null) {
eventHandler_.preServe();
}
stopped_ = false;
setServing(true);
int failureCount = 0;
while (!stopped_) {
try {
TTransport client = serverTransport_.accept();
WorkerProcess wp = new WorkerProcess(client); //包装客户端
int retryCount = 0;
long remainTimeInMillis = requestTimeoutUnit.toMillis(requestTimeout);
while(true) {
try {
executorService_.execute(wp); //提交到线程池执行
break;
} catch(Throwable t) {
if (t instanceof RejectedExecutionException) {
retryCount++;
try {
if (remainTimeInMillis > 0) {
//do a truncated 20 binary exponential backoff sleep
long sleepTimeInMillis = ((long) (random.nextDouble() *
(1L << Math.min(retryCount, 20)))) * beBackoffSlotInMillis;
sleepTimeInMillis = Math.min(sleepTimeInMillis, remainTimeInMillis);
TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis);
remainTimeInMillis = remainTimeInMillis - sleepTimeInMillis;
} else {
client.close();
wp = null;
LOGGER.warn("Task has been rejected by ExecutorService " + retryCount
+ " times till timedout, reason: " + t);
break;
}
} catch (InterruptedException e) {
LOGGER.warn("Interrupted while waiting to place client on executor queue.");
Thread.currentThread().interrupt();
break;
}
} else if (t instanceof Error) {
LOGGER.error("ExecutorService threw error: " + t, t);
throw (Error)t;
} else {
//for other possible runtime errors from ExecutorService, should also not kill serve
LOGGER.warn("ExecutorService threw error: " + t, t);
break;
}
}
}
} catch (TTransportException ttx) {
if (!stopped_) {
++failureCount;
LOGGER.warn("Transport error occurred during acceptance of message.", ttx);
}
}
}
executorService_.shutdown();
// Loop until awaitTermination finally does return without a interrupted
// exception. If we don't do this, then we'll shut down prematurely. We want
// to let the executorService clear it's task queue, closing client sockets
// appropriately.
long timeoutMS = stopTimeoutUnit.toMillis(stopTimeoutVal);
long now = System.currentTimeMillis();
while (timeoutMS >= 0) {
try {
executorService_.awaitTermination(timeoutMS, TimeUnit.MILLISECONDS);
break;
} catch (InterruptedException ix) {
long newnow = System.currentTimeMillis();
timeoutMS -= (newnow - now);
now = newnow;
}
}
setServing(false);
}
1.类初始化的时候就已经创建了队列
2.同样启用listen来进行监听
3.使用WorkerProcess来包装客户端,提交到线程池进行执行
TNonblockingServer
TNonblockingServer要求底层的传输通道必须使用TFramedTransport。
thrift的协议层
Thrift可以让用户选择客户端与服务端之间传输通信协议的类别,在传输协议上总体划分为文本(text)和二进制(binary)传输协议。为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数,有时还会使用基于文本类型的协议,这需要根据项目/产品中的实际需求。常用协议有以下几种:
TBinaryProtocol:二进制编码格式进行数据传输
TCompactProtocol:高效率的、密集的二进制编码格式进行数据传输
TJSONProtocol: 使用JSON文本的数据编码协议进行数据传输
TSimpleJSONProtocol:只提供JSON只写的协议,适用于通过脚本语言解析
服务端开启服务过程:
1.创建运输
2.创建用于传输的输入输出
3.根据创建的输入输出协议创建处理器
4.等待传入的连接并将其交给处理器
public static void startSimpleServer() {
TProcessor tProcessor = new HelloWorldService.Processor(new HelloImpl());
try {
//TServerTransport 创建transport阻塞通信,创建通道
TServerSocket serverSocket = new TServerSocket(port);
TBinaryProtocol.Factory protocol = new TBinaryProtocol.Factory();
TServer.Args args = new TServer.Args(serverSocket);
args.processor(tProcessor);
args.protocolFactory(protocol);
//定义服务器类型
TServer server = new TSimpleServer(args);
System.out.println("阻塞单线程server start");
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}