想象一下以下架构。 akka中有一个actor通过websocket接收推送消息。它们有一个时间戳,这些时间戳之间的间隔是1分钟。虽然具有相同时间戳的消息可以通过websocket多次到达。然后,这些消息被广播为三个其他演员(ma)。他们计算指标并将消息进一步推送给一个参与者(c)。
对于 ma 我定义了一个TimeSeriesBuffer,它只允许在实体有后续时间戳的情况下写入缓冲区。成功推送到缓冲区 ma 的发布指标后,转到 c 。 c 只有在具有所有三个指标时才能更改其状态。因此,我定义了一个特性Synchronizable,然后是一个SynchronizableTimeSeriesBuffer与" master-slave"建筑。
每次推送到每个缓冲区时,都会触发检查,以便了解所有三个SynchronizableTimeSeriesBuffer的缓冲区中是否有新元素具有相同的时间戳,可以作为单个进一步发送到 c 消息。
以下是问题:
1)解决方案太复杂了吗?
2)有没有更好的方法来实现scala和akka?
3)为什么系统中的消息不是那么快而且不那么平行而不是被接收"逐个"从一个大批量的db加载并送入系统,以便回溯测量指标。 (其中一个缓冲区填充速度比其他缓冲区快,而另一个缓冲区填充长度为0)。我假设它与akka关于调度/邮箱的设置有关。
我创建了一个关于代码的要点: https://gist.github.com/ifif14/18b5f85cd638af7023462227cd595a2f
我非常感谢社区帮助解决这个非常重要的案件。
提前致谢
伊戈尔
答案 0 :(得分:0)
<强>简化强>
您的架构似乎旨在确保您的邮件按时顺序排列。为什么不在开头添加一个简单的Actor
来过滤掉重复的邮件?然后你的系统的其余部分可能相对简单。
作为一个例子;给出带有时间戳的消息
type Payload = ???
case class Message(timestamp : Long, payload : Payload)
您可以编写过滤器Actor:
class FilterActor(ma : Iterable[ActorRef]) extends Actor {
var currentMaxTime = 0L
override def receive = {
case m : Message if m.timestamp > currentMaxTime => ma foreach (_ ! m)
case _ =>
}
}
现在您可以消除所有“TimeSeriesBuffer”和“Synchronizable”逻辑,因为您知道ma和c只接收按时间排序的消息。
批处理
批处理不是那么并发的可能原因是因为ma
Actor的邮箱正被数据库查询填满,而且它正在进行的任何处理都比c
的处理慢。因此,当c的邮箱保持相对空白时,ma的邮箱会继续累积邮件。
答案 1 :(得分:0)
非常感谢您的回答。切断的部分也是我在Synchronizable Trait中实现的。
//clean up slaves. if their queue is behind masters latest element
master_last_timestamp match {
case Some(ts) => {
slaves.foreach { s =>
while ( s.queue.length > 0 && s.getElementTimestamp(s.queue.front) < ts ) {
s.dequeue()
}
// val els = s.dequeueAll { queue_el => s.getElementTimestamp(queue_el) < ts }
}
}
case _ => Unit
}
我开始实现缓冲区的原因是因为我觉得我会在系统中大量使用它而我不会想为每个将要使用的演员编写这个部分。似乎更容易获得一个蓝图。
但更重要的原因是,由于某种原因,一个缓冲区要么填充得慢得多,要么根本不填充其他两个缓冲区。虽然他们被同样的演员填补! (只是不同的实例,计算时间应该几乎相同)然后在另外两个演员发出所有传递的消息后#34;从数据库中,第三个开始接收它。我觉得这个演员只是没有得到处理器时间。所以我认为这是一个可以影响这一点的调度员设置。你熟悉这个吗?
此外,我希望调度员的工作更像循环法,因为每个进程都有一点执行时间,但最终只能提供有限数量的演员,然后跳到下一个演员。虽然有一个广播公司,但它们必须同时接收初始消息。
我在调度员和邮箱上阅读了akka文档,但我仍然不了解如何操作。
谢谢
伊戈尔