netty源码分析(十六)Channel选择器工厂与轮询算法及注册底层实现

上一节说到注册的入口,即
MultithreadEventLoopGroup:

    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }

注册channel第一步调用了next()方法,next()是MultithreadEventLoopGroup里边的:

    public EventLoop next() {
        return (EventLoop) super.next();
    }

到了父类MultithreadEventExecutorGroup:

    public EventExecutor next() {
        return chooser.next();
    }

这里出现了一个chooser:

private final EventExecutorChooserFactory.EventExecutorChooser chooser;

看一下他的结构,EventExecutorChooserFactory是一个工厂,生产各种Executor,,用EventExecutorChooserFactory的实现类DefaultEventExecutorChooserFactory看一下:

/**
 * Default implementation which uses simple round-robin to choose next {@link EventExecutor}.
 * 默认使用round-robin算法选择下一个实例的EventExecutor实现
 * round-robin:主要用在负载均衡方向,比如有5台机器,第一次分请求到了第一台机器,第二次到了第二台机器,第三次请求到了第三台请求,以此类推一直到第五台机器,然后第六次又到了第一台机器,这样一个轮流的调用,处理负载,这里的Executor数组也是使用这种方式,保证数组里边的EventExecutor被均衡调用。
 */
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        if (isPowerOfTwo(executors.length)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }

从这里可以看到netty对性能的压榨,当有2的指数个executor的时候使用PowerOfTwoEventExecutorChooser性能会比非指数个的GenericEventExecutorChooser性能高一点,PowerOfTwoEventExecutorChooser和GenericEventExecutorChooser都是DefaultEventExecutorChooserFactory 的静态内部类,都有next()方法返回一个EventExecutor。以上是对chooser的创建的一个分析,
回到MultithreadEventExecutorGroup看一下对chooser的赋值:

//伪代码
public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
    private final EventExecutor[] children;
    protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
       children = new EventExecutor[nThreads];
         for (int i = 0; i < nThreads; i ++) {
            children[i] = newChild(executor, args);
         }   
        chooser = chooserFactory.newChooser(children);  
    }
}

children的来源是newChild()方法:

    /**
     * Create a new EventExecutor which will later then accessible via the {@link #next()}  method. This method will be
     * called for each thread that will serve this {@link MultithreadEventExecutorGroup}.
     *
     创建一个EventExecutor ,稍后可以调用next()方法,这个next()方法被每个线程调用,这些线程 是服务MultithreadEventExecutorGroup的
     */
    protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;

这个是EventExecutor 的创建,接下来我们看一下register方法,我们打了一个断点:
这里写图片描述
之后debug进入register方法,我们进入的是SingleThreadEventLoop:
这里写图片描述

/**
 * Abstract base class for {@link EventLoop}s that execute all its submitted tasks in a single thread.
 * EventLoop的基础抽象类,所有提交的任务都会在一个线程里边执行。
 *
 */
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
...略
    public ChannelFuture register(Channel channel) {
        return register(new DefaultChannelPromise(channel, this));
    }
    ...略
}

DefaultChannelPromise是ChannelFuture的具体实现, 其持有Channel 和当前的EventLoop。

    public DefaultChannelPromise(Channel channel, EventExecutor executor) {
        super(executor);
        this.channel = channel;
    }

父类->

public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
    public DefaultPromise(EventExecutor executor) {
        this.executor = checkNotNull(executor, "executor");
    }
}

最后我们来到register方法:

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop
    public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        promise.channel().unsafe().register(this, promise);
        return promise;
    }
}

这个方法是注册逻辑的真正的入口了,出现了unsafe对象,下一节介绍。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty5.0 架构剖析和源码解读 作者:李林锋 版权所有 email neu_lilinfeng@ © Netty5.0 架构剖析和源码解读1 1. 概述2 1.1. JAVA 的IO演进2 1.1.1. 传统BIO通信的弊端2 1.1.2. Linux 的网络IO模型简介4 1.1.3. IO复用技术介绍7 1.1.4. JAVA的异步IO8 1.1.5. 业界主流的NIO框架介绍10 2.NIO入门10 2.1. NIO服务端10 2.2. NIO客户端13 3.Netty源码分析16 3.1. 服务端创建16 3.1.1. 服务端启动辅助类ServerBootstrap16 3.1.2. NioServerSocketChannel注册21 3.1.3. 新的客户端接入25 3.2. 客户端创建28 3.2.1. 客户端连接辅助类Bootstrap28 3.2.2. 服务端返回ACK应答,客户端连接成功32 3.3. 读操作33 3.3.1. 异步读取消息33 3.4. 写操作39 3.4.1. 异步消息发送39 3.4.2. Flush操作42 4.Netty架构50 4.1. 逻辑架构50 5. 附录51 5.1. 作者简介51 5.2. 使用声明51 1. 概述 1.1.JAVA 的IO演进 1.1.1. 传统BIO通信的弊端 在JDK 1.4推出JAVANIO1.0之前,基于JAVA 的所有Socket通信都采用 BIO 了同步阻塞模式( ),这种一请求一应答的通信模型简化了上层的应用开发, 但是在可靠性和性能方面存在巨大的弊端。所以,在很长一段时间,大型的应 C C++ 用服务器都采用 或者 开发。当并发访问量增大、响应时间延迟变大后, 采用JAVABIO作为服务端的软件只有通过硬件不断的扩容来满足访问量的激 增,它大大增加了企业的成本,随着集群的膨胀,系统的可维护性也面临巨大 的挑战,解决这个问题已经刻不容缓。 首先,我们通过下面这幅图来看下采用BIO 的服务端通信模型:采用BIO 通信模型的 1connect NewThread1 WebBrowse 2connect 2handle(Req) WebBrowse 3connect Acceptor NewThread2 WebBrowse WebBrowse 4connect NewThread3 3sendResponsetopeer NewThread4 图1.1.1-1 BIO通信模型图 服务端,通常由一个独立的Accepto 线程负责监听客户端的连接,接收到客户 端连接之后为客户端连接创建一个新的线程处理请求消息

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值