Disruptor并发框架 (之)核心概念场景分析

原文链接:https://www.cnblogs.com/jiangjun-x/p/8111513.html

超级赞的原文链接:https://www.jianshu.com/p/f4021e8141ad

核心术语

  • RingBuffer(容器): 被看作Disruptor最主要的组件,然而从3.0开始RingBuffer仅仅负责存储和更新在Disruptor中流通的数据。对一些特殊的使用场景能够被用户(使用其他数据结构)完全替代。
  • Sequence(槽位置): Disruptor使用Sequence来表示一个特殊组件处理的序号。和Disruptor一样,每个消费者(EventProcessor)都维持着一个Sequence。大部分的并发代码依赖这些Sequence值的运转,因此Sequence支持多种当前为AtomicLong类的特性。
  • Sequencer: 这是Disruptor真正的核心。实现了这个接口的两种生产者(单生产者和多生产者)均实现了所有的并发算法,为了在生产者和消费者之间进行准确快速的数据传递。
  • SequenceBarrier(生产消费者冲突问题解决): 由Sequencer生成,并且包含了已经发布的Sequence的引用,这些的Sequence源于Sequencer和一些独立的消费者的Sequence。它包含了决定是否有供消费者来消费的Event的逻辑。
  • WaitStrategy:决定一个消费者将如何等待生产者将Event置入Disruptor。
  • Event:从生产者到消费者过程中所处理的数据单元。Disruptor中没有代码表示Event,因为它完全是由用户定义的。
  • EventProcessor(生产线程):主要事件循环,处理Disruptor中的Event,并且拥有消费者的Sequence。它有一个实现类是BatchEventProcessor,包含了event loop有效的实现,并且将回调到一个EventHandler接口的实现对象。
  • EventHandler(消费者):由用户实现并且代表了Disruptor中的一个消费者的接口。
  • Producer:由用户实现,它调用RingBuffer来插入事件(Event),在Disruptor中没有相应的实现代码,由用户实现。
  • WorkProcessor:确保每个sequence只被一个processor消费,在同一个WorkPool中的处理多个WorkProcessor不会消费同样的sequence。

EventProcessor接口继承了Runnable接口,主要有两种实现:单线程批量处理BatchEventProcessor和多线程处理WorkProcessor

在使用Disruptor帮助类构建消费者时,使用handleEventsWith方法传入多个EventHandler,内部使用多个BatchEventProcessor关联多个线程执行。这种情况类似JMS中的发布订阅模式,同一事件会被多个消费者并行消费。适用于同一事件触发多种操作。

而使用Disruptor的handleEventsWithWorkerPool传入多个WorkHandler时,内部使用多个WorkProcessor关联多个线程执行。这种情况类似JMS的点对点模式,同一事件会被一组消费者其中之一消费。适用于提升消费者并行处理能力。

  • WorkerPool:一个WorkProcessor池,其中WorkProcessor将消费Sequence,所以任务可以在实现WorkHandler接口的worker之间移交
  • LifecycleAware:当BatchEventProcessor启动和停止时,于实现这个接口用于接收通知,

调优:

调优主要有两种方法:单或多生产者和可选等待策略。

  • 单或多生产者

一个在concurrent系统提高性能的最好方式是单个Write的原则,这同样也适用于Disruptor,如果你在这种只有一个单线程的生产者发送Event的的Disruptor中,那么你能利用这个来获得额外的性能。

  • 选择等待策略

默认的Disruptor使用的等待策略是BlockingWaitStrategy(阻塞等待策略),阻塞等待策略内部使用的是典型的锁和Condition条件变量来处理线程唤醒,这是最慢的等待策略了,但是在CPU使用率上最保守而且能给予肯定的一致性行为。

休眠等待策略(SleepingWaitStrategy)

和BlockingWaitStrategy一样,为了保证CPU的使用率,不是通过一个简单的忙等待循环,而是使用一个叫LockSupport.parknanos(1)在循环中,在典型的Linux系统中将暂停60µs,这样显然是有优势的,生产者线程不需要增加计数器,也不需要信号条件。但是在生产者和消费者之间移动事件的平均延迟事件会更高。休眠等待策略在不需要低延迟的情况下效果最好,但是对生成线程的影响是很小的,一个常见的用例是异步日志记录。

退出等待策略(YieldingWaitStrategy)

退出等待策略是两个等待策略中可以被用到低延迟的策略,消耗CPU来提高实时性。YieldingWaitStrategy会忙等待Sequence增加为适当的值。在循环体中Thread.yield()将会允许其他线程运行,当需要非常高的性能和事件处理线程的的数量小于逻辑核心的总数时,这是推荐的等待策略,启用了超线程。

自旋等待策略(BusySpinWaitStrategy)

自旋等待策略是常见的等待策略,但是对部署环境也有很高的要求。自旋等待策略应该只能被用在处理线程数小于实际核数的时候。另外,超线程应该被关闭。

从RingBuffer清除对象

当通过Disruptor传递数据的时候,对象的存活寿命可能比预期的要长,为了避免这种情况发生,可能需要在处理完事件以后清除它。如果只有一个单事件处理程序,那么在一个处理程序中清除data就够了。如果有一个事件处理链,那么需要在链结束的地方利用特殊的处理程序来清除对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值