dubbo Netty服务启动流程及线程模型分析

  总所周知,dubbo是一个RPC框架,其网络通信采用Netty,其Netty服务在何时启动?启动流程是怎样的?线程模型是怎样的的?本文将解答以上问题。

Netty服务启动流程

  服务端与消费端的启动流程大同小异,你可以以同样的方法来分析服务端的启动流程,所以这里以服务端为例。
  Dubbo中有一个叫做NettyServer的类,该类就是Netty服务启动类。
  我们首先看该类的构造方法。
 1 public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
 2     super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
 3 }
 4 
 5 // ChannelHandlers
 6 public static ChannelHandler wrap(ChannelHandler handler, URL url) {
 7     return ChannelHandlers.getInstance().wrapInternal(handler, url);
 8 }
 9 
10 protected ChannelHandler wrapInternal(ChannelHandler handler, URL url) {
11     return new MultiMessageHandler(new HeartbeatHandler(ExtensionLoader.getExtensionLoader(Dispatcher.class)
12             .getAdaptiveExtension().dispatch(handler, url)));
13 }
  NettyServer是ChannelHandler的包装类,其ChannelHandler接口,又持有了ChannelHandler对象,其中的ChannelHandler的调用链在构造方法中已经完整的呈现出来了。
  值得注意的是,在ChannelHandlers#wrapInternal方法中获取了Dispthcer的自适应类,然后调用了它的dispath方法。这里默认会获取到AllDispatcher对象,该对象的dispath方法就会创建一个AllChannelHandler对象。还记得在《服务注册与调用流程》中提到的处理请求、响应的AllChannelHandler对象吗,该对象就是在这里创建的。
  接下来我们看下服务启动的入口,该类中有一个doOpen方法,该方法就是服务创建的入口。
 1 protected void doOpen() throws Throwable {
 2     NettyHelper.setNettyLoggerFactory();
 3     ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
 4     ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
 5     ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
 6     bootstrap = new ServerBootstrap(channelFactory);
 7 
 8     final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
 9     channels = nettyHandler.getChannels();
10 
11     bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
12         @Override
13         public ChannelPipeline getPipeline() {
14             NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
15             ChannelPipeline pipeline = Channels.pipeline();
16             // 添加编解码器以及Dubbo的ChannelHandler
17             pipeline.addLast("decoder", adapter.getDecoder());
18             pipeline.addLast("encoder", adapter.getEncoder());
19             pipeline.addLast("handler", nettyHandler);
20             return pipeline;
21         }
22     });
23     // bind
24     channel = bootstrap.bind(getBindAddress());
25 }
  其流程就是一个普通的Netty服务端的启动流程,这里不赘述。虽然流程简单,但是这里体现了dubbo的线程模型,放到下一节来讲。
  我们在该方法打一个断点就能够看到Netty服务的入口是在DubboProtocol的export方法,其中有一行调用了openServer方法,这里就是入口。

线程模型

  我们再次看一下doOpen方法,其中值得注意的是,Dubbo采用的Netty线程模型是使用的主从线程模型,然后在AllChannelHandler中也会有一个线程池。
  我们在DubboProtocol#openServer中可以看到,对于同一个地址(ip:port)只会存在一个NettyServer,对于服务端来说,地址就是自身的ip+dubbo协议的port,所以AllChannelHandler也会只有一个,所以AllChannelHandler中的线程池是服务端共享的。
  通过上面的分析,那么我们可以得出Dubbo的线程模型如下图所示:

  boss线程以及worker线程都是Netty的线程,而worker线程中还会使用到一个线程池,该线程池即为Dubbo的业务线程池,也就是AllChannelHandler中使用到的那个线程池。
  Dubbo提供了若干种线程分发策略,即Dispather的实现类:

  反应到程序中,就是将AllChannelHandler替换成了其他的ChannelHandler。

原文地址:https://www.cnblogs.com/ouhaitao/p/14329389.html