disruptor 无锁高效队列的使用

269 阅读1分钟

disruptor 无锁高效队列的使用

前言

使用队列在系统各阶段之间传递数据会引入延迟,因此我们重点优化该领域。Disruptor 是我们研究和测试的结果。我们发现 CPU 级别的缓存未命中以及需要内核仲裁的锁都非常昂贵,因此我们创建了一个对其运行的硬件具有“机械同情”的框架,并且该框架是无锁的。

官网: lmax-exchange.github.io/disruptor/

该框架架构图式:

楷模

简单阐述:

就是经典的生产者-消费者模型,在消息到的事件通知到绑定事件通知的接收者业务代码,去处理消息;

号称它的性能能达到每秒600百万,也是很多优秀开源框架的首选 消息消费模型的框架,目前Apache Storm、Camel、Log4j2在内的很多知名项目都在使用它;

简单使用

pom.xml

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.4.2</version>
</dependency>
//消息体
@Data
public class EventPaymentMessage {

    private BlockingQueue<PaymentProductMessage> paymentProductMessageQueue;
}

@Data
@ToString
public class PaymentProductMessage {


    /**
     * 消息id
     */
    private  String msgId;


    /**
     * 流水号
     */
    private Long flowNo;


    /**
     * 支付类型
     */
    private Integer payTypeType;


    /**
     *  期待执行时间消息创建时间
     */
    private Long expireTime;
}

// 消息事件工厂
public class OrderEventFactory implements EventFactory<EventPaymentMessage> {


    @Override
    public EventPaymentMessage newInstance() {
        return new EventPaymentMessage();
    }
}
//消息生产者
@Slf4j
public class OrderEventProducer {

   //发布事件的buffer
    private final RingBuffer<EventPaymentMessage> ringBuffer ;


    public  OrderEventProducer(RingBuffer<EventPaymentMessage> ringBuffer){
        this.ringBuffer = ringBuffer;
    }



    //调用生产消息体
    public void onData(BlockingQueue<PaymentProductMessage> paymentProductMessageQueue){
        ArrayBlockingQueue<PaymentProductMessage> arrayBlockingQueue = new ArrayBlockingQueue<>(paymentProductMessageQueue.size());
        for (PaymentProductMessage paymentProductMessage : paymentProductMessageQueue) {
            try {
                arrayBlockingQueue.put(paymentProductMessage);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        paymentProductMessageQueue=null;
        //获取下个消息槽
        long sequence = ringBuffer.next();
        try {
            //获取当前槽位消息 就是前面的EventFactory#newInstance方法生成新的消息
            EventPaymentMessage eventPaymentMessage = ringBuffer.get(sequence);            eventPaymentMessage.setPaymentProductMessageQueue(arrayBlockingQueue);
        }finally {
            //发布当前槽位下的消息
            ringBuffer.publish(sequence);
        }
    }
@PostConstruct
private void init() {
    //构建生产者的槽位大小和消息体
    ringBuffer = RingBuffer.createSingleProducer(new OrderEventFactory(), BUFFER_SIZE);
    //自定义的线程池用于生产者
    ThreadPoolExecutor ringBufferPool = ThreadPoolConfig.RING_BUFFER_POOL;
    //消费者
    consumerEventHandles = new MultiConsumerEventHandle[CONSUMER_NUM];
   
    //构建工作池
    WorkerPool<EventPaymentMessage> workerPool = new WorkerPool<>(ringBuffer, ringBuffer.newBarrier(), new IgnoreExceptionHandler(), consumerEventHandles);
    ringBuffer.addGatingSequences(workerPool.getWorkerSequences());
    //工作在那个线程池
    workerPool.start(ringBufferPool);
    //生产者指定
    producer = new OrderEventProducer(ringBuffer);
}

//生产者发送消息即可
log.info("生产者生成的消息为===>[{}]", paymentProductMessage);
producer.onData(nowDoQueue);
//消费者实现该类 消息下发到该方法
public interface WorkHandler<T>
{
    /**
     * Callback to indicate a unit of work needs to be processed.
     *
     * @param event published to the {@link RingBuffer}
     * @throws Exception if the {@link WorkHandler} would like the exception handled further up the chain.
     */
    void onEvent(T event) throws Exception;
}