Akka设计校长 [英] Akka Design Principals

查看:173
本文介绍了Akka设计校长的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



所以问题是这个,我有一个父actor,让我们称他为Connector,Connector有行为描述它在收到ConnectCommand实例时应该做什么。首先,它使用HttpClient提交表单,然后转到几个URL以检查某些会话参数,并最终向Sender(称为Consumer)发送包含使用API​​所需的所有内容的连接消息。



现在,我是一个忠实的粉丝,而不是拉/问,所以实现这一点在我看来是一项艰巨的任务。我们来看看吧。 HttpClientActor返回的所有响应都是一个Response实例,因此首先想到的是在我的actor中定义了多个行为,并且在连接过程的某个步骤完成后,逐步地将行为更改为下一步。

 私人最终的PartialFunction< Object,BoxedUnit> inital = ReceiveBuilder 
.match(ConnectCommand.class,c - > this.startConnection())
.matchAny(this :: unhandled)
.build();

私人最终的PartialFunction< Object,BoxedUnit> stage1 = ReceiveBuilder
.match(Response.class,this :: stage1)
.matchAny(this :: unhandled)
.build();

私人最终的PartialFunction< Object,BoxedUnit> stage2 = ReceiveBuilder
.match(Response.class,this :: stage2)
.matchAny(this :: unhandled)
.build();

私人最终的PartialFunction< Object,BoxedUnit> stage3 = ReceiveBuilder
.match(Response.class,this :: stage3)
.matchAny(this :: unhandled)
.build();

私人最终的PartialFunction< Object,BoxedUnit> stage4 = ReceiveBuilder
.match(Response.class,this :: stage4)
.matchAny(this :: unhandled)
.build();

私人最终的PartialFunction< Object,BoxedUnit> stage5 = ReceiveBuilder
.match(Response.class,this :: stage5)
.matchAny(this :: unhandled)
.build();

私人最终的PartialFunction< Object,BoxedUnit> stage6 = ReceiveBuilder
.match(Response.class,this :: stage6)
.matchAny(this :: unhandled)
.build();

私人最终的PartialFunction< Object,BoxedUnit> stage7 = ReceiveBuilder
.match(Response.class,this :: stage7)
.matchAny(this :: unhandled)
.build();

这样做的好处是它使用了tell而不是ask但是主要的缺点是代码变得非常不可读。



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



第一个涉及将每个HttpRequest和Response拆分为一个单独的Actor并在Connector actor中聚合结果。这样做的优点是非常易读,使用tell并且不应该损害性能,因为Akka是为处理大量演员而构建的。唯一的缺点是我需要为需要从Stage5Actor传递给Connector actor的状态部分创建许多容器类。这会产生很大的内存开销(如果我错了,请纠正我)。



第二种方法是使用Ask模式将步骤连接在一起。这将导致一个连接器actor,因为Spray也为它的Http Client做了这样的事情,我认为它可能是一个有效的解决方案。唯一的缺点是,因为一切都在外部Http API之上,超时可能会成为一个问题。如果Akka团队推荐这种方法,那么如何处理完全不可预测的所有超时。



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



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



提前感谢并感谢Akka团队制作了这么棒的lib!



PS。这个问题首先在Akka github本身上被问到,但我决定在这里发布,因为这与作为Akka相关问题的Actor模型相关问题一样多。



Link关于github上的问题: https://github.com/akka/akka/issues/16080

解决方案

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



此外,在您使用询问的任何情况下,您都可以轻松地将其替换为中间的Actor来保留此上下文并通过 tell 传递所有消息。这实际上是无论如何,但主要区别在于你不必为每个指定超时时间(好吧,你应该还有一个超时的整体请求)并且你可以在一个Actor中捆绑所有未完成的阶段而不是每个 ask 的额外Actor。 / p>

Jamie Allen对这种情况的描述非常好,因为有效的Akka 中的nofollow>额外和浮雕模式。



因此,考虑到所有这一切,您可能会遵循以下内容:




  • 当Consumer将消息发送到Connector时,Connector可以为此请求上下文创建一个新的Actor(Cameo)。您必须在此Actor中捕获 sender Consumer。

  • Cameo Actor可以通过告诉秒。此时,您可以将Cameo或Connector作为主管,这样您的监督策略仍可按您的需要工作。

  • 其中的Cameo 接收 block可以等待Connections的响应。这不必是询问上的等待。只需接受 receive 中的消息,然后更新内部状态。

  • 当所有连接完成后,您可以回复原始消费者通过告诉


Whilst working on a fairly large Akka application, I have come across a very simple structure when working with normal methods and non Akka classes but which are actually quite difficult to nail when working with Akka which is why I have come here to ask what you recommend to be the best way to solve this issue.

So the issue is this, I have one parent actor, let's call him "Connector", Connector has behavior describing what it should do when it receives a ConnectCommand instance. First it submit a form using an HttpClient, then it goes to a couple of URLs to check for some session parameters and eventually sends the Sender (Referred to as the "Consumer") a connection message containing everything it needs to use the API.

Now, I'm a big fan of tell, not so much of pull / ask so implementing this is in my opinion a hard task to do. Let's go over it. All the responses returned by the HttpClientActor are a Response instance, so what first came to mind is having multiple behaviors defined in my actor and incrementally, after a certain step of the connection process has been completed, change behavior to the next step.

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();

This has the advantage that it is using tell, not ask but has the major drawback that code becomes very unreadable.

Now I'm at the point I feel like this Actor needs some change in a good way but there are two alternatives in my opinion.

The first one involves splitting up every HttpRequest and Response into a separate Actor and aggregating the results in the Connector actor. This has the advantage of being very readable, using tell and shouldn't hurt performance because Akka is built to handle lots of actors. The only drawback to this is that I need to create a lot of container classes for these parts of state that need to be delivered from Stage5Actor to the Connector actor. This makes for a large memory overhead (correct me if I'm wrong).

The second approach is using the Ask pattern to wire the steps together. This would result in a single Connector actor and since Spray does so too for it's Http Client I think it may be a valid solution. Only drawback to this is, because everything rests on top of an external Http API, timeouts may become an issue. If this approach is recommend by the Akka team, how does one handle with all the timeouts which are completely unpredictable.

Please note that this implementation needs to be able to use supervision strategies since our whole current approach is based on top of this.

If you feel there is a far better solution than the ones I mentioned, please do tell! I'm really enjoying Akka a.t.m. and every piece of advice I get it, is a gain in experience and knowledge, not only for me, but for the whole community :D. Plus I think this is an issue more people run into every once in a while.

Thanks in advance and a big thanks to the Akka team for producing such an awesome lib!

PS. This question was first asked on the Akka github itself but I decided to post it here because this is just as much an Actor model related question as an Akka related question.

Link to the issue on github: https://github.com/akka/akka/issues/16080

解决方案

It seems to me like you don't necessarily need N stages to collect the responses. If you know how many responses you're waiting for you can collect them all under a single behavior.

Also, in any scenario where you are using ask, you can easily replace it with an intermediary Actor to hold this context and pass all messages through tell. That's actually what ask does anyway, but the main differences are that you wouldn't have to deal with specifying timeouts for every ask (well, you should still have a timeout for the overall request) and you can bundle all outstanding stages in a single Actor instead of an extra Actor for every ask.

Jamie Allen has really good description of this scenario as the Extra and Cameo Patterns in Effective Akka.

So with all this in mind, you might be able to follow something along the lines of:

  • When Consumer send the message to Connector, Connector can create a new Actor (Cameo) for this request context. You have to capture the sender Consumer in this Actor.
  • The Cameo Actor can kick off the subsequent requests through tells. At this point you can make either the Cameo or the Connector as the Supervisor so your Supervision Strategies still work as you want.
  • The Cameo in it's Receive block can wait for responses from Connections. This doesn't have to be an await on the ask. Just accept the message in the receive and then update your internal state.
  • When all the Connections are complete, you can respond to the original Consumer through tell.

这篇关于Akka设计校长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆