• 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。

  • 相关阅读:
    西子凌波26: 看各路新秀 2015-04-19
    西子凌波21:美元 2015-03-19
    西子凌波04:再读 教你炒股票104:几何结构与能量动力结构1有感 2011-05-23
    西子凌波08:闲聊~~共勉~~ 感恩缠主 2013-12-07
    西子凌波07:传统底部形态缠论解析 2011-10-26
    西子凌波03:缠论中的MACD 2011-05-21
    数组内Merge
    leetcode -- Decode Ways
    leetcode -- Distinct Subsequences
    leetcode -- permutation 总结
  • 原文地址:https://www.cnblogs.com/ouhaitao/p/14329389.html
Copyright © 2020-2023  润新知