由于RingBuffer预先分配给定类型的对象,如何使用单个环形缓冲区来处理各种不同类型的消息?
您无法创建要插入ringBuffer的新对象实例,这会破坏预先分配的目的.
因此,您可以在异步消息传递模式中拥有3条消息:
所以我的问题是你是如何将Disruptor模式用于现实世界的消息系统?
谢谢
链接:http: //code.google.com/p/disruptor-net/wiki/CodeExamples
我正在尝试学习如何使用Disruptor.NET消息框架,我找不到任何实际的例子.有很多文章都有关于它是如何工作的图片,但我找不到任何实际的内容,并向您展示如何实现这些方法.什么是一个例子?
我希望我能得到最简单的示例代码,它将展示如何使用LMAX disruptor(http://code.google.com/p/disruptor/).
不幸的是,每一段代码都已过时.有人知道吗,我在哪里可以找到小而且最新的howto(最好没有DSL)?
我的系统有两种不同类型的消息 - 类型A和B.每条消息都有不同的结构 - 类型A包含int成员,类型B包含双成员.我的系统需要将两种类型的消息传递给众多业务逻辑线程.减少延迟非常重要,因此我正在研究使用Disruptor以机械同情的方式将消息从主线程传递到业务逻辑线程.
我的问题是破坏者只接受环形缓冲区中的一种类型的对象.这是有道理的,因为破坏程序在环形缓冲区中预先分配对象.但是,它也很难通过Disruptor将两种不同类型的消息传递给我的业务逻辑线程.据我所知,我有四种选择:
配置破坏程序以使用包含固定大小字节数组的对象(如何使用Disruptor(Disruptor Pattern)来构建真实的消息系统?).在这种情况下,主线程必须在将消息发布到破坏程序之前将消息编码为字节数组,并且每个业务逻辑线程必须在接收时将字节数组解码回对象.这种设置的缺点是业务逻辑线程并不真正从破坏者共享内存 - 而是从破坏者提供的字节数组创建新对象(从而创建垃圾).这种设置的好处是所有业务逻辑线程都可以从同一个破坏者中读取多种不同类型的消息.
将破坏程序配置为使用单一类型的对象,但创建多个破坏程序,每个对象类型一个.在上面的例子中,将有两个单独的破坏程序 - 一个用于类型A的对象,另一个用于类型B的对象.此设置的优点是主线程不必将对象编码为字节数组并且business less逻辑线程可以共享与disruptor中使用的相同的对象(没有创建垃圾).这种设置的缺点是,不知何故,每个业务逻辑线程都必须订阅来自多个破坏者的消息.
配置破坏程序使用单一类型的"超级"对象,该对象包含消息A和B的所有字段.这非常违反OO样式,但允许在选项#1和#2之间进行折衷.
配置破坏程序以使用对象引用.但是,在这种情况下,我失去了对象预分配和内存排序的性能优势.
你对这种情况有什么建议?我认为选项#2是最干净的解决方案,但我不知道消费者是否或如何从技术上订阅来自多个破坏者的消息.如果有人可以提供如何实施选项#2的示例,那将非常感谢!
有LMAX的Disruptor模式的开源Java和.NET版本,如视频LMAX中所述 - 如何在不到1ms的延迟时间内执行100K TPS.这里有更多关于Disruptor模式信息的链接.
是否有人知道C++ 的Disruptor模式的端口,是完成还是测试?
更新
以下是否正确?
(当涉及多个生产者(即CAS操作)时,破坏者模式是否仍然比其他无锁多生产者多消费者队列(例如来自提升)快得多?)
我的情况详细:
处理条目可以产生几个新条目,这些条目也必须最终处理.性能具有最高优先级,以FIFO顺序处理的条目具有第二优先级.
在当前实现中,每个线程使用本地FIFO,在其中添加新条目.空闲线程从其他线程的本地FIFO中窃取工作.线程处理之间的依赖关系使用无锁,机械同情的哈希表(写入时的CAS,具有桶粒度)来解决.这导致相当低的争用,但FIFO顺序有时会被破坏.
使用干扰模式可以保证FIFO顺序.但是不会将条目分配到线程上导致更高的争用(例如,读取游标上的CAS),而不是工作窃取的本地FIFO(每个线程的吞吐量大致相同)?
我发现的参考文献
关于破坏者的标准技术论文(第5章+6)中的性能测试不包括不相交的工作分布.
https://groups.google.com/forum/?fromgroups=#!topic/lmax-disruptor/tt3wQthBYd0是我在disruptor +偷窃工作中发现的唯一参考.它声明如果存在任何共享状态,每个线程的队列会显着减慢,但不会详细说明或解释原因.我怀疑这句话适用于我的情况:
concurrency concurrent-programming disruptor-pattern work-stealing
我正在使用Disruptor框架对某些数据执行快速Reed-Solomon纠错.这是我的设置:
RS Decoder 1
/ \
Producer- ... - Consumer
\ /
RS Decoder 8
Run Code Online (Sandbox Code Playgroud)
在disruptor DSL术语中,设置如下所示:
RsFrameEventHandler[] rsWorkers = new RsFrameEventHandler[numRsWorkers];
for (int i = 0; i < numRsWorkers; i++) {
rsWorkers[i] = new RsFrameEventHandler(numRsWorkers, i);
}
disruptor.handleEventsWith(rsWorkers)
.then(writerHandler);
Run Code Online (Sandbox Code Playgroud)
当我没有磁盘输出消费者(没有.then(writerHandler)
部分)时,测量的吞吐量是80 M/s,一旦我添加消费者,即使它写入/dev/null
,甚至不写,但它被声明为依赖消费者,性能下降到50-65 M/s.
我已经使用Oracle Mission Control对其进行了分析,这就是CPU使用率图表显示的内容:
没有额外的消费者:
另外一个消费者:
图中的灰色部分是什么?它来自何处?我想它与线程同步有关,但我在Mission Control中找不到任何其他统计信息来指示任何此类延迟或争用.
是否有一些示例代码用于从标准LinkedBlockingQueue迁移到LMAX的Disruptor架构?我有一个事件处理应用程序(单个生产者,多个消费者),可能会从更改中受益.
当我的目标是最大化吞吐量而不是最小化延迟时,它是否有意义?
LMAX Disruptor通常使用以下方法实现:
在此示例中,Replicator负责将输入事件\命令复制到从属节点.复制一组节点需要我们应用一致性算法,以防我们希望系统在出现网络故障,主故障和从站故障时可用.
我正在考虑将RAFT一致性算法应用于此问题.一个观察结果是:"RAFT要求在复制期间将输入事件\命令存储到磁盘(持久存储)"(参考此链接)
这种观察实质上意味着我们无法执行内存中复制.因此,似乎我们可能必须结合复制器和记者的功能才能成功地将RAFT算法应用于LMAX.
有两种方法可以做到这一点:
选项1:使用复制日志作为输入事件队列
我认为这个选项的缺点与我们做一个额外的数据复制步骤(接收器到事件队列而不是环形缓冲区)这一事实有关.
选项2:使用Replicator将输入事件\命令推送到从属的输入日志文件
我想知道是否有其他解决方案来设计Replicator?人们用于复制器的不同设计选择有哪些?特别是任何可以支持内存复制的设计?
java ×4
concurrency ×3
performance ×2
actor ×1
c# ×1
c++ ×1
latency ×1
lmax ×1
messaging ×1
queue ×1
raft ×1
replication ×1