消息处理限制/背压

时间:2014-03-17 16:35:47

标签: system.reactive reactive-programming rxjs

我有消息来源,Observable。对于每个我希望进行HTTP调用的消息,这将产生另一个Observable,因此我将它们与flatMap组合在一起,然后将它们汇入某个订阅者。这里是这个场景的代码:

Rx.Observable.interval(1000)
.flatMap (tick) ->
  // returns an `Observable`
  loadMessages()
.flatMap (message) ->
  // also returns and `Observable`
  makeHttpRequest(message)
.subscribe (result) ->
  console.info "Processed: ", result

这个例子是用coffeescript编写的,但我认为问题陈述对任何其他Rx实现都有效。

我采用这种方法的问题是loadMessages非常快地产生了很多消息。这意味着,我在很短的时间内发出了很多HTTP请求。这在我的情况下是不可接受的,所以我想将并行HTTP请求的数量限制为10左右。换句话说,当我发出HTTP请求时,我想限制pipelene或应用某种backpresure。

Rx是否有任何标准方法或最佳做法来处理此类情况?

目前我实施了非常简单(并且非常次优)的背压机制,如果系统在处理过程中有太多按摩,则会忽略滴答。它看起来像这样(简化版):

Rx.Observable.interval(1000)
.filter (tick) ->
  stats.applyBackpressureBasedOnTheMessagesInProcessing()
.do (tick) ->
  stats.messageIn()
.flatMap (tick) ->
  // returns an `Observable`
  loadMessages()
.flatMap (message) ->
  // also returns and `Observable`
  makeHttpRequest(message)
.do (tick) ->
  stats.messageOut()
.subscribe (result) ->
  console.info "Processed: ", result

我不确定,这是否可以做得更好,或者Rx已经有一些机制来处理这种要求。

3 个答案:

答案 0 :(得分:2)

这不是严格的背压,这只是限制了并发性。这是一个简单的方法(忽略我可能错误的语法,通过TextArea编码):

Rx.Observable.interval(1000)
    .flatMap (tick) ->
        // returns an `Observable`
        loadMessages()
    .map (message) ->
        // also returns and `Observable`, but only when
        // someone first subscribes to it
        Rx.Observable.defer ->
            makeHttpRequest(message)
    .merge 10 // at a time
    .subscribe (result) ->
        console.info "Processed: ", result

在C#中,相同的想法是,而不是SelectMany,它是Select(Defer(x)).Merge(n)Merge(int)最多订阅了n个正在进行中的Observable,并将其余内容缓存到以后。我们拥有Defer的原因是为了让我们在Merge(n)订阅我们之前不做任何工作。

答案 1 :(得分:1)

听起来你想从队列中拉出而不是推送你的http请求。 Rx真的是正确的技术选择吗?

编辑:

一般情况下,我不会使用Rx设计解决方案,因为我对源事件有完全的命令控制。这不是一个被动的场景。

Rxjs中的背压模块是为了处理您不拥有源流的情况而编写的。你来了。

TPL Dataflow听起来更适合这里。

如果必须使用RX,则可以设置如下循环:如果要限制为X并发事件,请设置主题作为消息源,命令推送({ {1}})X消息进入它。在您的订阅者中,您可以在OnNext处理程序的每次迭代中将新消息推送到主题,直到源耗尽。这保证了飞行中最多X条消息。

答案 2 :(得分:1)

在RXJS中,您可以使用背压子模块

http://rxjs.codeplex.com/SourceControl/latest#src/core/backpressure/

disclaimer我从未使用过RX版本的JS,但你确实要求实现背压的标准方法,而核心库似乎也支持它。 RX c#还没有这个支持。不知道为什么。