Dubbo源码解析第一期:如何使用Netty4构建RPC

一、背景

        早期学习和使用Dubbo的时候(那时候Dubbo还没成为Apache顶级项目),写过一些源码解读,但随着Dubbo发生了翻天覆地的变化,那些文章早已过时,所以现在计划针对最新的Apache Dubbo源码来进行“阅读理解”,希望和大家一起再探Dubbo的实现。由于能力有限,如果文章有错误的地方,欢迎大家留言指正。

        本期的主题是Dubbo如何使用Netty4构建RPC来通讯

二、Server端视角

        我们看看作为服务提供方,Apache Dubbo是如何使用Netty4的。

2.1 Netty的线程组

        线程组作为Netty的Reactor设计核心组件,在这里自然少不了,我们看到org.apache.dubbo.remoting.transport.netty4.NettyServer中有如下两个方法:

    int DEFAULT_IO_THREADS = Math.min(Runtime.getRuntime().availableProcessors() + 1, 32);
    String IO_THREADS_KEY = "iothreads";
    String EVENT_LOOP_BOSS_POOL_NAME = "NettyServerBoss";
    String EVENT_LOOP_WORKER_POOL_NAME = "NettyServerWorker";

    protected EventLoopGroup createBossGroup() {
        return NettyEventLoopFactory.eventLoopGroup(1, EVENT_LOOP_BOSS_POOL_NAME);
    }

    protected EventLoopGroup createWorkerGroup() {
        return NettyEventLoopFactory.eventLoopGroup(
            getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
            EVENT_LOOP_WORKER_POOL_NAME);
    }

分别用来构建Boss线程组和Worker线程组,Boss线程组负责创建连接,连接创建成功后由Worker线程组来负责处理和发送请求。注意Boss线程组只设置了1个线程,而且没有设置修改接口,通常1个也是够用的,如果设置成可配的会更好。而Worker线程组默认值是当前可用核数和32中取最小值,注意,是最小值,不是最大值,意味着如果你单个Provider实例上可用的核超过32,那么一定要设置IO_THREADS_KEY,否则可能无法达到最大吞吐量(特别是IO密集型应用)。上面代码也给出了这两个线程组的线程池的名称,如果不清楚现在跑的是多少,可以jstack命令看下。注意,为了阐述方便,上面的四个属性定义来自org.apache.dubbo.remoting.Constants。

2.1 Netty的ChannelHandler

        Netty的可扩展性主要来自其核心组件之一ChannelHandler,ChannelHandler能帮助我们解决拆包&粘包、协议编解码、权限校验等RPC常遇到的问题。那我们来看看现在Dubbo的Provider端用到了哪些ChannelHandler,同样,我们看NettyServer#initServerBootstrap方法:

    protected void initServerBootstrap(NettyServerHandler nettyServerHandler) {
        boolean keepalive = getUrl().getParameter(KEEP_ALIVE_KEY, Boolean.FALSE);
        bootstrap
                .group(bossGroup, workerGroup)
                // 根据是否支持EPoll来返回EpollServerSocketChannel或者NioServerSocketChannel
                .channel(NettyEventLoopFactory.serverSocketChannelClass())
                // SO_REUSEADDR设置为true表示允许重用本地地址和端口。如果服务器意外关闭后再次启动,可以立即绑定到之前使用的地址和端口。
                .option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
                // 表示禁用Nagle算法。Nagle算法会将小的网络包合并成较大的包来提高网络效率,但会增加数据传输的延迟。一般对延迟敏感的场景都会禁用Nagle算法。
                .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
                // 开启TCP的心跳机制,用于检测连接是否还活着
                .childOption(ChannelOption.SO_KEEPALIVE, keepalive)
                // PooledByteBufAllocator是Netty提供的一种内存分配器实现,它可以重用ByteBuf对象的内存,提高内存的利用率和性能。
                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        int closeTimeout = UrlUtils.getCloseTimeout(getUrl());
                        NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                        // 处理HTTPS
                        ch.pipeline().addLast("negotiation", new SslServerTlsHandler(getUrl()));
                        ch.pipeline()
                    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值