2017-06-23 53 views
3

我们有一个相当高的吞吐量演员系统,它通过http进行异步调用外部系统。我们发现,由于他们从我们那里收到的电话数量众多,下游系统正在遭到不测。限制异步调用演员

使用由下游系统中的呼叫“管”在这里描述的模式:https://petabridge.com/blog/akkadotnet-async-actors-using-pipeto/

之所以如此多的呼叫到下游系统做是因为一个演员不会等待响应异步调用在它的邮箱中处理下一条消息之前返回(当异步调用被启动时,它完成了消息)。显然这是设计的,但在这种情况下,会导致对外部服务进行非常多的异步调用。

我们需要一种限制呼叫的方法。我可以想到解决这个问题的几个可能的解决方案。

  1. 通过等待任务完成来同步执行对外部服务的调用。为演员设置一个池路由器,这基本上是一种限制对这个外部服务进行调用的方式。

  2. 使用ReceiveAsync方法而不是Receive。这基本上是完全相同的选项1.在petabride页我张贴以上虽然说这个这个方法 - “只是不去做” :)

  3. 使异步调用之前,开始积攒任何来电消息,然后在异步任务完成后取消它们。显然使用这种方法的吞吐量要受限得多。

我想知道有没有人在使用akka时有类似的问题,并能解决它?

编辑:

那么它到底是只为我们的工作选项1。即有一个带有Receive()的池路由器,该路由器专门等待IO调用所需的(调用外部系统的api)。这似乎工作得很好,我们可以通过设置池大小来控制'节流'。

我们尝试了选项2(ReceiveAsync),但是我们发现在某些时候系统会停下来并停止响应而不会引发任何错误。我们怀疑它陷入了僵局。这可能是由于异步函数的工作方式,而只是使用.Wait()或.Result等待任务。我现在可以看到为什么Petabridge建议不要使用ReceiveAsync :)

我们没有尝试选项3,因为这意味着更重要的更改。

回答

2

对于我来说,我已经解决了这个问题,它使用创建子路由器作为工作者,一次只能处理一条消息。因此,您可以配置多个工作人员的外部系统负载。此外,这可以使您能够使用一致性散列来避免某些消息的并行处理。

至于工作人员 - 在一个项目中,我使用了第一种方式,但对工作人员使用固定调度程序 - 因此他们总是使用相同的线程来处理消息,而不会影响其他系统部件。如果你有一个相当恒定的负载,这很好。

+0

感谢您的回复,这听起来像我们正在接近这个以相当类似的方式对自己这是很好的......稍后将发布一个答案,一旦我们制定了什么适合我们。 – lachy

2

其实第二个选项(ReceiveAsync)对于您的问题是完全有效的解决方案。唯一的风险是,在这种情况下,你会放慢发送者,因为actor现在将异步等待HTTP请求完成。这意味着,如果高比例的信息会不断推动,那么演员本身可能会不知所措。

如果是这样的话,你可以:

  1. 增加消费者(在HTTP连接的另一端听众)的数量,以跟上步伐。
  2. 使用阿卡流代替演员来模拟您的问题。流内置支持背压,可以在上游应用,直到它到达请求跟踪的原始源。
+0

感谢您的回复。我们将尝试使用池路由器的ReceiveAsync并进行一些负载测试,以了解它是如何发生的。如果这对我们不好,可能会看看Akka Streams。 – lachy