我们有一个相当高吞吐量的Actor系统,通过http对外部系统进行异步调用。我们发现由于我们接收到的调用数量,下游系统正在被压垮。
使用“管道到”模式在此处描述的向下流系统的调用:https://petabridge.com/blog/akkadotnet-async-actors-using-pipeto/ 之所以会向下游系统发出这么多调用,是因为Actor在处理完消息后(异步调用启动时),不等待来自异步调用的响应即处理其邮箱中的下一条消息。显然,这是按设计而来的,但在这些情况下,它导致向外部服务发出非常多的异步调用。
我们需要一种限制调用的方法。我能想到几种可能的解决方案来解决这个问题。
我们没有尝试选项3,因为这将意味着更重大的更改。
使用“管道到”模式在此处描述的向下流系统的调用:https://petabridge.com/blog/akkadotnet-async-actors-using-pipeto/ 之所以会向下游系统发出这么多调用,是因为Actor在处理完消息后(异步调用启动时),不等待来自异步调用的响应即处理其邮箱中的下一条消息。显然,这是按设计而来的,但在这些情况下,它导致向外部服务发出非常多的异步调用。
我们需要一种限制调用的方法。我能想到几种可能的解决方案来解决这个问题。
通过等待任务完成,同步执行对外部服务的调用。为演员设置一个池路由器,基本上是一种限制对该外部服务进行调用的方式。
使用ReceiveAsync方法而不是Receive。这基本上与选项1完全相同。在我上面发布的petabride页面上,它关于此方法的说明是 - “只是别这样做” :)
在进行异步调用之前,开始存储任何传入的消息,然后在异步任务完成后将其取消存储。显然,使用此方法吞吐量要受到更大的限制。
我想知道是否有人在使用akka时遇到类似的问题并能够解决?
编辑:
最终我们只使用了选项1才解决了问题。即使用具有特定IO调用等待的Receive()的池路由器(对外部系统的api调用)。这似乎运行得很好,我们可以通过设置池大小来控制“限流”。
我们尝试了选项2(ReceiveAsync),但发现系统在某个时刻会变得不响应而没有抛出任何错误。我们怀疑它陷入了死锁状态。这可能是由于异步关键字的工作方式与仅使用.Wait()或.Result等待任务的方式不同。我现在可以看到Petabridge为什么建议不要使用ReceiveAsync :)我们没有尝试选项3,因为这将意味着更重大的更改。