线程模型
Dubbo使用多种线程模型来处理请求,默认使用Netty进行通信,默认线程分为业务线程
和IO线程
。带着下面问题学习本文
-
1)Dubbo处理请求和响应是在业务线程执行还是在IO线程执行呢?
-
2)如何才能使系统性能和资源利用率达到最佳,这就是学习线程模型的意义。
通常来说如果请求处理非常快,只是简单的内存操作,这时直接在IO线程处理反而比较快,因为避免了线程调度和线程上下文切换的开销。
如果请求处理比较慢,会发起新的IO请求,比如数据库读写,这时如果还在在IO线程处理这些逻辑会阻塞IO线程,使得其他
请求无法处理,因此这种场景应当分发的业务线程处理。
认识线程模型接口 Dispatcher
从接口我们得到信息
- 默认的线程模型是 AllDispatcher
- 线程模型的核心主要返回的ChannelHandler 不同
@SPI(AllDispatcher.NAME)
public interface Dispatcher {
/**
* dispatch the message to threadpool.
*
* @param handler
* @param url
* @return channel handler
*/
@Adaptive({Constants.DISPATCHER_KEY, "dispather", "channel.handler"})
// The last two parameters are reserved for compatibility with the old configuration
ChannelHandler dispatch(ChannelHandler handler, URL url);
}
ChannelHandler 接口
包含 connected 、disconnected、sent、received、caught 方法。
ChannelHandler接口包装类 WrappedChannelHandler ,所有的线程模型相关Handler 都继承WrappedChannelHandler
WrappedChannelHandler 构造参数中 handler 可以参考以前的文章。
线程模型默认的有几种实现如下
all=org.apache.dubbo.remoting.transport.dispatcher.all.AllDispatcher
direct=org.apache.dubbo.remoting.transport.dispatcher.direct.DirectDispatcher
message=org.apache.dubbo.remoting.transport.dispatcher.message.MessageOnlyDispatcher
execution=org.apache.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher
connection=org.apache.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedDispatcher
all
所有消息事件(请求、响应、连接事件、断开连接事件、心跳事件)都分派给业务线程池处理.
所有事件处理前会获取线程池
ExecutorService executor = getExecutorService();
然后通过executor 异步执行
message only
只有请求响应的事件会异步执行
public class MessageOnlyChannelHandler extends WrappedChannelHandler {
public MessageOnlyChannelHandler(ChannelHandler handler, URL url) {
super(handler, url);
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getExecutorService();
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);
}
}
}
Direct
直接在IO 线程处理
execution
execution 请求类消息派发到业务线程
总结
默认使用的All, 所有的事件都放到业务线程处理,尽管有些请求处理很快,可能在IO线程处理比较合适,但是实际情况如果我们无法确定该业务逻辑是否
哪天会处理变慢,使用All比较保险,因为它不会阻塞IO线程,导致其他请求无法处理。