Disruptor

介绍

其实是来源于一个算法,解决高并发下队列锁的问题,完全运行在内存中

  • 相对于java的队列,它是一个无锁的有界队列

  • LMAX Disruptor是一个高性能的线程间消息传递库。

  • Disruptor是一个高性能的异步处理框架

  • 目前最快的消息框架(轻量的JMS),也可以认为是一个观察者模式的实现,或者事件监听模式的实现。

  • 一种高效的"生产者-消费者"模型

使用场景

  • PCP(生产者-消费者问题)

实战

  1. new Event类 , 其实是用来包装数据(事件)的

  2. EventFactory ,newInstance()

  3. 消费者:new EventHandler()

  4. ThreadFactory线程工厂

  5. new Disruptor (

    EventFactory,

    ringbuffersize,(环形数组大小,2的N次方)

    threadFactory,

    ProducerType enum(是否多个生产者),

    WaitStrategy :等待策略类 )

    • Disruptor的入口
    • 封装了RingBuffer ,消费者集合引用(ConsumerRepository)
  6. 存储核心:RingBuffer 环行数组,通过Disruptor实例拿到它,它是Disruptor类中的一个数组

    • RingBuffer 内部有一个序列生成器接口(Sequencer)
  7. 消费者注册监听 Disruptor.handleEventWith(handler)

    • 实现 onEvent()
  8. disruptor.start();

  9. Disruptor.getRingBuffer();

  10. new Producer(ringBuffer) ; producer.onData(ringBuffer);//ringBuffer表示容器

    //producer
    //构造初始化RingBuffer容器
    public MyEventProducer(RingBuffer<MyEvent> ringBuffer){
        this.ringBuffer = ringBuffer;
    }
    
    try{
        //1.获取下一个序号
        long sequence = ringBuffer.next();
        //2.从容器中取出空的事件队列
        myEvent = ringBuffer.get(sequence);
        //3.生产数据
        myEvent.setxxx(data); 
    }finally{
        //4.发布事件
    	ringBuffer.publish(sequence);
    }
    
    

核心组件

  • Sequencer 序列生成器

    • 包括 单生产者,多生产者实现类。还维护了生产者和消费者序列冲突时的等待策略
  • Sequence 序列对象 组件处理的序号 引用(索引,序列) 底层实现是 AtomicLong

    • 生产者和消费者都维护了各自的Sequence ,都指向了ringBuffer内的Object[]
    • 这个序号是一直递增的,long是一个很大的值2的63次方-1 ,亿的平方级别的,即使是100WQPS也得用30年
    • 序号的初始值是 -1
  • RingBuffer 一个首尾相接的环

    • 用于上下文(线程)间传递数据的buffer

    • ringbuffer拥有一个序号Sequencer,这个序号指向数组中下一个可用元素

  • WaitStrategy 没有可消费的事件时,没有可生产的地方时

    • 主要针对消费者线程

    • Blocking

      • 性能比较低效
      • 对cpu消耗小,更好的一致性
      • 内部维护了一个重入锁和Condition
    • Yielding

      • 性能最高
    • Sleeping

      • 性能和Blocking差不多,也是一种无锁的方式

      • 对生产者线程影响最小,适合用于异步日志类似的场景

      • Log4j2 就用了Disruptor这个框架

  • Event 只是一个定义,没有具体的Event类

  • Producer 只是泛指调用 Disruptor 发布事件的用户代码,Disruptor 没有定义特定接口或类型需要使用者自己定义

  • Sequence Barrier

生产消费流程

  • 单生产者-单消费者
  • MultiProducer - MultiConsumer
    • ProducerType.MULTI
    • EventHandler 变成WorkHandler
    • WorkPool 多消费者工作池

优缺点

  • 环形数组结构
    • 避免了垃圾回收,直接覆盖
    • 数组对处理器的缓存机制更加友好
    • 数组元素定位 (通过位运算加速定位速度)
      • 序列号%数组大小 = index ,其实是通过位运算做的不是上面的取模算法
      • UNSAFE.getObject(entries,REF_ARRAY_BASE + ( (sequence & indexMask) << REF_ELEMENT_SHIFT)));
    • 初始化了大小 2的n次方,不需要扩容
  • 无锁设计
    • 每个生产者或者消费者线程,会先申请可以操作的元素位置,然后直接在该位置写入或者读取数据
  • 大公司实践
    • 美团网 ,得到了大数据的验证
  • Disruptor 是基于单JVM的无锁队列技术 ,不是分布式下的
posted @ 2021-06-29 23:34  沉梦匠心  阅读(175)  评论(0)    收藏  举报