前言
dubbo底层通讯使用的是netty,下面介绍下dubbo中使用netty业务线程池的使用。
一.业务线程池
为什么需要业务线程池?直接使用netty的io线程处理非耗时链接是ok的;如果业务有数据库,调用第三方接口等耗时操作,就会阻塞住io线程,导致其他的io线程得不到及时的处理,造成阻塞导致客户端超时。所以对于耗时操作,扔到业务线程池,释放io线程去处理其他连接。
二.源码解析
源码是dubbo3.1
服务端接受到请求的链路
received()方法:netty pipeline链路,NettyServerHandler自定义handler
IO线程:
NettyServerHandler=>AbstractPeer=>MultiMessageHandler=>HeartbeatHandler=>AllChannelHandler(获取业务线程池)
业务线程:
ChannelEventRunnable=>DecodeHandler=>HeaderExchangeHandler=>DubboProtocol$ExchangeHandlerAdapter=> 《invoke filter chain》 => real method
中间都是一些链路逻辑处理,重点看看AllChannelHandler
public void received(Channel channel, Object message) throws RemotingException {
//获取线程池
ExecutorService executor = getPreferredExecutorService(message);
try {
//执行业务逻辑
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
if(message instanceof Request && t instanceof RejectedExecutionException){
sendFeedback(channel, (Request) message, t);
return;
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
这个方法getPreferredExecutorService获取线程池:
/**
* Currently, this method is mainly customized to facilitate the thread model on consumer side.
* 1. Use ThreadlessExecutor, aka., delegate callback directly to the thread initiating the call. //客户端使用ThreadlessExecutor,发起调用的线程执行
* 2. Use shared executor to execute the callback. //服务端用线程池
*
* @param msg
* @return
*/
public ExecutorService getPreferredExecutorService(Object msg) {
if (msg instanceof Response) {
Response response = (Response) msg;
DefaultFuture responseFuture = DefaultFuture.getFuture(response.getId());
// a typical scenario is the response returned after timeout, the timeout response may have completed the future
if (responseFuture == null) {
return getSharedExecutorService();
} else {
ExecutorService executor = responseFuture.getExecutor();
if (executor == null || executor.isShutdown()) {
executor = getSharedExecutorService();
}
return executor;
}
} else {
return getSharedExecutorService();
}
}
1.如果是客户端处理response,未超时情况下使用ThreadlessExecutor;超时了可能处理了等待的future,使用共享线程池;
2.如果是服务端,使用共享线程池;
这个区别是客户端使用当前发起调用的线程执行返回结果,减少线程切换;服务端则需要放入线程池执行,防止阻塞io线程。