You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在RxJava中实现条目缓存并避免缓存雪崩?

解决RxJava结合Caffeine缓存的异步加载与缓存雪崩问题

嘿,这个场景我太熟悉了!之前也遇到过同步缓存转RxJava异步流的需求,刚好可以结合Caffeine的异步API完美解决,同时还能保持它防缓存雪崩的特性。

核心思路

Caffeine本身提供了异步加载缓存的能力(AsyncLoadingCache),它和同步版本一样,会自动保证同一个Key的并发请求只会触发一次加载逻辑,从根源上避免缓存雪崩。我们只需要把RxJava的Single和Caffeine的CompletableFuture做个适配就行——毕竟两者都是异步结果的载体,转换起来很丝滑。

具体实现步骤

  1. 替换为异步缓存实例
    把原来的同步LoadingCache换成AsyncLoadingCache,并在构建时指定异步加载逻辑:

    // 初始化异步缓存,配置你需要的缓存策略(过期、容量等)
    AsyncLoadingCache<GUID, Entity> entityCache = Caffeine.newBuilder()
        .maximumSize(1000) // LRU最大容量
        .expireAfterWrite(10, TimeUnit.MINUTES) // 写入后10分钟过期
        .buildAsync((entityId, executor) -> 
            // 把RxJava的Single转换成CompletableFuture,交给Caffeine处理
            longLoadFromDatabase(entityId).toFuture()
        );
    
  2. 封装RxJava风格的查询方法
    从异步缓存获取CompletableFuture,再转成Single返回给调用方:

    Single<Entity> getEntity(GUID entityId) {
        // 将Future转换为RxJava的Single,适配响应式编程模型
        return Single.fromFuture(entityCache.get(entityId));
    }
    

为什么这样能解决缓存雪崩?

和你之前用的同步get方法一样,AsyncLoadingCache内部会自动处理并发请求:当多个线程(或RxJava订阅)同时请求同一个未缓存的Key时,Caffeine只会调用一次longLoadFromDatabase,所有请求共享同一个加载结果,完全避免了缓存失效时的数据库流量暴增。

额外注意点

  • 异常处理:如果longLoadFromDatabase返回的Single触发了错误,这个异常会被自动传递到CompletableFuture中,最终通过Single的onError回调抛出,完全符合RxJava的错误处理机制。
  • 缓存刷新:如果需要主动刷新某个Key的缓存,可以调用entityCache.refresh(entityId),它会异步重新加载缓存,不会阻塞当前的查询请求。
  • 线程调度:Caffeine的异步加载默认使用ForkJoinPool,但你也可以在buildAsync的第二个参数executor指定自定义线程池,和RxJava的线程调度配合使用。

内容的提问来源于stack exchange,提问作者Alex Kokorin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:50:51