TNonblockingServer是服务端五个服务器之一,TNonblockingServer的工作模式也是单线程工作,但是该模式与TSimpleServer模式不同之处就是采用NIO的方式,这样可以避免每个客户端阻塞等待,它的accept,read,write都是注册在同一个Selector上,它内部用来处理这几个事件的是SelectAcceptThread线程, 它继承自AbstractNonblockingServer,AbstractNonblockingServer里面封装了一个FrameBuffer作为数据输入输出流的缓冲,同时还充当了rpc的调用,FrameBuffer由后面说明,这篇只说明TNonblockingServer线程io模型。下面先看下TNonblockingServer的流程图。
TNonblockingServer模式优点:
相比于TSimpleServer效率提升主要体现在IO多路复用上,TNonblockingServer采用非阻塞IO,同时监控多个socket的状态变化;
TNonblockingServer模式缺点:
TNonblockingServer模式在业务处理上还是采用单线程顺序来完成,在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。
。
TNonblockingServer服务端使用流程大概如下:
public static void main(String[] args) {
private Integer port = 9090;
//thrift支持的scoker有很多种,这个是非阻塞的socker
TNonblockingServerSocket socket = new TNonblockingServerSocket(port);
TNonblockingServer.Args args = new TNonblockingServer.Args(socket);
//---------------thrift传输协议------------------------------
//1. TBinaryProtocol 二进制传输协议
//2. TCompactProtocol 压缩协议 他是基于TBinaryProtocol二进制协议在进一步的压缩,使得体积更小
//3. TJSONProtocol Json格式传输协议
//4. TSimpleJSONProtocol 简单JSON只写协议,生成的文件很容易通过脚本语言解析,实际开发中很少使用
//5. TDebugProtocol 简单易懂的可读协议,调试的时候用于方便追踪传输过程中的数据
//-----------------------------------------------------------
//协议工厂 TCompactProtocol压缩工厂 二进制压缩协议
arg.protocolFactory(new TCompactProtocol.Factory());
//---------------thrift传输格式------------------------------
//---------------thrift数据传输方式------------------------------
//1. TSocker 阻塞式Scoker 相当于Java中的ServerSocket
//2. TFrameTransport 以frame为单位进行数据传输,非阻塞式服务中使用
//3. TFileTransport 以文件的形式进行传输
//4. TMemoryTransport 将内存用于IO,Java实现的时候内部实际上是使用了简单的ByteArrayOutputStream
//5. TZlibTransport 使用zlib进行压缩,与其他传世方式联合使用;java当前无实现所以无法使用
//传输工厂 更加底层的概念
arg.transportFactory(new TFramedTransport.Factory());
//---------------thrift数据传输方式------------------------------
//设置处理器(Processor)工厂
//processor已经设置好了业务处理逻辑
arg.processorFactory(new TProcessorFactory(processor));
TNonblockingServer tNonblockingServer = new TNonblockingServer(arg);
//启动服务器
tNonblockingServer.serve();
}
我们先来看下TNonblockingServer的类图
TNonblockingServer继承了抽象类AbstractNonblockingServer,AbstractNonblockingServer又继承了TServer抽象类。
我们先来看下TServer接口的源代码。
/**
* Generic interface for a Thrift server.
*
*/
public abstract class TServer {
public static class Args extends AbstractServerArgs {
//参数传进来一个TServerTransport类型的参数,
//记住名字带有Server多半都是在服务端才用到的参数。
public Args(TServerTransport transport) {
super(transport);//一层一层的传入,最后赋值给AbstractServerArgs类里的serverTransport
}
}
public static abstract class AbstractServerArgs> {
//用来存储服务端的socket,通过构造方法传入
final TServerTransport serverTransport;
TProcessorFactory processorFactory;
//一些传输类工厂和协议类工厂,此处实例化是当初默认值
TTransportFactory inputTransportFactory = new TTransportFactory();
TTransportFactory outputTransportFactory = new TTransportFactory();
TProtocolFactory inputProtocolFactory = new TBinaryProtocol.Factory();
TProtocolFactory outputProtocolFactory = new TBinaryProtocol.Factory();
public AbstractServerArgs(TServerTransport transport) {
serverTransport = transport;
}
//省略AbstractServerArgs类里面的方法...
}
//省略TServer 类里面的方法...
}
TServer里面有一个静态类Args,继承了抽象类AbstractServerArgs,AbstractServerArgs的源码也在TServer里面
public static abstract class AbstractServerArgs> {
final TServerTransport serverTransport;
TProcessorFactory processorFactory;
TTransportFactory inputTransportFactory = new TTransportFactory();
TTransportFactory outputTransportFactory = new TTransportFactory();
TProtocolFactory inputProtocolFactory = new TBinaryProtocol.Factory();
TProtocolFactory outputProtocolFactory = new TBinaryProtocol.Factory();
public AbstractServerArgs(TServerTransport transport) {
serverTransport = transport;
}
//传入TProcessorFactory
public T processorFactory(TProcessorFactory factory) {
this.processorFactory = factory;
return (T) this;
}
//new一个TProcessorFactory工厂,将传入的TProcessor 放入TProcessorFactory工厂内,
public T processor(TProcessor processor) {
this.processorFactory = new TProcessorFactory(processor);
return (T) this;
}
//设置传输工厂
public T transportFactory(TTransportFactory factory) {
this.inputTransportFactory = factory;
this.outputTransportFactory = factory;
return (T) this;
}
//设置输入传输工厂
public T inputTransportFactory(TTransportFactory factory) {
this.inputTransportFactory = factory;
return (T) this;
}
//设置输出传输工厂
public T outputTransportFactory(TTransportFactory factory) {
this.outputTransportFactory = factory;
return (T) this;
}
//设置协议工厂
public T protocolFactory(TProtocolFactory factory) {
this.inputProtocolFactory = factory;
this.outputProtocolFactory = factory;
return (T) this;
}
//设置输入协议工厂
public T inputProtocolFactory(TProtocolFactory factory) {
this.inputProtocolFactory = factory;
return (T) this;
}
//设置输出协议工厂
public T outputProtocolFactory(TProtocolFactory factory) {
this.outputProtocolFactory = factory;
return (T) this;
}
}
TServer 类里面也有一些属性,但是这些属性都是在构造函数里面通过args的属性获得
public abstract class TServer {
/**
* Core processor
*/
protected TProcessorFactory processorFactory_;
/**
* Server transport
*
*/
protected TServerTransport serverTransport_;
/**
* Input Transport Factory
*/
protected TTransportFactory inputTransportFactory_;
/**
* Output Transport Factory
*/
protected TTransportFactory outputTransportFactory_;
/**
* Input Protocol Factory
*/
protected TProtocolFactory inputProtocolFactory_;
/**
* Output Protocol Factory
*/
protected TProtocolFactory outputProtocolFactory_;
private volatile boolean isServing;
protected TServerEventHandler eventHandler_;
// Flag for stopping the server
// Please see THRIFT-1795 for the usage of this flag
protected volatile boolean stopped_ = false;
protected TServer(TServer.AbstractServerArgs args) {
//TServer里的属性在初始化的时候通过args里的属性获取
processorFactory_ = args.processorFactory;
serverTransport_ = args.serverTransport;
inputTransportFactory_ = args.inputTransportFactory;
outputTransportFactory_ = args.outputTransportFactory;
inputProtocolFactory_ = args.inputProtocolFactory;
outputProtocolFactory_ = args.outputProtocolFactory;
}
/**
* The run method fires up the server and gets things going.
* 这个方法用来启动服务,是个抽象方法,详细的启动步骤由他的继承类实现
*/
public abstract void serve();
/**
* Stop the server. This is optional on a per-implementation basis. Not
* all servers are required to be cleanly stoppable.
*/
public void stop() {
}
public boolean isServing() {
return isServing;
}
protected void setServing(boolean serving) {
isServing = serving;
}
public void setServerEventHandler(TServerEventHandler eventHandler) {
eventHandler_ = eventHandler;
}
public TServerEventHandler getEventHandler() {
return eventHandler_;
}
public boolean getShouldStop() {
return this.stopped_;
}
public void setShouldStop(boolean shouldStop) {
this.stopped_ = shouldStop;
}
}
下面我么再来分析AbstractNonblockingServer 的代码
public abstract class AbstractNonblockingServer extends TServer {
//千篇一律吧AbstractNonblockingServerArgs继承于AbstractServerArgs
public static abstract class AbstractNonblockingServerArgs> extends AbstractServerArgs {
//多了个属性 最大buffer读取大小
public long maxReadBufferBytes = 256 * 1024 * 1024;
public AbstractNonblockingServerArgs(TNonblockingServerTransport transport) {
super(transport);
transportFactory(new TFramedTransport.Factory());
}
}
/**
* The maximum amount of memory we will allocate to client IO buffers at a
* time. Without this limit, the server will gladly allocate client buffers
* right into an out of memory exception, rather than waiting.
* 一次分配给客户端IO缓冲区的最大内存量,如果没有这个限制,
* 服务器分配给客户端缓冲区过大的话会抛出内存不足异常中,而不是等待。
* 暂时还不懂,看源码英文注释自己想象翻译的
*/
final long MAX_READ_BUFFER_BYTES;
/**
* How many bytes are currently allocated to read buffers.
*/
final AtomicLong readBufferBytesAllocated = new AtomicLong(0);
public AbstractNonblockingServer(AbstractNonblockingServerArgs args) {
super(args);
MAX_READ_BUFFER_BYTES = args.maxReadBufferBytes;
}
/**
* Begin accepting connections and processing invocations.
* 服务器通过调用这个方法开始接受客户端请求,进行业务逻辑处理
*/
public void serve() {
/**
* Begin accepting connections and processing invocations.
* 开启一个线程进行接受客户端请求,进行一系列的逻辑处理,但是这个方法没有实现体,
* 详细的实现留给继承AbstractNonblockingServer类的类去实现
*/
if (!startThreads()) {
return;
}
// start listening, or exit
//服务端开始接受连接,此法方法在此类里面已经实现了
if (!startListening()) {
return;
}
//设置服务端是否正在服务为true
setServing(true);
// this will block while we serve
/**
* Begin accepting connections and processing invocations.
* 阻塞当前服务,也就是开启这个server的线程,知道开启server的线程被中断
* 详细的实现留给继承AbstractNonblockingServer类的类去实现
*/
waitForShutdown();
setServing(false);
// do a little cleanup
stopListening();
}
}
AbstractNonblockingServer 类里面还有个比较重要的抽象类:AbstractSelectThread,SelectThread都继承于这个抽象类
protected abstract class AbstractSelectThread extends Thread {
protected Selector selector;
// List of FrameBuffers that want to change their selection interests.
protected final Set selectInterestChanges = new HashSet();
public AbstractSelectThread() throws IOException {
this.selector = SelectorProvider.provider().openSelector();
}
还有两个比较重要的方法
//这两个方法大部分情况下会在startThreads()方法里面被调用。
/**
* Do the work required to read from a readable client. If the frame is
* fully read, then invoke the method call.
* 从可以读取数据的客户端读取数据,如果数据块读满了,触发相应的方法回调
*/
protected void handleRead(SelectionKey key) {
// 获取附加在SelectionKey上的FrameBuffer
FrameBuffer buffer = (FrameBuffer) key.attachment();
// 读取客户端发过来的数据,如果读取失败,清除SelectionKey
if (!buffer.read()) {
cleanupSelectionKey(key);
return;
}
// if the buffer's frame read is complete, invoke the method.
// 如果读取客户端数据成功,requestInvoke触发相应事件,
// 也就是根据客户端请求,调用服务端相应方法
if (buffer.isFrameFullyRead()) {
if (!requestInvoke(buffer)) {
cleanupSelectionKey(key);
}
}
}
/**
* Let a writable client get written, if there's data to be written.
* 让可被写的客户端写数据
*/
protected void handleWrite(SelectionKey key) {
FrameBuffer buffer = (FrameBuffer) key.attachment();
if (!buffer.write()) {
cleanupSelectionKey(key);
}
}
下面开始正式讲解TNonblockingServer的源码
大家可以看出TNonblockingServer的源码除了老生常谈的Args类,多了个最重要的SelectAcceptThread类参数selectAcceptThread_,看名字就知道这个类肯定继承了Thread类,被当成一个线程了,SelectAcceptThread里面绝对封装了这个线程要处理的逻辑。
public static class Args extends AbstractNonblockingServerArgs {
public Args(TNonblockingServerTransport transport) {
super(transport);
}
}
private SelectAcceptThread selectAcceptThread_;
public TNonblockingServer(AbstractNonblockingServerArgs args) {
super(args);
}
源码往下看会看到我们熟悉的startThreads()方法
/**
* Start the selector thread to deal with accepts and client messages.
* 通过这个方法开启线程去处理客户端请求,这个发方法是重写的,将
* AbstractNonblockingServer抽象类里的方法重写了
* @return true if everything went ok, false if we couldn't start for some
* reason.
*/
@Override
protected boolean startThreads() {
// start the selector
try {
// 将selectAcceptThread_实例化
selectAcceptThread_ = new SelectAcceptThread((TNonblockingServerTransport)serverTransport_);
// 开启线程
selectAcceptThread_.start();
return true;
} catch (IOException e) {
LOGGER.error("Failed to start selector thread!", e);
return false;
}
}
SelectAcceptThread类也在TNonblockingServer类里面,我们看下SelectAcceptThread的类图和源码
SelectAcceptThread就是一个线程,想要的处理逻辑也封装在里面,
SelectAcceptThread线程中,使用Selector(选择器), 可以使用一个线程处理多个客户端连接。Selector 能够检测多个注册的通道上是否有事件发生(多个Channel以事件的方式可以注册到同一个Selector), 如果有事件发生, 便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道, 也就是管理多个连接和请求。
- 这些都是NIO的知识,如果不太了解,可以先去学习下NIO。
/**
* The thread that will be doing all the selecting, managing new connections
* and those that still need to be read.
*/
protected class SelectAcceptThread extends AbstractSelectThread {
// The server transport on which new client transports will be accepted
// 服务端的 serverTransport ,后面会把它注册到selector
private final TNonblockingServerTransport serverTransport;
/**
* Set up the thread that will handle the non-blocking accepts, reads, and
* writes.
*/
public SelectAcceptThread(final TNonblockingServerTransport serverTransport)
throws IOException {
this.serverTransport = serverTransport;
// 将serverTransport 注册到了selector,selector是在AbstractSelectThread里声明的
serverTransport.registerSelector(selector);
}
public boolean isStopped() {
return stopped_;
}
/**
* The work loop. Handles both selecting (all IO operations) and managing
* the selection preferences of all existing connections.
*/
public void run() {
try {
if (eventHandler_ != null) {
eventHandler_.preServe();
}
while (!stopped_) {
// 从这个地方开始进行select()
select();
processInterestChanges();
}
// 服务端停止以后,回收selector里面的key
for (SelectionKey selectionKey : selector.keys()) {
cleanupSelectionKey(selectionKey);
}
} catch (Throwable t) {
LOGGER.error("run() exiting due to uncaught error", t);
} finally {
try {
selector.close();
} catch (IOException e) {
LOGGER.error("Got an IOException while closing selector!", e);
}
stopped_ = true;
}
}
}
select()方法里面主要是通过seletor循环监控所有的socket,每次selector结束时,获取所有的处于就绪状态的socket,然后通过循环对这些处于就绪状态的socket进行处理
/**
* Select and process IO events appropriately:
* If there are connections to be accepted, accept them.
* If there are existing connections with data waiting to be read, read it,
* buffering until a whole frame has been read.
* If there are any pending responses, buffer them until their target client
* is available, and then send the data.
*/
private void select() {
try {
// wait for io events.
/**
* 线程阻塞在这里,seletor循环监控所有的IO事件,
* 每次selector结束时,获取所有的处于就绪状态的IO事件。
*/
selector.select();
// process the io events we received
/**
* 获取所有的处于就绪状态的io事件,通过遍历这些io事件来进行相应的处理,
* 每个客户端第一次连接后的socket,注册到selector后,都有一个SelectionKey与之对应
* 同理 服务端也注册到selector了,也有SelectionKey与之对应
*/
Iterator selectedKeys = selector.selectedKeys().iterator();
while (!stopped_ && selectedKeys.hasNext()) {
SelectionKey key = selectedKeys.next();
selectedKeys.remove();
// skip if not valid
if (!key.isValid()) {
cleanupSelectionKey(key);
continue;
}
// if the key is marked Accept, then it has to be the server transport.
if (key.isAcceptable()) {
// 服务端的transport接收到了客服端发来创建连接的请求,所以accept()
handleAccept();
} else if (key.isReadable()) {
// deal with reads
// 方法详细实现在AbstractSelectThread类里面
handleRead(key);
} else if (key.isWritable()) {
// deal with writes
// 方法详细实现在AbstractSelectThread类里面
handleWrite(key);
} else {
LOGGER.warn("Unexpected state in select! " + key.interestOps());
}
}
} catch (IOException e) {
LOGGER.warn("Got an IOException while selecting!", e);
}
}
protected FrameBuffer createFrameBuffer(final TNonblockingTransport trans,
final SelectionKey selectionKey,
final AbstractSelectThread selectThread) {
return processorFactory_.isAsyncProcessor() ?
new AsyncFrameBuffer(trans, selectionKey, selectThread) :
new FrameBuffer(trans, selectionKey, selectThread);
}
/**
* Accept a new connection.
*/
private void handleAccept() throws IOException {
SelectionKey clientKey = null;
TNonblockingTransport client = null;
try {
// accept the connection
// 接受客户端过来的连接请求
client = (TNonblockingTransport)serverTransport.accept();
// 将客户端注册到Selector里,以后就可以处理新加入客户端的请求了
clientKey = client.registerSelector(selector, SelectionKey.OP_READ);
// 实例化一个FrameBuffer,将实例化的FrameBuffer
FrameBuffer frameBuffer = createFrameBuffer(client, clientKey, SelectAcceptThread.this);
// 将实例化的FrameBuffer添加到新生成的客户端的SelectionKey
// 因为在handleRead()和handleWrite()方法里面都是在这个FrameBuffer里面获取数据,
// 调用服务端的方法,进行相应的业务处理后,再发送给客户端
clientKey.attach(frameBuffer);
} catch (TTransportException tte) {
// something went wrong accepting.
LOGGER.warn("Exception trying to accept!", tte);
if (clientKey != null) cleanupSelectionKey(clientKey);
if (client != null) client.close();
}
}
} // SelectAcceptThread