disruptor组件在超级牛掰开源网关组件star80K+【shenyu】中的运用+研究

disruptor组件在超级牛掰开源网关组件star80K+【shenyu】中的运用+研究

  • 作者:爱抄中间件代码的路人丙

源码地址:https://gitee.com/Apache-ShenYu/shenyu?_from=gitee_search

打个小广告,觉得有收获的小伙伴,希望点赞、收藏,笔者将会持续的分享自己研究源码的学习和收获!

阅读提醒:源码部分建议文章和代码一起食用

本文主要探究以下几个问题:

  • shenyu 使用disruptor的场景是什么?
  • shenyu 为什么使用disruptor 而不使用其他的内存队列?
  • shenyu 是如何使用disruptor
  • shenyu 对disruptor 做了其他的扩展么

阅读本文你将收获到的内容

  • 参考disruptor 在shenyu开源项目中的优雅使用方式

一、shenyu如何封装disruptor

大家可以去gitee或者github把 shenyu

的代码克隆下来一起食用

首先,简单看一下源码的目录结构,图中标记也是基于笔者使用过disruptor经历的猜测

在这里插入图片描述

对于一个新的组件或者源码,首先我们先从宏观到微观去了解他

DisruptorProviderManage 生产者管理类,顾名思义,他可能是一个控制类

ctr+F12 看一下主要的成员和方法,发现方法挺少的,代码也比较简单,简单总结一下

*           简单总结一下该类:
*           (1)提供构造方法以及成员变量去配置 ringbuffer、消费者数量大小(不设置,提供默认ringbuffer 4096 *2 * 2   消费者数量: cpu核数 *2)
*           (2)提供获取生产者实列方法
*           (3)提供生产者初始化启动方法
*           (4)该类只维护了一个生产者实列

startup()方法代码稍稍多一点

    public void startup(final boolean isOrderly) {
        // (1)弄了一个线程池
        //  这个线程池可以支持有序  只有核心线程、阻塞队列基本无界 拒绝策略抛异常
        OrderlyExecutor executor = new OrderlyExecutor(isOrderly, consumerSize, consumerSize, 0, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(),
                DisruptorThreadFactory.create("shenyu_disruptor_consumer_", false), new ThreadPoolExecutor.AbortPolicy());
        int newConsumerSize = this.consumerSize;
        // (2)初始化EventFactory
        // 事件封装:把泛型data包装了一下
        EventFactory<DataEvent<T>> eventFactory;
        if (isOrderly) {
            // 2.1 如果有序,则设置消费者线程为1  eventFactory为OrderlyDisruptorEventFactory
            newConsumerSize = 1;
            // 有序事件工厂  生产 OrderlyDataEvent(DataEvent的子类) 多了一个hash属性
            eventFactory = new OrderlyDisruptorEventFactory<>();
        } else {
            // 2.2 无序 eventFactory为DisruptorEventFactory
            // 无序事件工厂
            eventFactory = new DisruptorEventFactory<>();
        }
        // (3) 初始化 disruptor实列
        Disruptor<DataEvent<T>> disruptor = new Disruptor<>(eventFactory,
                size, // buffer大小
                DisruptorThreadFactory.create("shenyu_disruptor_provider_" + consumerFactory.fixName(), false),
                ProducerType.MULTI, // 采用多生产者
                new BlockingWaitStrategy()); // 采用阻塞策略
        // (4) 初始化消费者队列  (塞了一个可支持排序的多线程线程池和consumerFactory进去)
        // QueueConsumer封装了业务逻辑   主要将数据委托给了executor线程池执行 具体的业务逻辑封装在QueueConsumer子类的run方法里,大概是做注册(URI、API、METADATA)
        // 所以shenyu 使用disruptor主要的场景为:使用其多生产者多消费者模式 做各种客户端、服务端注册请求的削峰、缓存、分发(最主要还是一个分发作用,并没有在队列线程里执行业务逻辑)
        @SuppressWarnings("all")
        QueueConsumer<T>[] consumers = new QueueConsumer[newConsumerSize];
        for (int i = 0; i < newConsumerSize; i++) {
            consumers[i] = new QueueConsumer<>(executor, consumerFactory);
        }
        // (5) disruptor必备流程 塞值
        disruptor.handleEventsWithWorkerPool(consumers);
        disruptor.setDefaultExceptionHandler(new IgnoreExceptionHandler());
        disruptor.start();
        // (6) 拿到ringBuffer 然后封装成DisruptorProvider实列
        RingBuffer<DataEvent<T>> ringBuffer = disruptor.getRingBuffer();
        provider = new DisruptorProvider<>(ringBuffer, disruptor, isOrderly);
    }

熟悉disruptor的小伙伴,应该了解以上几个步骤是使用disruptor的必要步骤

第(6)步,封装了一个DisruptorProvider实列,猜测这个对象应该是给生产者用的

接下来我们学习一下,优秀的开源组件如何优雅的封装DisruptorProvider

DisruptorProvider 类源码比较简单,简单小结一下

*           小结:简单来说就是给生产者用的
*           (1)提供2种往ringbuffer放数据的方法:有序(多传一个hash)、无序
*           (2) 提供destory销毁的方法

消费者:QueueConsumer

QueueConsumer 的onEvent方法是具体的消费逻辑,我们简单看一下源码:

    public void onEvent(final DataEvent<T> t) {
        if (Objects.nonNull(t)) {
            ThreadPoolExecutor executor = orderly(t);// 获取线程池
            QueueConsumerExecutor<T> queueConsumerExecutor = factory.create(); // 消费者队列执行器
            queueConsumerExecutor.setData(t.getData()); // 把DataEvent的data塞给了queueConsumerExecutor  QueueConsumerExecutor实现了Runnable接口
            // help gc
            t.setData(null);
            executor.execute(queueConsumerExecutor);// 然后把queueConsumerExecutor放到线程池执行  QueueConsumerExecutor的具体实现类封装了业务逻辑
        }
    }

很明显,shenyu在使用disruptor的时候并没有在消费者线程里执行具体的业务逻辑,而是把业务逻辑委托给了disruptor构造时的线程池,具体的业务逻辑主要封装在QueueConsumerExecutor类的run方法(实现了Runnable接口,这个就不多说了)

后面又跟了一下QueueConsumerExecutor的2个子类的run方法,猜测大概是做client、server注册(URI、API、METADATA)到网关吧,等后面用过shenyu才探究吧

二、回答最开始提出的4个问题

看到这里,我相信大概能回答前面提出的问题了,“shenyu 使用disruptor的场景是什么?”

  • shenyu 使用disruptor的场景:
使用其多生产者多消费者模式 做各种客户端、服务端注册请求的削峰、缓存、分发(最主要还是一个分发作用,并没有在队列线程里执行业务逻辑,而是委托给了另外的线程池执行各种方式注册逻辑)
所以简单来说,shenyu 使用disruptor主要看重了它的高并发性能,利用其做一个多生产者多消费者场景下的削峰和分发
  • shenyu 是如何使用disruptor

关于这个问题,相信不用解释了,源码其实写的也比较清除了,笔者参考其中的使用方式,比如封装DisruptorProvider 更优雅的供生产方使用

  • shenyu 对disruptor 做了其他的扩展么

暂时未发现

  • shenyu 为什么使用disruptor 而不使用其他的内存队列?

解释这个问题的话,就比较麻烦了,需要对disruptor 的源码有一个清晰的认识

简单总结3个点:破除伪造共享、无锁编程、环形队列 (这个百度一搜索一堆)

一句话来说,就是生产者消费者模式下的高并发框架

笔者因为参与公司项目的优化,其实也研究了disruptor 的源码,等后面有时间梳理一下,以上对于问题的回答仅是笔者的个人思考,仅供参考,如果当前的你也感兴趣的话,可以评论你的想法!

三、总结一下收获和思考

(1)发现了disruptor更优雅的封装方式(中间件中抄代码 杠杠的爽)

(2)拓宽了自己disruptor 的应用场景认识:disruptor 在shenyu中主要负责注册请求的中转,起到一个可以处理高并发的作用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值