QA 视角下的 Akka 系统
Akka system from a QA perspective
我已经测试基于 Akka 的应用程序一个多月了。但是,如果我反思一下,我有以下结论:
- 单靠Akka actors就可以实现很多并发。我达到了10万多messages/sec。这很好,只是消息传递。
- 现在,如果一端有用于连接的 netty 层,或者您最终使用 akka actors 最终进行数据库调用、REST 调用、写入文件,那么整个系统就不再有意义了。演员的邮箱已满,他们的吞吐量(此处,接收能力 msgs/sec)变慢。
- 从 QA 的角度来看,这就像有一个巨大的管道,您可以在其中强行泵入大量水并且它可以处理。但是,如果输入软管坏了,或者端点不能承受压力,那么这个巨大的管道就没有用了。
我需要以下问题的答案,以便我可以在系统中进行建议或验证:
- DB 调用、REST 调用等阻塞调用是否应该由 actor 处理?或者它们只适用于消息传递?
- 是否可以,假设您需要将数百万 android/ios 设备持续连接到您的 akka 系统。代替sockets(如此不可靠)等,remote actor可以实现为持久连接吗?
- 可以在 actor 的
handleMessage()
中进行任何类型的计算吗?像数据库调用等
我会请求这个 post 由编辑通过。我不能单独问所有这些。
我不确定我能理解你所有的问题,但总的来说,演员也适合慢活:
1) 是的,它们非常好。每个请求仅 create/assign 1 个参与者(可能在 akka 路由器后面用于负载平衡),一旦完成,它可以将自己标记为 "free for new work" 或自行终止。记得以后执行慢代码。就个人而言,由于隐式超时和异常吞噬,我喜欢避免使用 ask/pipe 模式,只需使用带有请求 ID 的告诉,但如果您的延迟和错误率很低,请选择 ask/pipe.
2) 可以,但在那种情况下,我建议使用一个连接池而不是按请求生成它们,因为这需要更长的时间。如果你能提供更多细节,我也许可以改进这个答案。
3) 是的,但想想看:演员很便宜。创造数以百万计的他们,每次有一个阻塞的部分,它应该是一个不同的、专门的演员。将单一职责发挥到极致。如果您的阻塞演员很少,您将失去所有好处。
1) 是的,他们可以。但是这个操作应该在单独的(工作者)actor 中完成,它使用 fork-join-pool 结合 scala.concurrent.blocking
围绕阻塞代码,它需要它来防止线程饥饿。如果目标系统(DB、REST 等)支持多个并发连接,您可以为此使用 akka 的路由器(为池中的每个连接创建一个参与者)。您还可以为多个不同的表(资源、队列等)生成多个参与者,具体取决于您的事务隔离和存储的一致性要求。
处理此问题的另一种方法是使用带有确认而不是阻塞的异步请求。您也可以将阻塞操作放在一些单独的未来(线程,工作人员)中,它将在操作结束时发送确认消息。
2) 是的,actor 可以实现为持久连接。它将只是一个 actor,它保存连接的状态(因为 actor 是有状态的)。使用 Akka Persistence 可能更可靠,它可以节省与某些存储的连接。
3) 您可以在 actor 的 receive
内部进行任何非阻塞计算(akka 中没有 handleMessage
方法)。失败(比如没有连接到数据库)将由 Akka Supervising 自动管理。拦截代码见1.
P.S。大约 "huge pipe"。后端应用程序本身是一个管道(它随着 akka 变得越来越大),所以如果环境无法处理它,没有什么可以帮助您提高性能 - 这个世界上没有泵。但是akka也是一个"water tank",也就是说外压可能比内压强。顺便说一句,这意味着开发人员应该小心邮箱 - 因为 "too much water" 可能会导致 OutOfMemory,防止这种情况的方法是组织 back pressure。这可以通过不确认传入消息(或简单地阻止端点的处理程序)直到它由 akka 进行来完成。
我已经测试基于 Akka 的应用程序一个多月了。但是,如果我反思一下,我有以下结论:
- 单靠Akka actors就可以实现很多并发。我达到了10万多messages/sec。这很好,只是消息传递。
- 现在,如果一端有用于连接的 netty 层,或者您最终使用 akka actors 最终进行数据库调用、REST 调用、写入文件,那么整个系统就不再有意义了。演员的邮箱已满,他们的吞吐量(此处,接收能力 msgs/sec)变慢。
- 从 QA 的角度来看,这就像有一个巨大的管道,您可以在其中强行泵入大量水并且它可以处理。但是,如果输入软管坏了,或者端点不能承受压力,那么这个巨大的管道就没有用了。
我需要以下问题的答案,以便我可以在系统中进行建议或验证:
- DB 调用、REST 调用等阻塞调用是否应该由 actor 处理?或者它们只适用于消息传递?
- 是否可以,假设您需要将数百万 android/ios 设备持续连接到您的 akka 系统。代替sockets(如此不可靠)等,remote actor可以实现为持久连接吗?
- 可以在 actor 的
handleMessage()
中进行任何类型的计算吗?像数据库调用等
我会请求这个 post 由编辑通过。我不能单独问所有这些。
我不确定我能理解你所有的问题,但总的来说,演员也适合慢活:
1) 是的,它们非常好。每个请求仅 create/assign 1 个参与者(可能在 akka 路由器后面用于负载平衡),一旦完成,它可以将自己标记为 "free for new work" 或自行终止。记得以后执行慢代码。就个人而言,由于隐式超时和异常吞噬,我喜欢避免使用 ask/pipe 模式,只需使用带有请求 ID 的告诉,但如果您的延迟和错误率很低,请选择 ask/pipe.
2) 可以,但在那种情况下,我建议使用一个连接池而不是按请求生成它们,因为这需要更长的时间。如果你能提供更多细节,我也许可以改进这个答案。
3) 是的,但想想看:演员很便宜。创造数以百万计的他们,每次有一个阻塞的部分,它应该是一个不同的、专门的演员。将单一职责发挥到极致。如果您的阻塞演员很少,您将失去所有好处。
1) 是的,他们可以。但是这个操作应该在单独的(工作者)actor 中完成,它使用 fork-join-pool 结合 scala.concurrent.blocking
围绕阻塞代码,它需要它来防止线程饥饿。如果目标系统(DB、REST 等)支持多个并发连接,您可以为此使用 akka 的路由器(为池中的每个连接创建一个参与者)。您还可以为多个不同的表(资源、队列等)生成多个参与者,具体取决于您的事务隔离和存储的一致性要求。
处理此问题的另一种方法是使用带有确认而不是阻塞的异步请求。您也可以将阻塞操作放在一些单独的未来(线程,工作人员)中,它将在操作结束时发送确认消息。
2) 是的,actor 可以实现为持久连接。它将只是一个 actor,它保存连接的状态(因为 actor 是有状态的)。使用 Akka Persistence 可能更可靠,它可以节省与某些存储的连接。
3) 您可以在 actor 的 receive
内部进行任何非阻塞计算(akka 中没有 handleMessage
方法)。失败(比如没有连接到数据库)将由 Akka Supervising 自动管理。拦截代码见1.
P.S。大约 "huge pipe"。后端应用程序本身是一个管道(它随着 akka 变得越来越大),所以如果环境无法处理它,没有什么可以帮助您提高性能 - 这个世界上没有泵。但是akka也是一个"water tank",也就是说外压可能比内压强。顺便说一句,这意味着开发人员应该小心邮箱 - 因为 "too much water" 可能会导致 OutOfMemory,防止这种情况的方法是组织 back pressure。这可以通过不确认传入消息(或简单地阻止端点的处理程序)直到它由 akka 进行来完成。