最近項目中的本地緩存,看是從Guava改爲了Caffeine,聽說是性能更好,既然性能更好的話,那麼就用起來吧。不過在使用過程當中,發現了單個load和批量loadall方面的一些小設置,記錄一下。css
通常說來,咱們獲取單條記錄的時候,通常都是 cache.get(id),當數據過時,會從提早設定好的load方法中獲取數據。html
一樣的,若是咱們想批量獲取記錄的時候,通常都是用cache.getAll(ids),當數據過去,會從提早設定好的loadAll方法中獲取數據。redis
實際在測試的時候,發現,利用以下的緩存初始化方式,不管怎麼泡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屬性,總體就完美了。最終代碼以下:ide
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加載。性能