Caffeine批量加載淺析

最近項目中的本地緩存,看是從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加載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章