Scala Akka框架支持查找重复消息

Scala Akka框架支持查找重复消息,scala,akka,Scala,Akka,我正试图用Akka和Scala构建一个高性能的分布式系统 如果一条请求昂贵(且无副作用)计算的消息到达,并且之前已经请求过完全相同的计算,我希望避免再次计算结果。如果之前请求的计算已经完成,并且结果可用,我可以缓存它并重新使用它 然而,可以请求重复计算的时间窗口可以任意小。e、 出于所有实际目的,我可以在同一时刻收到一千或一百万条请求同样昂贵计算的消息 有一种叫做Gigaspaces的商业产品,据说可以处理这种情况 然而,目前在Akka似乎没有处理重复工作请求的框架支持。鉴于Akka框架已经可以

我正试图用Akka和Scala构建一个高性能的分布式系统

如果一条请求昂贵(且无副作用)计算的消息到达,并且之前已经请求过完全相同的计算,我希望避免再次计算结果。如果之前请求的计算已经完成,并且结果可用,我可以缓存它并重新使用它

然而,可以请求重复计算的时间窗口可以任意小。e、 出于所有实际目的,我可以在同一时刻收到一千或一百万条请求同样昂贵计算的消息

有一种叫做Gigaspaces的商业产品,据说可以处理这种情况

然而,目前在Akka似乎没有处理重复工作请求的框架支持。鉴于Akka框架已经可以访问通过框架路由的所有消息,因此框架解决方案在这里似乎很有意义

以下是我对Akka框架的建议: 1.创建一个trait,以指示要遵循以下缓存方法的消息类型(例如,“ExpensiveComputation”或类似内容)。 2.Smartly(哈希等)在用户可配置的时间窗口内识别(相同或不同)参与者收到的相同消息。其他选项:选择用于此目的的最大内存缓冲区大小(如LRU)替换等。Akka还可以选择仅缓存处理成本高昂的消息的结果;处理时间很短的消息可以在需要时重新处理;无需浪费宝贵的缓冲空间来缓存它们及其结果。 3.当识别出相同的消息(在该时间窗口内接收,可能是“在同一时刻”)时,避免不必要的重复计算。框架将自动完成这项工作,从本质上讲,新参与者永远不会接收到重复的消息进行处理;它们将悄悄消失,并且处理一次的结果(无论该计算是过去已经完成的,还是当时正在进行的)将发送给所有适当的接收者(如果已经可用,则立即发送,如果不可用,则在计算完成后发送)。请注意,即使“回复”字段不同,只要它们所表示的语义/计算在所有其他方面都相同,消息也应被视为相同的。还请注意,计算应该是纯功能性的,即没有副作用,因为建议的缓存优化可以工作,并且根本不会更改程序语义

如果我的建议与阿克卡的做事方式不一致,和/或如果你认为这是一个非常糟糕的想法,请让我知道

谢谢,
非常棒,Scala

你所要求的不是依赖于Akka框架,而是你如何构建你的参与者和信息。首先,通过equals/hashCode方法确保消息是不可变的,并且具有适当定义的标识。Case类免费提供这两种方法,但是如果消息中嵌入了actorRefs用于回复,则必须重写identity方法。case类参数还应该递归地具有相同的属性(不可变和正确的标识)

其次,您需要弄清楚参与者将如何处理存储和识别当前/过去的计算。最简单的方法是将请求唯一地映射到参与者。这样,该参与者,而且只有该参与者才会处理该特定请求。只要有一组固定的参与者和请求的hashCode,就可以很容易地做到这一点如果参与者集受到监督,则奖励点数,其中主管管理负载平衡/映射并更换失败的参与者(Akka使这一部分变得容易)


最后,参与者本身可以根据您描述的标准维护响应缓存行为。在参与者的上下文中,一切都是线程安全的,因此由请求本身设置密钥的LRU缓存(请记住良好的标识属性)对于您想要的任何类型的行为都是很容易的。

正如Neil所说,这并不是真正的框架功能,实现它甚至将其抽象为自己的特性是相当简单的

trait CachingExpensiveThings { self: Actor =>
  val cache = ...
  def receive: Actor.Receive = {
    case s: ExpensiveThing => cachedOrCache(s)
  }

  def cacheOrCached(s: ExpensiveThing) = cache.get(s) match {
    case null => val result = compute(s)
                 cache.put(result)
                 self.reply_?)(result)
    case cached => self.reply_?)(cached)
  }
  def compute(s: ExpensiveThing): Any 
}


class MyExpensiveThingCalculator extends Actor with CachingExpensiveThings {
  def compute(s: ExpensiveThing) = {
    case l: LastDigitOfPi => ...
    case ts: TravellingSalesman => ...
  }
}

我不知道是否所有这些责任都应该由Akka来处理。通常,这一切都取决于规模,尤其是定义消息唯一性的属性的数量

对于缓存机制,前面提到的将请求唯一映射到参与者的方法是可行的,特别是持久性可以支持这种方法


如果是标识,我宁愿使用基于图形的算法,而不是检查简单的等式(这可能是瓶颈)

我还计算了Pi的最后一位,你把它变成了什么;p这是一种变化,取决于确保最后一条消息是已处理的消息,而不是队列中较早的消息。在我确保所有消息都已收到之前,我不想开始昂贵的计算。我认为上述方法可以通过FSM进行修改,以达到相同的结果。