使用Akka Streams询问演员或讲述或转发演员

时间:2018-11-16 07:38:31

标签: java akka akka-stream

嗨,我正在与akka streamsakka-stream-kafka一起工作。我正在使用以下设置来设置Stream:

Source (Kafka) --> | Akka Actor Flow | --> Sink (MongoDB)

Actor Flow基本上是由Actor处理数据,以下是层次结构:

                                      System
                                         | 
                                     Master Actor  
                                      /       \
                          URLTypeHandler     SerializedTypeHandler
                             /       \                   |
                     Type1Handler   Type2Handler     SomeOtherHandler

Kafka收到消息后,我写下了使用者并以atMostOnceSource配置运行并使用

Consumer.Control control =
            Consumer.atMostOnceSource(consumerSettings, Subscriptions.topics(TOPIC))
                    .mapAsyncUnordered(10, record -> processAccessLog(rootHandler, record.value()))
                    .to(Sink.foreach(it -> System.out.println("FinalReturnedString--> " + it)))
                    .run(materializer);

我最初使用打印作为接收器,只是为了使流程运行。

processAccessLog定义为:

private static CompletionStage<String> processAccessLog(ActorRef handler, byte[] value) {

    handler.tell(value, ActorRef.noSender());

    return CompletableFuture.completedFuture("");
}

现在,当演员期望响应时,必须使用定义ask,在这种情况下,这很有意义,因为我想返回要写入接收器中的值。

但是每个人(包括文档)都提到要避免使用ask,而要使用tellforwardDon't Ask, Tell上写着一个很棒的博客。

他在博客中提到,如果角色嵌套,则对第一条消息使用tell,然后对消息使用forward到达目的地,然后在处理后直接将消息发送回根演员。

from the blog

现在这是问题所在,

  1. 如何将消息从D发送回A,这样我仍然可以使用接收器。
  2. 拥有开放式视频流是一种好习惯吗?例如将Sink放到无关紧要的地方,因为演员已经完成了工作。 (我不建议这样做,这似乎是有缺陷的)。

2 个答案:

答案 0 :(得分:1)

ask仍然是正确的模式

在链接的博客文章中,ask的一个“缺点”是:

  

阻止演员本身,直到演员不能选择任何新消息   响应到达并完成处理。

但是,在akka-stream中,这正是我们正在寻找的确切功能,也就是“背压”。如果FlowSink花费很长时间来处理数据,那么我们希望Source变慢。

作为一个旁注,我认为博客文章中声称附加监听器Actor导致实现“数十倍重”的实现是夸张的。显然,中间的Actor增加了一些延迟开销,但没有增加12x

消除背压

您所寻找的任何实现都可以有效消除背压。仅使用tell的中间流将连续将需求传播回源,而不管您的处理逻辑是否在处理程序Actors中以与源生成数据相同的速度完成其计算。  考虑一个极端的例子:如果您的Source每秒可以产生100万条消息,但是Actor通过tell接收到这些消息,则每秒只能处理1条消息。该Actor的邮箱会发生什么?

通过using the ask pattern in an intermediate Flow,您有目的地链接处理程序的速度和Source生成数据的速度。

如果您想删除从接收器到源的反压信号,那么您最好也不要使用akka流。您可以使用反压力消息,也可以使用非阻塞消息,但不能同时使用。

答案 1 :(得分:1)

Ramon J Romero和Vigil是正确的,但我会尝试扩大答复。

1)我认为“不问,不说”教条主要用于Actor系统架构。在这里,您需要返回一个Future,以便流可以解析处理后的结果,您有两个选择:

  • 使用Ask
  • 为每个事件创建一个actor并将其传递给Promise,以便当该actor接收数据时,Future将完成(您可以使用getSender方法,以便D可以将响应发送给A)。无法在消息中发送Promise或Future(不可序列化),因此无法避免这种短暂的演员的创建。

最后,您的操作几乎相同...

2)最好使用一个空的接收器来完成流的确定(实际上akka提供了Sink.ignore()方法)。

似乎您正在丢失使用流的原因,它们是很酷的抽象,可提供可组合性,并发性和背压。另一方面,演员无法构成,很难应对背压。如果您不需要此功能,并且演员可以轻松完成工作,则不应该首先使用Akka流。