thrift的服务模式
对于Java中使用thrift,其服务模式如下:
1.阻塞服务模型:TSimpleServer、TThreadPoolServer。
TSimpleServer的工作模式采用最简单的阻塞IO,实现方法简洁明了,便于理解,但是一次只能接收和处理一个socket连接,效率比较低。它主要用于演示Thrift的工作过程,在实际开发过程中很少用到它。
TThreadPoolServer模式采用阻塞socket方式工作,主线程负责阻塞式监听是否有新socket到来,具体的业务处理交由一个线程池来处理。TThreadPoolServer在构造函数中创建工作线程池,用executorService_来处理RPC请求,根据args参数判断用户是否自己设置了线程池,如未设置,就根据传递进来的参数创建线程池,使用ThreadPoolExecutor创建 。其构造函数:
public TThreadPoolServer(Args args) {
super(args);
stopTimeoutUnit = args.stopTimeoutUnit;
stopTimeoutVal = args.stopTimeoutVal;
......
executorService_ = args.executorService != null ? args.executorService : createDefaultExecutorService(args);}
创建线程池:
private static ExecutorService createDefaultExecutorService(Args args) { SynchronousQueue<Runnable> executorQueue = new SynchronousQueue<Runnable>(); return new ThreadPoolExecutor(args.minWorkerThreads, args.maxWorkerThreads, 60, TimeUnit.SECONDS, executorQueue);}
其中,默认的minWorkerThreads=5,maximumPoolSize=2147483647,keepAliveTime=60,unit=TimeUnit.SECONDS,executorQueue = new SynchronousQueue()。
TThreadPoolServer模式的优点:
拆分了监听线程(Accept Thread)和处理客户端连接的工作线程(Worker Thread),数据读取和业务处理都交给线程池处理。因此在并发量较大时新连接也能够被及时接受。线程池模式比较适合服务器端能预知最多有多少个客户端并发的情况,这时每个请求都能被业务线程池及时处理,性能也非常高。
TThreadPoolServer模式的缺点:
线程池模式的处理能力受限于线程池的工作能力,当并发请求数大于线程池中的线程数时,新请求也只能排队等待。
2.非阻塞服务模型:TNonblockingServer、THsHaServer和TThreadedSelectorServer。
TNonblockingServer模式也是单线程工作,但是采用NIO的模式,借助Channel/Selector机制, 采用IO事件模型来处理。(其中NIO中的Channel/Selector,可以理解为,举个例子,我们把Channel比作高铁,则Selector就是高铁的调度系统,负责监控每列高铁的运行状态,是出站还是在路上,也就是说Selector可以轮询Channel的状态。)
所有的socket都被注册到selector中,在一个线程中通过seletor循环监控所有的socket。
每次selector循环结束时,处理所有的处于就绪状态的socket,对于有数据到来的socket进行数据读取操作,对于有数据发送的socket则进行数据发送操作,对于监听socket则产生一个新业务socket并将其注册到selector上。
TNonblockingServer模式优点:
相比于TSimpleServer效率提升主要体现在IO多路复用上,TNonblockingServer采用非阻塞IO,对accept/read/write等IO事件进行监控和处理,同时监控多个socket的状态变化。
TNonblockingServer模式缺点:
TNonblockingServer模式在业务处理上还是采用单线程顺序来完成。在业务处理比较复杂、耗时的时候,例如某些接口函数需要读取数据库执行时间较长,会导致整个服务被阻塞住,此时该模式效率也不高,因为多个调用请求任务依然是顺序一个接一个执行。
鉴于TNonblockingServer的缺点,THsHaServer继承于TNonblockingServer,引入了线程池提高了任务处理的并发能力。THsHaServer是半同步半异步(Half-Sync/Half-Async)的处理模式,Half-Aysnc用于IO事件处理(Accept/Read/Write),Half-Sync用于业务handler对rpc的同步处理上。
THsHaServer的优点:
THsHaServer与TNonblockingServer模式相比,THsHaServer在完成数据读取之后,将业务处理过程交由一个线程池来完成,主线程直接返回进行下一次循环操作,效率大大提升。
THsHaServer的缺点:
主线程仍然需要完成所有socket的监听接收、数据读取和数据写入操作。当并发请求数较大时,且发送数据量较多时,监听socket上新连接请求不能被及时接受。
TThreadedSelectorServer是对THsHaServer的一种扩充,它将selector中的读写IO事件(read/write)从主线程中分离出来。同时引入worker工作线程池,它也是种Half-Sync/Half-Async的服务模型。
TThreadedSelectorServer模式是目前Thrift提供的*的线程服务模型,它内部有如果几个部分构成:
a. 一个AcceptThread线程对象,专门用于处理监听socket上的新连接。
b. 若干个SelectorThread对象专门用于处理业务socket的网络I/O读写操作,所有网络数据的读写均是有这些线程来完成。
c. 一个负载均衡器SelectorThreadLoadBalancer对象,主要用于AcceptThread线程接收到一个新socket连接请求时,决定将这个新连接请求分配给哪个SelectorThread线程。
d. 一个ExecutorService类型的工作线程池,在SelectorThread线程中,监听到有业务socket中有调用请求过来,则将请求数据读取之后,交给ExecutorService线程池中的线程完成此次调用的具体执行。主要用于处理每个rpc请求的handler回调处理(这部分是同步的)。
python使用thrift的服务模式:
在/usr/local/lib/python2.7/dist-packages/thrift/server目录下看到TServer.py,这个文件中列举了在TServer基础上实现的四种服务模式类:TSimpleServer、TThreadedServer、TThreadPoolServer、TForkingServer。和Java的几种模式不太相同。
① TSimpleServer模式,描述如下:
这个服务模式的工作原理应该是和Java的类似,简单的单线程服务,一次只能接收和处理一个socket连接。
② TThreadedServer模式,描述如下:
线程服务器,每个连接产生一个新线程。
③ TThreadPoolServer模式,描述如下:
该服务模式带有一个大小固定的线程池用于处理请求。我推测这个应该是类似于Java的TThreadPoolServer,主线程负责阻塞式监听是否有新socket到来,具体的业务处理交由一个线程池来处理。其中线程池中默认的线程数目为10。
④ TForkingServer模式 ,描述如下:
这种模式每次检测到有socket连接时,调用os.fork()创建一个新线程来处理。当并发数目大于默认值的线程池中线程数目时,显然比上TThreadPoolServer模式的执行效率要高。
综上所述,当并行度不大于线程池中线程数时,使用TThreadPoolServer模式和TForkingServer模式均可,我测试启动了6个客户端,使用TThreadPoolServer模式和TForkingServer模式运行时间相当;
而当我启动了14个客户端时,TThreadPoolServer模式就比较耗时,因为线程池中只有10个线程,只能先把前10个任务执行完后才会再接收新任务,在处理这10个任务期间,后面的任务处于等待的状态,因此会耗时。TForkingServer模式可以同时处理这14个任务,使得运行性能高于TThreadPoolServer模式。
因此选用TForkingServer模式。
上一篇: Access随机显示记录解决方案