小编典典

LMAX 的破坏者模式如何运作?

all

我试图理解破坏者模式。我看过 InfoQ
的视频并尝试阅读他们的论文。我知道涉及到一个环形缓冲区,它被初始化为一个非常大的数组以利用缓存局部性,消除新内存的分配。

听起来好像有一个或多个原子整数可以跟踪位置。每个“事件”似乎都有一个唯一的 id,它在环中的位置是通过找到它相对于环的大小等的模数来找到的。

不幸的是,我对它的工作原理没有直观的感觉。我做过很多交易应用,研究过actor模型,研究过SEDA等。

在他们的演讲中,他们提到这种模式基本上就是路由器的工作方式。但是我也没有找到关于路由器如何工作的任何好的描述。

是否有一些好的指示可以更好地解释?


阅读 67

收藏
2022-06-24

共1个答案

小编典典

Google Code
项目确实参考了有关实现环形缓冲区的技术论文,但是对于想要了解它如何工作的人来说,它有点枯燥、学术和艰难。然而,有一些博客文章已经开始以更易读的方式解释内部结构。有对作为中断器模式核心的环形缓冲区的解释,对消费者障碍(与从中断器读取相关的部分)的描述以及有关处理可用的多个生产者的一些信息

Disruptor 最简单的描述是:它是一种在线程之间以最有效的方式发送消息的方式。它可以用作队列的替代方案,但它也与 SEDA 和 Actors
共享许多功能。

与队列相比:

Disruptor 提供了将消息传递到另一个线程的能力,如果需要,可以将其唤醒(类似于 BlockingQueue)。但是,有 3 个明显的区别。

  1. Disruptor 的用户通过扩展 Entry 类并提供工厂来进行预分配来定义消息的存储方式。这允许内存重用(复制)或条目可以包含对另一个对象的引用。
  2. 将消息放入 Disruptor 是一个两阶段的过程,首先在环形缓冲区中声明一个插槽,该插槽为用户提供可以填充适当数据的条目。然后必须提交条目,这种两阶段方法对于灵活使用上述内存是必要的。正是提交使消息对消费者线程可见。
  3. 消费者有责任跟踪已从环形缓冲区消费的消息。将此责任从环形缓冲区本身移开有助于减少写入争用的数量,因为每个线程都维护自己的计数器。

与演员相比

与大多数其他编程模型相比,Actor 模型更接近 Disruptor,尤其是当您使用提供的 BatchConsumer/BatchHandler
类时。这些类隐藏了维护使用的序列号的所有复杂性,并在发生重要事件时提供一组简单的回调。但是,有一些细微的差别。

  1. Disruptor 使用 1 线程 - 1 消费者模型,其中 Actor 使用 N:M 模型,即您可以拥有任意数量的 Actor,它们将分布在固定数量的线程上(通常每个核心 1 个)。
  2. BatchHandler 接口提供了一个额外的(并且非常重要的)回调onEndOfBatch()。这允许速度较慢的消费者,例如那些执行 I/O 以将事件批处理在一起以提高吞吐量的消费者。可以在其他 Actor 框架中进行批处理,但是由于几乎所有其他框架都不在批处理结束时提供回调,因此您需要使用超时来确定批处理结束,从而导致延迟很差。

与 SEDA 相比

LMAX 构建了 Disruptor 模式来替代基于 SEDA 的方法。

  1. 它比 SEDA 提供的主要改进是并行工作的能力。为此,Disruptor 支持将相同的消息(以相同的顺序)多播给多个消费者。这避免了流水线中对分叉阶段的需要。
  2. 我们还允许消费者等待其他消费者的结果,而不必在他们之间设置另一个排队阶段。消费者可以简单地查看它所依赖的消费者的序列号。这避免了管道中连接阶段的需要。

与内存屏障相比

另一种思考方式是将其视为结构化的、有序的内存屏障。生产者屏障形成写屏障,消费者屏障是读屏障。

2022-06-24