使用反应式编程将Couchbase文档从一个存储桶复制到另一个存储桶时出现OOM问题

时间:2019-03-05 08:32:08

标签: rx-java couchbase reactive

我们正在尝试使用反应式编程(大约一百万个文档)将数据从一个存储桶复制到另一个存储桶。在这段代码中,我们正在获得OOM。我不是rxjava专家,因此需要帮助以防止OOM。我认为读取的速度比写入的速度快,这是由于缓冲区已满导致的OOM。代码如下:

CountDownLatch countDownLatch5 = new CountDownLatch(1);
Observable
        .from(n1qlKeysForDocsGPC)
        .flatMap(new Func1<String, Observable<JsonDocument>>() {
            @Override
            public Observable<JsonDocument> call(String key) {
                return readPrimaryMainAsyncBucket
                        .get(key, 10, TimeUnit.SECONDS)
                        .onErrorResumeNext(readPrimaryMainAsyncBucket.get(key, 10, TimeUnit.SECONDS))
                        .retry(50)
                        .switchIfEmpty(Observable.empty())
                        .onErrorResumeNext(Observable.empty());
            }
        })
        .flatMap(new Func1<JsonDocument, Observable<JsonDocument>>() {
            @Override
            public Observable<JsonDocument> call(JsonDocument jsonDocument) {
                return readPrimaryBackupAsyncBucket.upsert(jsonDocument, 10, TimeUnit.SECONDS).retry(50);
            }
        })
        .last()
        .doOnTerminate(new Action0() {
            @Override
            public void call() {
                countDownLatch5.countDown();
            }
        })
        .subscribe();
try {
    countDownLatch5.await();
    logger.info("DataRecoverySchedulers | Completed countDownLatch5");
} catch (InterruptedException e) {
    e.printStackTrace();
}

1 个答案:

答案 0 :(得分:3)

3.x之前的Couchbase Java SDK版本(在撰写本文时尚未发布)使用RxJava版本1。

flatmap调用(如您现在所拥有的那样)将把操作发布到内部缓冲区以异步执行,并返回一个Observable来跟踪每个操作。这意味着第一个flatmap将无限制地消耗from调用的输出。换句话说,它将比操作快得多地读取整个列表。我希望您看到的OOM错误是由于超出了Couchbase内部缓冲区。

要解决此问题,可以使用flatmap的变体来限制未完成的订阅数。您只需在flatmap调用中添加第二个整数参数即可。因此,您必须.flatmap(new Func1<~>..., 10)一次将自己限制在10次出色的操作中。

Couchbase中的默认缓冲区大约有16000个出色的操作,但这远远超出了使大多数系统饱和所需的数量。

作为参考,请参阅与此相关的Stack Overflow post,有关限制文件上传的吞吐量。