我一直在研究我的一个项目,使用Akka来创建一个实时处理系统,该系统接收Twitter流(现在)并使用actor以各种方式处理所述消息。我一直在阅读其他人使用Akka构建的类似架构,这个特别的博客文章引起了我的注意:
http://blog.goconspire.com/post/64901258135/akka-at-conspire-part-5-the-importance-of-pulling
在这里,他们解释了在向演员推动工作(即消息)与让演员拉动工作时出现的不同问题。为了解释这篇文章,通过推送信息,没有内置的方法来了解哪个工作单位是由哪个工人接收的,也无法可靠地跟踪。此外,如果工作人员突然收到大量消息,其中每条消息都非常大,您可能最终会不堪重负,并且机器可能会耗尽内存。或者,如果处理是CPU密集型的,您可能会因CPU抖动而使节点无响应。此外,如果jvm崩溃,您将丢失该actor在其邮箱中的所有消息。
拉取消息很大程度上消除了这些问题。由于特定的参与者必须从协调员那里获取工作,协调员总是知道每个工人的工作单位;如果工人死亡,协调员知道要重新处理哪个工作单元。消息也不会位于工作人员的邮箱中(因为它在拉动另一条消息之前处理它并处理它),因此如果演员崩溃则丢失这些邮箱不是问题。此外,由于每个工作人员只有在完成当前任务后才会请求更多的工作,所以不会担心工人接收或开始的工作多于它可以同时处理的工作。显然,这个解决方案也存在问题,比如当协调器本身崩溃时会发生什么,但现在让我们假设这是一个非问题。关于这种拉动模式的更多信息也可以在博客引用的“Let It Crash”网站上找到:
http://letitcrash.com/post/29044669086/balancing-workload-across-nodes-with-akka-2
这让我想到了这种拉动模式的可能替代方案,即使用持久邮箱进行推送。我想到的一个例子是实现一个使用RabbitMQ的邮箱(其他数据存储,如Redis,MongoDB,Kafka等也可以在这里工作),然后让每个actor的路由器(所有这些都用于相同的目的)共享相同的消息队列(或相同的DB /集合/ etc ...取决于所使用的数据存储)。换句话说,每个路由器在RabbitMQ中都有自己的队列作为邮箱。这样,如果其中一个路由器出现故障,那些仍在运行的路由器可以简单地继续从RabbitMQ中检索,而不必担心队列会溢出,因为它们不再使用典型的内存中邮箱。此外,由于他们的邮箱没有在内存中实现,如果一个routee崩溃,它可能丢失的大多数消息将只是它在崩溃之前处理的单个消息。如果整个路由器出现故障,那么您可以预期RabbitMQ(或正在使用的任何数据存储)处理增加的负载,直到路由器能够恢复并再次开始处理消息为止。
就持久邮箱而言,似乎在2.0版本中,Akka更倾向于更积极地支持这些,因为他们已经实现了一些可以与MongoDB,ZooKeeper等一起工作的东西。但是,似乎无论出于什么原因他们自从最新版本(截至本文撰写后的2.3.2)未提及它们以来,某些时候放弃了这个想法。您仍然可以通过实现MessageQueue接口来实现自己的邮箱,该接口为您提供了enqueue(),dequeue()等方法...因此制作一个适用于RabbitMQ,MongoDB,Redis等的方法似乎不会是个问题。
无论如何,只是想让你的男人和女孩们对此有所了解。这看起来像是拉动的可行替代方案吗?
答案 0 :(得分:1)
这个问题也在akka-user上产生了一个相当长而且信息丰富的主题。总之,最好显式管理要由(持久性)actor执行的工作项,可变数量的工作者从中提取新作业,因为这样可以更好地管理资源并明确控制处理的内容以及处理重试的方式