Caffeine批量加载浅析

摘要:
最近项目中的本地缓存从Guava更改为Caffeine。据说表现更好。既然性能更好,就让我们使用它吧。在实际测试中,发现无论如何缓存,都使用以下缓存初始化方法。getAll方法发现数据总是从load方法加载的,并且批量采集被更改为单周期采集。这导致数十个Redis命令被发送到Redis集群,导致网络浪费和性能差异:batchNumCache=Cache。newBuilder()。initialCapacity。maximumSize。refreshAfterWrite构建(newCacheLoader<Long,Map<String,Integer>(){@OverridepublicMap<String、Integer>加载(LongbatchId)throwsException{returngetBatchNumJimdb(batchId;}@OverridepublicMap<Long,Map<String,Integer>>loadAll(Iterable<?

最近项目中的本地缓存,看是从Guava改成了Caffeine,据说是性能更好,既然性能更好的话,那么就用起来吧。不过在使用过程中,发现了单个load和批量loadall方面的一些小设置,记录一下。

一般说来,我们获取单条记录的时候,一般都是 cache.get(id),当数据过期,会从提前设定好的load方法中获取数据。

同样的,如果我们想批量获取记录的时候,一般都是用cache.getAll(ids),当数据过去,会从提前设定好的loadAll方法中获取数据。

实际在测试的时候,发现,利用如下的缓存初始化方式,无论怎么泡cache.getAll(ids)方法,发现总会从load方法中加载数据,硬生生的把批量获取变成了单个循环获取,这就导致几十个redis命令一起发到redis集群那边,造成了网络浪费和性能差异:

 batchNumCache = Caffeine.newBuilder()
                .initialCapacity(cacheSize)
                .maximumSize(cacheSize)
                .refreshAfterWrite(cacheTime, TimeUnit.SECONDS)
                .build(new CacheLoader<Long, Map<String, Integer>>() {

                    @Override
                    public Map<String, Integer> load(Long batchId) throws Exception {
                        return getBatchNumJimdb(batchId);
                    }

                    @Override
                    public Map<Long, Map<String, Integer>> loadAll(Iterable<? extends Long> batchIds) throws Exception {
                        if (Iterables.isEmpty(batchIds)) {
                            return null;
                        }
                        return getAllBatchNumJimdb(Lists.newArrayList(batchIds));
                    }
                });

如上代码可以看出,load方法会调用getBatchNumJimdb加载数据,而loadAll方法会调用getAllBatchNumJimdb加载数据,getAllBatchNumJimdb加载数据的方式就是利用redis的pipeline,一次性将请求发给redis,然后获取返回结果。

虽然如上代码不能按照我们既定的方式工作,那么肯定配置有些什么问题,后来经过诸多的ut测试,发现设置上expireAfterWrite属性,整体就完美了。最终代码如下:

batchNumCache = Caffeine.newBuilder()
                .initialCapacity(cacheSize)
                .maximumSize(cacheSize)
                .refreshAfterWrite(cacheTime, TimeUnit.SECONDS)
                .expireAfterWrite(cacheTime, TimeUnit.SECONDS)
                .build(new CacheLoader<Long, Map<String, Integer>>() {

                    @Override
                    public Map<String, Integer> load(Long batchId) throws Exception {
                        return getBatchNumJimdb(batchId);
                    }

                    @Override
                    public Map<Long, Map<String, Integer>> loadAll(Iterable<? extends Long> batchIds) throws Exception {
                        if (Iterables.isEmpty(batchIds)) {
                            return null;
                        }
                        return getAllBatchNumJimdb(Lists.newArrayList(batchIds));
                    }
                });

如上代码,整体就ok了。当使用cache.get的时候,会从load加载,当使用cache.getall的时候,会从loadall加载。

免责声明:文章转载自《Caffeine批量加载浅析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用自增主键、UUID的优缺点VS2019配置MKL教程(Windows)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

kibana数据操作

ES中的索引数据将存储为_分数:分数越高,匹配越好。即使Lucene使用了反向索引,计算搜索得分仍需要一些时间。②.— 筛选器上下文:使用筛选器参数时的执行环境,例如在布尔查询中使用Must _ Not或Filter。在筛选器上下文中,查询将回答此问题...

Json 的日期格式转化(时区标准化)

在JavaScript中,这无疑可以通过初始化Data()对象//converttomsecsinceJan11970localTime=d轻松完成。获取时间();步骤2:接下来,通过Data()对象的getTimezoneOffset()方法//obtainlocalUTCoffsetandconverttomseclocalOffset=d找出本地时间偏...

Android Exception 10(server)' ~ Channel is unrecoverably broken and will be disposed!)

08-1119:22:35.028:W/MemoryDealer(2123):madvise(0x43e1600012288,MADV_REMOVE)返回操作不支持传输端点08-1119:22-35.038:W/InputDispatcher(2714):channel'4236b890com.tongyan.activi...

PbootCMS后台增加轮播图自定义分组名称

我们知道,在PbootCMS后台的旋转木马图形模块中,当添加新的旋转木马图时,您不能自己选择组。相反,您可以自动创建组,例如组1、组2和组3。这显然对客户的体验不友好,而且您无法直观地知道在网页的哪个位置使用了旋转木马图。让我们分享一下如何启用PbootCMS后台来添加、删除和修改旋转木马图形组。...

前端导航站点(PC端)

本篇LIST1.项目预览地址:项目预览地址2.项目完成效果:3.HTML布局拆分1.tip提示部分2.title标题部分3.搜索栏部分找的是codepen上现成的搜索框样式,包含搜索框展开收缩的特效。...

狼人杀规则

自爆后,所有演讲立即暂停,进入夜间。自爆后的那晚,狼人可以指着那把刀。预言家只能验证某个玩家是否是狼人,除狼人是否是狼人之外的所有信息都无法验证。如果先知测试丘比特,法官不必担心丘比特是哪一个阵营,只会展示好人的手势。...