繁体   English   中英

如何使用disruptor实现自定义actor邮箱?

[英]How to implement custom actor mailbox using disruptor?

我有一些LMAX Disruptor的经验,我真的想用disruptor实现一个自定义actor邮箱。

有没有指导方针? 它甚至可能吗? Akka的演员邮箱有哪些限制?

正如它在这里所说你只需要实现一些方法 - 当然你应该使用指向环形缓冲区的指针直接写/读消息。 你还应该记住:

  • 破坏者通常预先分配大量内存,因此每个actor使用一个破坏者是个坏主意,你可以使用一个路由器actor(内部有disruptor)和BalancingPool

  • 如果你想要不同的消息类型消费,单独的消费者进行日记,修复等 - 你应该将不同的RingBufferPointer(类似smthng)实例作为参数传递给你的邮箱(具有相同的日记起始值,不同的起始值为不同的消息类型),但仍然使用一个Disruptor。 所以不同的邮箱会引用一个破坏者。

  • 你将失去对消息创建,提取等的低级控制,因此默认情况下不进行批量分配。

  • 你也可以使用ring中的历史来恢复失败的actor的状态(在preRestart或supervisor中)。

LMAX说的是什么:

它以与传统方法不同的方式工作,因此您使用它的方式与您习惯的方法略有不同。 例如,将模式应用于您的系统并不像使用魔术环缓冲区替换所有队列那么简单。 我们有代码示例来指导您,越来越多的博客和文章概述了它的工作原理,技术论文按照您的预期进行了详细介绍,性能测试给出了如何使用Disruptor的示例http://mechanitis.blogspot.com/2011/06/dissecting-disruptor-whats-so-special.html

这里有一个简短的Queues / Disruptors / Actors比较

在伪scala代码中,它将类似于:

object MyUnboundedMailbox {
  val buffer = new RingBuffer()

  class MyMessageQueue(val startPointer: Pointer, readerPointer: Pointer, writerPointer: Pointer) extends MessageQueue {

    // these should be implemented; queue used as example
    def enqueue(receiver: ActorRef, handle: Envelope): Unit = {
      writerPointer.allocate(() => handle) //allocate one element and set, if you want different message types - you should allocate big amount of data before and block when it ends (to not interfere with another messages), so it has to be bounded queue then  

    }
    def dequeue(): Envelope = readerPointer.poll()
    def numberOfMessages: Int = writerPointer - readerPointer //should be synchronized
    def hasMessages: Boolean = readerPointer == writerPointer //should be synchronized
    def cleanUp(owner: ActorRef, deadLetters: MessageQueue) { }
  }

  trait MyUnboundedMessageQueueSemantics 

}

class MyUnboundedMailbox(settings: ActorSystem.Settings, config: Config) extends MailboxType
  with ProducesMessageQueue[MyUnboundedMailbox.MyMessageQueue] {

  import MyUnboundedMailbox._
  final override def create(owner: Option[ActorRef],
                            system: Option[ActorSystem]): MessageQueue = {

    val pointer = ring.newPointer
    val read = pointer.copy
    val write = pointer.copy
    new MyMessageQueue(pointer, read, write) 
  }
    // you may use another strategy here based on owner (you can access name and path here), 
    // so for example may allocate same pointers for same prefixes in the name or path 
}

您可以使用未更改的MyMessageQueue.startPointer在故障恢复期间访问消息日志(您也可以查看akka的Event Sourcing进行类比)。

使用UnboundedQueue方法并不保证此处的消息传递,因为如果响铃“结束”,可能会使用新版本覆盖旧的未传递消息,因此您可能需要BoundedQueue,就像这里一样。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM