Akka 这种阿卡卡夫卡流配置是否得益于阿卡流的背压机制?
我们有一个Akka应用程序,它使用Kafka主题并将收到的消息发送给Akka参与者。我不确定我编程的方式是否充分利用了Akka Streams内置背压机制的所有优点 以下是我的配置Akka 这种阿卡卡夫卡流配置是否得益于阿卡流的背压机制?,akka,akka-stream,akka-kafka,Akka,Akka Stream,Akka Kafka,我们有一个Akka应用程序,它使用Kafka主题并将收到的消息发送给Akka参与者。我不确定我编程的方式是否充分利用了Akka Streams内置背压机制的所有优点 以下是我的配置 val control : Consumer.DrainingControl[Done] Consumer .sourceWitOffsetContext(consumerSettings, Subscriptions.topics("myTopic")) .map(consumerRecor
val control : Consumer.DrainingControl[Done]
Consumer
.sourceWitOffsetContext(consumerSettings, Subscriptions.topics("myTopic"))
.map(consumerRecord =>
val myAvro = consumerRecord.value().asInstanceOf[MyAvro]
val myActor = AkkaSystem.sharding.getMyActor(myAvro.getId)
myActor ! Update(myAvro)
)
.via(Commiter.flowWithOffsetContext(CommitterSettings(AkkaSystem.system.toClassic)))
.toMat(Sink.ignore)(Consumer.DrainControl.apply)
.run()
这与我的商业案例所期望的一样,myActor接收命令更新(MyAvro)
我对背压的技术概念更为恼火,据我所知,背压机制部分由水槽控制,但在这种流配置中,我的水槽只是“水槽。忽略”。所以我的水槽对背压有任何作用
当Akka Kafka Stream提交Kafka主题偏移量时,我还好奇什么?命令发送到MyActor邮箱的那一刻?如果是这样的话,那么我如何处理像ask模式这样的场景呢?在ask模式完成之前,卡夫卡偏移量不应该提交
我看到一些处理手动偏移控制的工厂方法“plainPartitionedManualOffsetSource”、“CommitteablePartitionManualOffsetSource”,但我找不到这些方法的任何示例,我可以用我的业务逻辑来决定手动提交偏移吗
作为一种替代配置,我可以使用这样的配置
val myActor: ActorRef[MyActor.Command] = AkkaSystem.sharding.getMyActor
val (control, result) =
Consumer
.plainSource(consumerSettings, Subscriptions.topics("myTopic"))
.toMat(Sink.actorRef(AkkaSystem.sharding.getMyActor(myAvro.getId), null))(Keep.both)
.run()
现在我可以访问Sink.actorRef了,我认为背压机制有机会控制背压,当然这个代码不会工作,因为我不知道如何在这个星座下访问“myAvro”
答案为Thx。在第一个流中,基本上没有背压。偏移提交将在消息发送到
myActor
后很快发生
对于背压,您需要等待目标参与者的响应,正如您所说,ask模式是实现这一点的标准方法。由于来自参与者外部的参与者请求(出于所有意图和目的,流都在参与者外部:参与者执行的阶段是一个实现细节)会导致未来
,这表明需要调用mapsync
def askUpdate(m: MyAvro): Future[Response] = ??? // get actorref from cluster sharding, send ask, etc.
然后将原始流中的映射替换为
.mapAsync(parallelism) { consumerRecord =>
askUpdate(consumeRecord.value().asInstanceOf[MyAvro])
}
mapsync
将“正在运行”的未来限制为并行性
。如果存在parallelism
futures(当然是由它产生的),它将产生反压力。如果衍生的未来完成时出现故障(对于ask本身,这通常是一个超时),它将失败;成功期货的结果(关于传入订单)将被传递(通常情况下,这些结果将是akka.Done
,尤其是当流中只剩下offset commit和Sink.ignore
)时)。此语句不正确:
。。。据我所知,背压机制部分由水槽控制,但在这种水流配置中,我的水槽只是“水槽。忽略”。所以我的水槽对背压有任何作用
对于背压,Sink
s没有什么特别之处。作为流量控制机制的背压将自动用于流中存在异步边界的任何地方。这可能在Sink
中,但也可能在流中的任何其他地方
在你的情况下,你正在连接你的流与演员交谈。这是您的异步边界,但您这样做的方式是使用映射
,在该映射内使用代码>与演员对话。因此没有背压,因为:
map
不是一个异步操作符,它内部调用的任何东西都不能参与背压机制。因此,从Akka流的角度来看,没有引入异步边界
是fire and forget,没有提供关于演员有多忙来实施任何背压的反馈
就像Levi提到的那样,你可以做的是从告诉
改变为询问
互动,并让接受者在工作完成时做出回应。然后可以像Levi描述的那样使用mapAsync
。这里map
和mapsync
之间的区别在于mapsync
的语义使得它只有在返回Future
完成时才会向下游发出。即使并行度为1,背压仍然有效。如果您的卡夫卡记录比您的演员处理的速度快得多,mapsync
将在等待未来
完成时向上游反压。在这种情况下,我认为增加并行度没有任何意义,因为所有这些消息都将添加到参与者的收件箱中,所以这样做不会真正加快任何速度。如果交互是REST调用,那么它可以提高总体吞吐量。根据参与者处理消息的方式,为mapsync
增加并行度可能会导致吞吐量增加paralleslism
value有效地限制了在背压开始之前允许的最大未完成的Future
s数。首先感谢您的回答,如果我理解正确,如果“并行度”不大于1,那么将再次没有背压机制。所以下一个问题是,什么是平行性?经典的“核心数量*2”?哪个最有可能与Dispatcher线程池大小相同?以及它如何与卡夫卡的分区交互,这是卡夫卡创建并行性的方式。因此,如果我使用plainPartitionedManualOffsetSource而不是“sourceWitOffsetContext”,并且使用4个Kafka分区和并行度1,我将得到反压力?如果并行度为1,则在发送ask和接收响应之间的一段时间内仍然会有反压力。分区源和mapAsync(1)仍将背压(请注意,为了提高效率,消费者仍会批量读取卡夫卡的内容,并且