如何限制Akka流每秒只执行和发送一条消息?

如何限制Akka流每秒只执行和发送一条消息?,akka,rate,rate-limiting,akka-stream,Akka,Rate,Rate Limiting,Akka Stream,我有一个Akka流,我希望该流大约每秒向下游发送消息 我尝试了两种方法来解决这个问题,第一种方法是让流开始时的生产者在连续消息进入这个参与者时每秒只发送一次消息 //在ActorPublisher中接收继续消息时 //那就工作吧。。。 如果(总需求>0){ 导入scala.concurrent.duration_ context.system.scheduler.scheduleOnce(1秒,self,Continue) } 这在短时间内起作用,然后ActorPublisher actor

我有一个Akka流,我希望该流大约每秒向下游发送消息

我尝试了两种方法来解决这个问题,第一种方法是让流开始时的生产者在连续消息进入这个参与者时每秒只发送一次消息


//在ActorPublisher中接收继续消息时
//那就工作吧。。。
如果(总需求>0){
导入scala.concurrent.duration_
context.system.scheduler.scheduleOnce(1秒,self,Continue)
}

这在短时间内起作用,然后ActorPublisher actor中出现大量Continue消息,我假设(猜测但不确定)来自下游,通过背压请求消息,因为下游可以快速消费,但上游没有快速生产。所以这个方法失败了

我尝试的另一种方法是通过背压控制,在流的末尾对
ActorSubscriber
使用
MaxInFlightRequestStrategy
,将消息数量限制为每秒1条。这是可行的,但每次收到的消息大约有三条左右,而不是一次一条。似乎背压控制不会立即更改传入消息的速率,或者消息已经在流中排队等待处理

所以问题是,我怎么能有一个每秒只能处理一条消息的Akka流呢



我发现
MaxInFlightRequestStrategy
是一种有效的方法,但是我应该将批大小设置为1,它的批大小默认为5,这就是我发现的问题的原因。现在我在这里查看提交的答案,这也是解决问题的一种过于复杂的方法。

您可以将元件通过节流流,这将对快速源产生反压力,或者您可以使用
勾选
压缩
的组合

第一种解决方案如下:

val veryFastSource =
  Source.fromIterator(() => Iterator.continually(Random.nextLong() % 10000))

val throttlingFlow = Flow[Long].throttle(
  // how many elements do you allow
  elements = 1,
  // in what unit of time
  per = 1.second,
  maximumBurst = 0,
  // you can also set this to Enforcing, but then your
  // stream will collapse if exceeding the number of elements / s
  mode = ThrottleMode.Shaping
)

veryFastSource.via(throttlingFlow).runWith(Sink.foreach(println))
val veryFastSource =
  Source.fromIterator(() => Iterator.continually(Random.nextLong() % 10000))

val tickingSource = Source.tick(1.second, 1.second, 0) 

veryFastSource.zip(tickingSource).map(_._1).runWith(Sink.foreach(println))
第二种解决方案如下:

val veryFastSource =
  Source.fromIterator(() => Iterator.continually(Random.nextLong() % 10000))

val throttlingFlow = Flow[Long].throttle(
  // how many elements do you allow
  elements = 1,
  // in what unit of time
  per = 1.second,
  maximumBurst = 0,
  // you can also set this to Enforcing, but then your
  // stream will collapse if exceeding the number of elements / s
  mode = ThrottleMode.Shaping
)

veryFastSource.via(throttlingFlow).runWith(Sink.foreach(println))
val veryFastSource =
  Source.fromIterator(() => Iterator.continually(Random.nextLong() % 10000))

val tickingSource = Source.tick(1.second, 1.second, 0) 

veryFastSource.zip(tickingSource).map(_._1).runWith(Sink.foreach(println))

您是否考虑过使用
源代码。勾选
?不,让我看看,谢谢。您也可以尝试
节流
…但这将保留上游元素。。。如果要在节流的情况下丢弃上游元素,该怎么办?这有点棘手,因为您必须使用强制节流模式,然后处理阶段异常(节流不支持监控策略,因此您无法轻松恢复)。嘿@Christophern,您可以在勾号后使用缓冲区,并删除如下元素
Source.tick(1秒,3秒,完成)。buffer(0,OverflowStrategy.dropNew).throttle(1,1秒,1,ThrottleMode.Shaping).runForeach{{u=>}