美文网首页Java 杂谈技术干货
【第16篇】Netty的Channel选择器工厂与轮询算法及注册

【第16篇】Netty的Channel选择器工厂与轮询算法及注册

作者: 爱学习的蹭蹭 | 来源:发表于2019-05-29 06:53 被阅读0次

    一、DefaultEventExecutorChooseFactory

    • DefaultEventExecutorChooseFactory选择器工厂
    • DefaultEventExecutorChooseFactory这个事件执行选择器工厂是在Netty的并发包里面,io.netty.util.concurrent而且并注解UnstableApi标志

    UnstableApi注解类这样指出的,(基于internal的工具类切记少用点
    1、使用指南:位于.internal.包中的内容是否不需要
    2、只有公共可访问的类/接口必须被注释,
    3、如果该注释不存在,则认为API是稳定的,因此在非主要版本中不能破坏向后兼容性!

    二、算法

    • round-robin 思想编程在负载均衡场景使用(轮询算法)
    • Netty使用了二的指数算法进行事件选择(isPowerOfTwo),从哪里可以看出来它是用了二的指数算法呢,从 EventExecutorChooserFactory接口 跟踪进去的EventExecutorChooser,然后通过IDEA工具可以鼠标点击绿色图标可以调出查看。


      EventExecutorChooserFactory#EventExecutorChooser
    • isPowerOfTwo关键代码
       //事件执行选择器
        public EventExecutorChooser newChooser(EventExecutor[] executors) {
            //isPowerOfTwo二的指数算法进行事件选择
            if (isPowerOfTwo(executors.length)) {
                return new PowerOfTwoEventExecutorChooser(executors);
            } else {
                return new GenericEventExecutorChooser(executors);
            }
        }
        //处理isPowerOfTwo
        private static boolean isPowerOfTwo(int val) {
            return (val & -val) == val;
        }
        //PowerOfTwo事件执行选择器
        private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
            //原子性的Integer类型类
            private final AtomicInteger idx = new AtomicInteger();
            private final EventExecutor[] executors; //事件执行器
           //PowerOfTwo事件执行选择器构造方法
            PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
                this.executors = executors;
            }
    
            @Override//下一个事件执行器
            public EventExecutor next() {
                return executors[idx.getAndIncrement() & executors.length - 1];
            }
        }
    
    • DefaultEventExecutorChooserFactory ( round-robin
    /**
     * 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);
            }
        }
    

    三、加权

    • 加权让性能好的机器在集群中选择的机率较为大,配置低的机器选择较低或概率小

    四、SingleThreadEventLoop

    • SingleThreadEventLoop针对EventLoop的抽象的父类会将所有被提交的任务当个线程去执行,它是一个单线程的事件循环对象
      @Override //管道注册
        public ChannelFuture register(Channel channel) {
          //返回一个注册(register)的复合管道
            return register(new DefaultChannelPromise(channel, this));
        }
    
        @Override//复合管道注册
        public ChannelFuture register(final ChannelPromise promise) {
            ObjectUtil.checkNotNull(promise, "promise");
            promise.channel().unsafe().register(this, promise);
            return promise;
        }
    
    • promise.channel().unsafe().register(this, promise);的Channel接口的Unsafe的接口的方法,可以看出AbstractChannel类的内部类的AbstractUnsafe的register注册方法,而且AbstractUnsafe是一个抽象类.


      AbstractUnsafe
    • AbstractChanne类重要的方法,如:doBind,doDisconnect,doDeregisterconnect
    • AbstractChanne的AbstractUnsafe内部类l许多比较重要的方法,如:
      register0registerderegistersafeSetSuccesssafeSetFailurerecvBufAllocHandleinvokeLater更多请看截图
    AbstractChanne AbstractUnsafe

    五、 Unsafe
    Unsafe 提供内部类使用,提供不安全的操作,在Channel接口定义

    六、MultithreadEventLoopGroup类

    • MultithreadEventLoopGroup有注册入口处理,register代码如下:
        @Override
        public EventLoop next() {
            return (EventLoop) super.next();
        }
        @Override
        public ChannelFuture register(Channel channel) {
            //此时这个next方法是上面的 public EventLoop next()
            return next().register(channel);
        }
    

    6.1 register的实现类.

    • return next().register(channel);的实现类.
      方法点击进去几个类进行实现registerf方法EmbeddedEventLoopMultithreadEventLoopGroupSingleThreadEventLoopThreadPerChannelEventLoopGroup、如图所示:
      image.png 、

    6.2 ThreadPerChannelEventLoopGroup代码分析.

    • 咱们以典型的ThreadPerChannelEventLoopGroup进行跟踪一下代码
       @Override
        public ChannelFuture register(Channel channel) {
            //判断管道对象是否为空,是空就返回空指针操作
            if (channel == null) {
                throw new NullPointerException("channel");
            }
            try {
                EventLoop l = nextChild(); //事件循环
                //返回一个事件循环注册的默认复合管道处理
                return l.register(new DefaultChannelPromise(channel, l));
            } catch (Throwable t) {
                return new FailedChannelFuture(channel, GlobalEventExecutor.INSTANCE, t);
            }
        }
    

    相关文章

      网友评论

        本文标题:【第16篇】Netty的Channel选择器工厂与轮询算法及注册

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