Disruptor 简介

  1. 总体介绍
    disruptor是LMAX 开源的一个无锁循环队列,队列内部采用数组实现,通过Sequence表示当前生产者可以提交元素的位置以及消费者消费的位置。Sequence可以理解成一个AtomicLong。生产者申请数据空间,并且将元素放入指定的空间中。消费者则从数组中取得相应的数据,进行消费.生产者角度来看,支持多生产者,单生产者.从消费者角度来看,支持单消费者,也支持多消费者,同时还支持具体依赖关系的不同消费者的消费.
  2. 模块分析
    1. Sequence: 序列号,相当于AtomicLong,有set,get,cas方法,其内部进行了缓存行填充,避免了伪共享问题。每一个生产者以及消费者内部都会维护一个Sequence,表明当前正在消费的或者正在生产的索引值
    2. Sequencer: Disruptor中一个核心的类,该类有两个实现(多生产者,单生产者),主要功能是保证正确的完成生产者与消费者之间的数据传递
    3. RingBuffer:在Sequencer 的基础上,加入了数据元素的存储,会对数组进行预填充,大小必须为2的n次方。
    4. Disruptor: 协调类,入口类,根据不同的参数,生成不同的生产者,消费者以及他们之间的协调关系。
    5. WaitStrategy:等待策略,当生产者没有空间可以存放数据或者消息者没有数据可以消费时,以何种方式进行等等,有忙等待,sleep等待等共8种等待策略.
    6. Barrier:消费者之间以及消费者与生产者之间协调的基础,其内部是其依赖的生产者及消息者的Sequence,比如A消费者依赖于生产者,那么Barrier中的核心内容是生产者的Sequence,如果A依赖于B,B依赖于生产者,那么A的Barrier中保存的就是B的Sequence,如果A依赖于B及C。那么A中保存的就是B以及C的Sequenbce。通过Barrier可以获得接下来可以处理的数据位置
    7. EventFactory: 生成Event的工厂,通过该工厂方法填充RingBuffer
    8. EventProcessor: 是一个Runnable, 其run方法就是消费者的消费过程
    9. EventHandler处理,如果遇到异常,同时处理异常的过程.主要有两种实现,一是BatchEventProcessor,批量获取需要处理的元素并处理, 二是WorkProcessor,用于多个消费者情况.
    10. ExceptionHandler: 异常处理器,如果处理运行中遇到的异常
    11. 其它说明
      1. gatingSequence:是个Sequence的数组,保存着生产者直接依赖的最慢的消费者的Sequence。
  3. 代码示例

    1. 先上公共代码

      // 事件处理器
      static class EventHandler implements com.lmax.disruptor.EventHandler{
          String prefix;
          public EventHandler(String prefix){
              this.prefix = prefix;
          }
          @Override
          public void onEvent(LongWrapper event, long sequence, boolean endOfBatch) throws Exception {
              System.out.println(prefix + event.getData() );
          }
      }
      
      
      // EventFactory
      static class LongEventEventFactory implements com.lmax.disruptor.EventFactory{
          @Override
          public LongWrapper newInstance() {
              return new LongWrapper();
          }
      }
      
      // 具体的Event
      static class LongWrapper{
          private Long data;
      
          public Long getData() {
              return data;
          }
      
          public LongWrapper setData(Long data) {
              this.data = data;
              return this;
          }
      }
      
      // 具体的生产者
      static class Producer implements Runnable{
          RingBuffer ringBuffer = null;
      
          public Producer(RingBuffer ringBuffer) {
              this.ringBuffer = ringBuffer;
          }
      
          AtomicLong atomicLong = new AtomicLong(0);
          @Override
          public void run() {
              while(true){
                  long next = ringBuffer.next();
                  try{
                      LongWrapper aLong = ringBuffer.get(next);
                      aLong.setData(atomicLong.addAndGet(1));
                      TimeUnit.MILLISECONDS.sleep(50);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  } finally {
                      ringBuffer.publish(next);
                  }
              }
          }
      }
    2. 生产者角度:单生产者与多生产者在创建的时候传不同的ProducerType值即可.默认情况下是多生产者.单生产者与多生产者内部的实现是不同的. 从代码角度来看,基本上不致,这专门上代码. 下面的所有case都是以多生产者case来的.

    3. 单消费者

      public static void main(String[] args) throws InterruptedException {
          Executor executor = Executors.newCachedThreadPool();
          final Disruptor longDisruptor = new Disruptor(new LongEventEventFactory(),512,executor);
          longDisruptor.handleEventsWith(new EventHandler("first handler"));
          longDisruptor.start();
          new Thread(new Producer(longDisruptor.getRingBuffer())).start();
          TimeUnit.HOURS.sleep(2);
      }
      
      // 结果如下
      first handler 1
      first handler 2
      first handler 3
      first handler 4
      first handler 5
      first handler 6
      .......
    4. 不具有依赖关系的消费者消费同一份数据

      public static void main(String[] args) throws InterruptedException {
          Executor executor = Executors.newCachedThreadPool();
          final Disruptor longDisruptor = new Disruptor(new LongEventEventFactory(),512,executor);
          longDisruptor.handleEventsWith(new EventHandler("first handler"));
          longDisruptor.start();
          new Thread(new Producer(longDisruptor.getRingBuffer())).start();
          TimeUnit.HOURS.sleep(2);
      }
      
      // 结果如下.可以看到 handler 1 与handler 2 不区分先后顺序, 因为生产者太慢.可以看到消费者每次基本上都同同消费1 ,同时消费2 
      first handler1
      second handler1
      first handler2
      second handler2
      first handler3
      second handler3
      first handler4
      second handler4
      second handler5
      first handler5
      .......
    5. 具有消费依赖关系的消费者消费同一份数据

      // handler 3 与handler1 与hadnler 2 没有任何关系.handler2 必须在handler1消费以后再消费
      public static void main(String[] args) throws InterruptedException {
          Executor executor = Executors.newCachedThreadPool();
          final Disruptor longDisruptor = new Disruptor(new LongEventEventFactory(),512,executor);
          EventHandler handler1 = new EventHandler("first handler");
          EventHandler handler2 = new EventHandler("second handler");
          EventHandler handler3 = new EventHandler("third handler");
          longDisruptor.handleEventsWith(handler1);
          longDisruptor.after(handler1).handleEventsWith(handler2);
          longDisruptor.handleEventsWith(handler3);
          longDisruptor.start();
          new Thread(new Producer(longDisruptor.getRingBuffer())).start();
          TimeUnit.HOURS.sleep(2);
      }
      
      // 结果如下.可以看到handler 3的顺序可能在handler 1的前面.也可能handler 2的后面.也可能在两者中间. 而handler 2 一定在handler 1 的后面
      first handler1
      second handler1
      third handler1
      third handler2
      first handler2
      second handler2
      third handler3
      first handler3
      second handler3
      first handler4
      second handler4
      third handler4
      first handler5
      second handler5
      first handler6
      second handler6
      third handler5
      .......
    6. 同一个元素只能被多个消费者中的某一个消费

      public static void main(String[] args) throws InterruptedException {
          Executor executor = Executors.newCachedThreadPool();
          final Disruptor longDisruptor = new Disruptor(new LongEventEventFactory(),512,executor);
          longDisruptor.handleEventsWithWorkerPool(
                  new WorkHandler() {
                      @Override
                      public void onEvent(LongWrapper event) throws Exception {
                          System.out.println("first handler" + event.getData());
                      }
                  },
                  new WorkHandler() {
                      @Override
                      public void onEvent(LongWrapper event) throws Exception {
                          System.out.println("second handler" + event.getData());
                      }
                  },
                  new WorkHandler() {
                      @Override
                      public void onEvent(LongWrapper event) throws Exception {
                          System.out.println("third handler" + event.getData());
                      }
                  });
          longDisruptor.start();
          new Thread(new Producer(longDisruptor.getRingBuffer())).start();
          TimeUnit.HOURS.sleep(2);
      }
      
      // 结果如下,可以看到同一个元素只能被某一个handler处理
      second handler1
      third handler2
      first handler3
      second handler4
      third handler5
      first handler6
      second handler7
      third handler8
      first handler9
      second handler10
      third handler11
      first handler12
      second handler13
      third handler14
      first handler15
      ......
    7. 总结及说明
      生产者支持多生者与单生产者.默认为多生产者.对于消费者,支持单消费者,支持多消费者,支持多消费者之间的依赖处理,支持多消费者处理同一份数据以及某一个数据只能被多消费者中间的某一个消费者处理.
      调用disruptor.start()方法后,consumer开始消费开始.每一个EventHandler或者WorkHandler总终都被线程池中的一个线程执行. 所以假如你有三个handler在执行,线程池中一定要有三个线程,当不传线程池的时候,会采用默认的线程池,默认的线程池就是新起一个线程,对于此处来讲,完全可以采用默认的线程线.

  4. 其它说明
    在前文中没有提到ExceptionHandler,如果没有给Disruptor设置异常处理器,那么假如消费者在处理任务的过程中.而默认的异常处理器会找印相应的日志后.再将异常抛出.从而导致消费者的线程死掉. RingBuffer被生产者填满,导致内存释放不掉.笔者在生产环境就遇到过由于消费者线程死掉导致不停的fucc gc的案例. 同时需要说明的是,为disruptor设置exceptionHandler 时,一定要先于调用其的handleEventsWith,handleEventsWithWorkerPool等方法. 否则无效.
  5. 参考文献
    1. http://blog.csdn.net/zhxdick/article/category/6121943
    2. http://ifeve.com/disruptor/
    3. https://github.com/LMAX-Exchange/disruptor/wiki/Getting-Started
    4. https://github.com/LMAX-Exchange/disruptor/wiki/Introduction
    5. http://www.360doc.com/content/15/0330/20/11962419_459384128.shtml

你可能感兴趣的:(技术文档,源码分析)