guava緩存批量獲取的一個坑

摘要

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

背景

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

對於的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,走到批量查詢數據庫中。bash

分析解決

  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來加載數據的。app

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

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

搜索了下,github.com/google/guav… github上這個issue還在。汗!!!性能

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

總結

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

關注公衆號【方丈的寺院】,第一時間收到文章的更新,與方丈一塊兒開始技術修行之路

在這裏插入圖片描述
相關文章
相關標籤/搜索