使用Rx限制远程资源的使用

时间:2016-02-06 12:40:20

标签: java rx-java

我正在使用RxJava异步处理servlet请求。在每个请求期间,使用flatMap运算符对远程服务API进行大量异步调用。

由于资源限制,我需要限制针对该API的并发请求总数。对于使用其并发参数在单个flatMap中调用API的单个Rx流,这将是微不足道的。但是我的应用程序中有多个独立的流(每个ServletRequest基本上都有一个),每个流都有多个对API的flatMap调用。

所以我认为我必须将所有远程请求汇集到执行实际调用的单例流中,然后才能轻松限制并发性。但是,将API响应恢复到原始流中似乎并非易事。另外,在这样的构造中保持背压似乎很复杂。

另一种选择是使用传统的信号量,但我不确定它的阻塞行为是否适合Rx。

那么有一个既定的模式来实现这样的东西?或者我错过了一个聪明的运算符组合,完全避免了这些复杂性?

2 个答案:

答案 0 :(得分:0)

在RxJava中,您可以从常规Java执行程序创建自己的调度程序:

ExecutorService exec= Executors.newFixedThreadPool(2); //2 Fixed threads
Schedulers.from(exec);

因此,只需为每个资源创建一个具有有限数量线程的执行程序,并在访问资源时使用该特定调度程序。有限数量的线程将限制并发呼叫的数量。

编辑:

显然我误解了这个问题。如果呼叫是异步的,您可以尝试使用Rx的背压来管理它们。以下是关于如何使用Rx管理此类调用的想法:

您创建了一个"资源许可可观察的"只要调用API ,就会发出某种东西(某种代币)。其创建令牌(许可)的速率将是该API的最大使用率。每当一些observable需要调用API时,只需压缩调用带有permit observable的调用。 Zip运算符将阻塞,直到许可证可用,将API调用限制为允许生成速率

这是一个发布时间戳的permit observable的简单实现:

public class PermitObservable extends Observable<Long> {

    private final long msBetweenEmissions;

    public PermitObservable(long msBetweenEmissions) {
        super(new SyncOnSubscribe<Long, Long>() {
            @Override
            protected Long generateState() {
                return System.currentTimeMillis();
            }

            @Override
            protected Long next(Long state, Observer<? super Long> observer) {
                long nextEmissionAt = state + msBetweenEmissions;
                long timeToWait = nextEmissionAt - System.currentTimeMillis();
                if (timeToWait > 0) {
                    try {
                        Thread.sleep(timeToWait);
                    } catch (InterruptedException e) {
                        observer.onError(e);
                    }
                }
                long now = System.currentTimeMillis();
                observer.onNext(Long.valueOf(now)); // Permit emission
                return now;
            }
        });

        this.msBetweenEmissions = msBetweenEmissions;
    }
}

答案 1 :(得分:0)

签出Scheduler.when()。它允许用户从现有调度程序构建修改后的调度程序,而不用创建新的线程池。像使用Schedulers.io()一样,但限制活动线程的数量。或限制Schedulers.computation()上onNexts的数量。