美文网首页
Netty在Dubbo中使用了哪些Handler

Netty在Dubbo中使用了哪些Handler

作者: 书唐瑞 | 来源:发表于2021-01-24 22:45 被阅读0次

    本篇以Dubbo作为服务端为例.

    当配置如下信息时

    <dubbo:application name="infuq-dubbo-provider" />
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181" check="false" />
    <dubbo:protocol name="dubbo" port="20880" threads="200"/>
    <dubbo:service ref="queryUserInfoFacade" interface="com.infuq.facade.QueryUserInfoFacade" version="1.0.0" />
    <bean id="queryUserInfoFacade" class="com.infuq.facade.impl.QueryUserInfoFacadeImpl" />
    

    Spring在启动的过程中,通过DubboNamespaceHandler解析上面的标签.
    将每个标签与之对应的BeanDefinition注册到BeanFactory中.
    Spring再根据BeanDefinition生成对应的Bean实例.
    上面的<dubbo:service />标签最终会生成对应的ServiceBean实例.

    // 源码位置: com.alibaba.dubbo.config.spring.ServiceBean
    public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
            ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware,
            ApplicationEventPublisherAware {
              
    }
    

    ServiceBean实现了ApplicationListener<ContextRefreshedEvent>接口.
    在Spring创建完所有的Bean之后,最后会发布一个ContextRefreshedEvent事件.
    因此ServiceBean的onApplicationEvent()方法会被执行.

    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (isDelay() && !isExported() && !isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            // 暴露服务
            export();
        }
    }
    

    接下来就进入到了服务暴露的过程.
    (本篇文章不会详细讲述暴露流程)

    服务暴露会完成两件事情. 第一件事情是通过Netty开启服务,监听端口.
    第二件事情是将服务注册到注册中心.

    跟进export()方法, 最后会来到DubboProtocol类
    大体看下它是如何开启服务,监听端口? 留意下,有个属性requestHandler.

    public class DubboProtocol extends AbstractProtocol {
      private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() { ... };
    ​
      private ExchangeServer createServer(URL url) {
        // 绑定
        server = Exchangers.bind(url, requestHandler);
      }
    ​
    }
    

    跟进bind()方法,最后会来到NettyServer的doOpen()方法.
    留意下,有个属性nettyServerHandler.

    ​// 源码位置: com.alibaba.dubbo.remoting.transport.netty4.NettyServer
    protected void doOpen() throws Throwable {
        bootstrap = new ServerBootstrap();
    ​
        bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
        workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS), new DefaultThreadFactory("NettyServerWorker", true));
    ​
        // 重要的Handler
        final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
        channels = nettyServerHandler.getChannels();
    ​
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
                .childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                        ch.pipeline()
                                .addLast("decoder", adapter.getDecoder())
                                .addLast("encoder", adapter.getEncoder())
                                .addLast("handler", nettyServerHandler);// 处理请求和响应的Handler
                    }
                });
        // bind
        ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
        channelFuture.syncUninterruptibly();
        channel = channelFuture.channel();
    ​
    }
    

    从DubboProtocol类的requestHandler属性到NettyServer的nettyServerHandler属性.
    ​这一路会经历很多Handler,经过层层封装,最后才封装成NettyServerHandler.

    它会经历如下Handler
    NettyServerHandler
    -> NettyServer
    -> MultiMessageHandler
    -> ​HeartbeatHandler
    -> AllChannelHandler
    -> ​DecodeHandler
    -> HeaderExchangeHandler
    -> ​ExchangeHandler

    Netty在Dubbo中使用了哪些Handler.png

    当客户端连接服务端,或者发送数据到服务端的时候​,

    首先会由NettyServerHandler处理请求,然后依次将请求传递下去,最后到ExchangeHandler.

    那么这些Handler是否都由同一个线程执行的吗? 并不是


    Netty在Dubbo中使用了哪些Handler - 副本.png

    如上图, ​在AllChannelHandler中有个executor属性,它是一个线程池.

    NettyServerHandler
    -> NettyServer
    -> MultiMessageHandler
    -> HeartbeatHandler
    -> AllChannelHandler
    以上这几个Handler是由同一个线程执行的, 是由Netty的IO线程执行的, 名称类似NettyServerWorker-5-7

    -> DecodeHandler
    -> HeaderExchangeHandler
    -> ExchangeHandler
    以上这几个Handler是由另一类线程执行的, 是由AllChannelHandler中的线程池执行的, 名称类似​DubboServerHandler-2.0.1.15:20880-thread-57

    也就是说, Netty的IO线程在接收到请求后, 先依次执行
    NettyServerHandler ​-> NettyServer ​->
    MultiMessageHandler ​-> HeartbeatHandler
    -> AllChannelHandler 这五个Handler.
    之后会由AllChannelHandler中的​线程池执行后面的DecodeHandler
    -> HeaderExchangeHandler ​-> ExchangeHandler 这三个Handler.

    未命名文件(1).png
    <dubbo:protocol name="dubbo" port="20880" threads="200" threadpool="fixed"  />
    

    使用threads=200, threadpool=fixed 就是在配置图中红色区域的线程池. 线程池也是调优的一个地方.

    相关文章

      网友评论

          本文标题:Netty在Dubbo中使用了哪些Handler

          本文链接:https://www.haomeiwen.com/subject/tppvzktx.html