Java 询问vs告诉或转发使用Akka流的演员
您好,我与Java 询问vs告诉或转发使用Akka流的演员,java,akka,akka-stream,Java,Akka,Akka Stream,您好,我与akka streams以及akka stream kafka一起工作。我正在使用以下设置设置流: Source (Kafka) --> | Akka Actor Flow | --> Sink (MongoDB) Actor Flow主要由处理数据的Actor进行,下面是层次结构: System |
akka streams
以及akka stream kafka
一起工作。我正在使用以下设置设置流:
Source (Kafka) --> | Akka Actor Flow | --> Sink (MongoDB)
Actor Flow
主要由处理数据的Actor进行,下面是层次结构:
System
|
Master Actor
/ \
URLTypeHandler SerializedTypeHandler
/ \ |
Type1Handler Type2Handler SomeOtherHandler
卡夫卡有一条信息,我写下消费者并在atmostonesource
configuration and use中运行它
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("");
}
私有静态CompletionStage processAccessLog(ActorRef处理程序,字节[]值){
tell(value,ActorRef.noSender());
返回CompletableFuture.completedFuture(“”);
}
现在,根据定义,当参与者期望响应时必须使用ask
,在这种情况下是有意义的,因为我希望返回要写入接收器中的值
但是每个人(包括文档)都提到避免询问,而是使用告诉和转发,这是一个很棒的博客
在他提到的博客中,如果是嵌套的参与者,则对第一条消息使用tell
,然后对到达目的地的消息使用forward
,然后在处理后直接将消息发送回根参与者
现在问题来了
询问
仍然是正确的模式
从链接的博客文章来看,ask
的一个“缺点”是:
阻止参与者本身,直到
响应到达,处理完成
然而,在akka stream中,这正是我们正在寻找的特征,也称为“背压”。如果流
或接收器
处理数据需要很长时间,那么我们希望源
的速度减慢
作为旁注,我认为在博客文章中声称额外的监听器Actor
会导致一个“几十倍重”的实现是夸张的。显然,中间参与者会增加一些延迟开销,但不会增加更多
消除背压
任何你正在寻找的实现都将有效地消除背压。仅使用tell
的中间流将持续将需求传播回源,而不管处理程序参与者中的处理逻辑是否以源生成数据的相同速度完成其计算。
考虑一个极端的例子:如果你的源可以每秒产生100万条消息,但是通过<代码>接收这些消息的参与者告诉每秒只能处理1条消息。那个演员的邮箱会怎么样
通过有目的地链接处理程序的速度和源生成数据的速度
如果你愿意移除从水槽到源头的背压信号,那么你最好首先不要使用akka stream。您可以使用背压或非阻塞消息,但不能同时使用两者。Ramon J Romero y Vigil是正确的,但我将尝试扩展响应 1) 我认为“不问就说”的教条主要是针对参与者系统架构的。在这里,您需要返回Future,以便流可以解析处理后的结果,您有两个选项:
- 使用询问
- 为每个事件创建一个参与者,并向他们传递承诺,这样,当该参与者收到数据时,未来将是完整的(您可以使用
方法,以便D可以将响应发送给a)。没有办法在信息中传达承诺或未来(这些信息不可连载),因此无法避免创造这种短命演员getSender
Sink.ignore()
方法来完成)
似乎您缺少了使用流的原因,它们是提供可组合性、并发性和背压的很酷的抽象。另一方面,演员无法作曲,难以承受背压。如果您不需要这些功能,而且您的演员可以轻松完成工作,那么您首先不应该使用akka streams。感谢您的精彩解释,我最后做的是使用
.mapsyncUnordered(10,record->ask(ActorA,record.value()处理我的流)
,然后是来自ActorA->ActorB->ActorC
的forward
,ActorC使用getSender().tell(myResponse,ActorRef.noSender());
。然后利用Sink
对所有仍应传播背压的外部数据存储进行处理(根据我的理解)@iam.Carrot不客气。只要涉及到一个ask,那么是的,背压就会传播。很快,执行ActorRef.ask()是否相关
如果你有一个完整的演员系统来处理Sink
,那么在Sink
也可以。或者,即使我们有告诉非常感谢你的回答,特别是在第二点上,因为我很担心它。+1