guava緩存批量獲取的一個坑

摘要

Guava Cache是Google開源的Java工具集庫Guava裏的一款緩存工具,一直覺得使用起來比較簡單,沒想到這次居然還踩了一個坑

背景

功能需求抽象出來很簡單,就是將數據庫的查詢sthMapper.findById(Long id)的結果緩存起來。但同時還有批量請求,爲了提高效率,肯定要批量查詢數據庫,sthMapper.findByIds(Collection<Long> ids)

對於的guava cache 處理類

  // 定義guava緩存
  public SthCache() {
        sthCache = CacheBuilder.newBuilder()
                .maximumSize(SIZE)
                .refreshAfterWrite(3, TimeUnit.SECONDS)
                .build(new CacheLoader<Long, List<Long>>() {
                    @Override
                    public List<Long> load(final Long id) {
                        return doLoad(Arrays.asList(id)).get(id);
                    }

                    @Override
                    public Map<Long, List<Long>> loadAll(
                            final Iterable<? extends Long> ids)
                            throws Exception {
                        return doLoad(Lists.newArrayList(ids));
                    }
                });
    }
// 實際從數據庫中加載數據
private Map<Long, List<Long>> doLoad(final List<Long> ids) {
    return sthMapper.findByIds(ids);
} 
// 批量獲取數據
 public Map<Long, List<Long>> getSthById(final List<Long> ids) {
        return sthCache.getAll(ids);
    
    }

沒毛病,getAll(Iterable<? extendsK>)方法用來執行批量查詢。默認情況下,對每個不在緩存中的鍵,getAll方法會單獨調用CacheLoader.load來加載緩存項。如果批量的加載比多個單獨加載更高效,你可以重載CacheLoader.loadAll來利用這一點。getAll(Iterable)的性能也會相應提升。這邊定義了loadAll效率高了。

問題

在debug的時候發現確實走的loadAll,批量查詢數據庫。但是上線後,線上監控數據卻發現這個接口耗時很長,通過分析,發現有很多sthMappper.findByIds()的單個查詢。也就是說,並沒有調用loadAll,走到批量查詢數據庫中。

分析解決

  1. 首先看了下guava的代碼實現
ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
   int hits = 0;
   int misses = 0;
   // 省略一大坨
   try {
     if (!keysToLoad.isEmpty()) {
       try {
       // 調用loadAll
         Map<K, V> newEntries = loadAll(keysToLoad, defaultLoader);

批量查詢時,對於沒有命中的,確實調用的loadAll來加載數據的。

那問題就不是這邊了。在load()方法打了個斷點,原因就找到了。

原來是refesh的時候,加載的。refreshAfterWrite 刷新緩存數據時調用的還是load方法。

搜索了下,https://github.com/google/guava/issues/1975 github上這個issue還在。汗!!!

最後我這邊解決是用Spring Cache統一了緩存管理。

總結

對於開源庫的使用不可只知其然,不知其所以然。

關注公衆號【方丈的寺院】,第一時間收到文章的更新,與方丈一起開始技術修行之路
在這裏插入圖片描述

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