gpt4 book ai didi

java - Akka 设计原则

转载 作者:搜寻专家 更新时间:2023-11-01 03:04:49 25 4
gpt4 key购买 nike

在处理相当大的 Akka 应用程序时,我在使用普通方法和非 Akka 类时遇到了一个非常简单的结构,但在使用 Akka 时实际上很难确定,这就是我来这里的原因询问您推荐什么是解决此问题的最佳方法。

所以问题是这样的,我有一个父角色,我们称他为“Connector”,Connector 的行为描述了它在收到 ConnectCommand 实例时应该做什么。首先,它使用 HttpClient 提交一个表单,然后它转到几个 URL 以检查一些 session 参数,并最终向发送者(称为“消费者”)发送一条连接消息,其中包含使用 API 所需的一切。

现在,我非常喜欢讲述,而不是拉动/询问,所以在我看来,实现这是一项艰巨的任务。让我们回顾一下。 HttpClientActor 返回的所有响应都是一个 Response 实例,所以首先想到的是在我的 actor 中定义多个行为,并在完成连接过程的某个步骤后,将行为更改为下一步。

private final PartialFunction<Object, BoxedUnit> inital = ReceiveBuilder
.match(ConnectCommand.class, c -> this.startConnection())
.matchAny(this::unhandled)
.build();

private final PartialFunction<Object, BoxedUnit> stage1 = ReceiveBuilder
.match(Response.class, this::stage1)
.matchAny(this::unhandled)
.build();

private final PartialFunction<Object, BoxedUnit> stage2 = ReceiveBuilder
.match(Response.class, this::stage2)
.matchAny(this::unhandled)
.build();

private final PartialFunction<Object, BoxedUnit> stage3 = ReceiveBuilder
.match(Response.class, this::stage3)
.matchAny(this::unhandled)
.build();

private final PartialFunction<Object, BoxedUnit> stage4 = ReceiveBuilder
.match(Response.class, this::stage4)
.matchAny(this::unhandled)
.build();

private final PartialFunction<Object, BoxedUnit> stage5 = ReceiveBuilder
.match(Response.class, this::stage5)
.matchAny(this::unhandled)
.build();

private final PartialFunction<Object, BoxedUnit> stage6 = ReceiveBuilder
.match(Response.class, this::stage6)
.matchAny(this::unhandled)
.build();

private final PartialFunction<Object, BoxedUnit> stage7 = ReceiveBuilder
.match(Response.class, this::stage7)
.matchAny(this::unhandled)
.build();

这有一个优点,它使用的是告诉,而不是询问,但有一个主要缺点,即代码变得非常不可读。

现在我觉得这个 Actor 需要一些好的改变,但我认为有两种选择。

第一个涉及将每个 HttpRequest 和 Response 拆分到一个单独的 Actor 中,并将结果聚合到 Connector actor 中。这具有非常可读的优点,使用 tell 和 shouldn 不会影响性能,因为 Akka 是为处理大量 actors 而构建的。这样做的唯一缺点是我需要为这些需要从 Stage5Actor 传递到 Connector actor 的状态部分创建很多容器类。这会导致大量内存开销(如果我错了请纠正我)。

第二种方法是使用 Ask 模式将步骤连接在一起。这将导致单个连接器参与者,并且由于 Spray 也为其 Http 客户端这样做,我认为这可能是一个有效的解决方案。唯一的缺点是,因为一切都基于外部 Http API,超时可能成为一个问题。如果 Akka 团队推荐这种方法,那么如何处理所有完全不可预测的超时?

请注意,此实现需要能够使用监督策略,因为我们当前的整个方法都基于此。

如果您觉得有比我提到的更好的解决方案,请告诉我!我真的很喜欢 Akka a.t.m.我得到的每条建议都是经验和知识的收获,不仅对我而且对整个社区都是如此:D。另外,我认为这是一个越来越多的人不时遇到的问题。

在此先感谢并非常感谢 Akka 团队制作了如此出色的库!

附言。这个问题最初是在 Akka GitHub 本身上提出的,但我决定将其发布在这里,因为这既是 Actor 模型相关问题,也是 Akka 相关问题。

GitHub 上问题的链接:https://github.com/akka/akka/issues/16080

最佳答案

在我看来,您不一定需要 N 个阶段来收集回复。如果您知道您在等待多少响应,您可以在一个行为下收集所有响应。

此外,在您使用ask 的任何场景中,您都可以轻松地将其替换为一个中介 Actor 来保存此上下文并通过 tell 传递所有消息。这实际上就是 ask 所做的,但主要区别在于您不必为每个 ask 指定超时(好吧,您仍然应该为整个请求),您可以将所有未完成的阶段捆绑在一个 Actor 中,而不是为每个 ask 一个额外的 Actor。

杰米·艾伦 (Jamie Allen) 对这种情况的描述非常好,如 Extra and Cameo PatternsEffective Akka .

因此,考虑到所有这些,您也许可以遵循以下思路:

  • 当 Consumer 将消息发送给 Connector 时,Connector 可以为此请求上下文创建一个新的 Actor (Cameo)。您必须在此 Actor 中捕获 sender Consumer。
  • Cameo Actor 可以通过 tell 启动后续请求。此时,您可以将 Cameo 或连接器设置为监督者,这样您的监督策略仍然可以按照您的意愿工作。
  • Receive block 中的 Cameo 可以等待来自 Connections 的响应。这不一定是 ask 上的 await。只需在 receive 中接受消息,然后更新您的内部状态。
  • 当所有的Connection都完成后,就可以通过tell来响应原来的Consumer了。

关于java - Akka 设计原则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26319471/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com