(翻譯)Google Guava Cache

devos發表於2016-05-29

翻譯自Google Guava Cache

This Post is a continuation of my series on Google Guava, this time covering Guava Cache. Guava Cache offers more flexibility and power than either a HashMap or ConcurrentHashMap, but is not as heavy as using EHCache or Memcached (or robust for that matter, as Guava Cache operates solely in memory). The Cache interface has methods you would expect to see like ‘get’, and ‘invalidate’. A method you won’t find is ‘put’, because Guava Cache is ‘self-populating’, values that aren’t present when requested are fetched or calculated, then stored. This means a ‘get’ call will never return null. In all fairness, the previous statement is not %100 accurate. There is another method ‘asMap’ that exposes the entries in the cache as a thread safe map. Using ‘asMap’ will result in not having any of the self loading operations performed, so calls to ‘get’ will return null if the value is not present (What fun is that?). Although this is a post about Guava Cache, I am going to spend the bulk of the time talking about CacheLoader and CacheBuilder. CacheLoader specifies how to load values, and CacheBuilder is used to set the desired features and actually build the cache.

 

這篇文章是我的Google Guava系列文章的延續,這次的主題是Guava Cache。Guava Cahce比HashMap和ConcurrentHashMap更靈活也更強大,但是又不像使用EHCache或者Memcached(因此也不像它們這麼健壯,因為Guava Cache只在記憶體中操作)那麼重量級。Guava Cache有你期待的介面,像是'get',以及'invalide'。一個你不會發現的方法是'put', 因為Guava Cache是“自填充”的,在請求時沒有出現的值會被抓取或者計算,然後儲存起來。所以'get'方法永遠不會返回null。公平地說,上邊一句並不是100%準確的。還有一個方法叫做‘asMap',把cache中的條目作為一個執行緒安全的map暴露出來。使用'asMap'並不會執行任何自填充操作,因此,如果值不存在的話,呼叫'get'會返回null(這麼做有啥意義呢?)儘管這篇blog是關於Guava Cache的,我也會花很多時間講CacheLoader和CacheBuilder。CacheLoader用來指明怎麼樣載入值,而CacheBuilder用於設定你想要的特性,並且實際用來建立cache。

CacheLoader

CacheLoader is an abstract class that specifies how to calculate or load values, if not present. There are two ways to create an instance of a CacheLoader:

  1. Extend the CacheLoader<K,V> class

  2. Use the static factory method CacheLoader.from

CacheLoader是一個抽象類,用來指明怎麼樣計算或者載入值,如果沒有發現的話(譯註:如果沒有在快取裡)。有兩種方法來建立一個CacheLoader的例項:

  1. 擴充套件CacheLoader<K,V>類
  2. 使用靜態工程方法CacheLoader.from

If you extend CacheLoader you need to override the V load(K key) method, instructing how to generate the value for a given key. Using the static CacheLoader.from method you build a CacheLoader either by supplying a Function or Supplier interface. When supplying a Function object, the Function is applied to the key to calculate or retrieve the results. Using a Supplier interface the value is obtained independent of the key.

如果你擴充套件CacheLoader,你需要覆蓋V load(K key)方法,來說明怎麼樣從一個指定的key生成value。使用靜態的CacheLoader.from方法來構造CacheLoader時,你或者提供一個Function介面或者Supplier介面(譯註:應該是說“實現了Function或者Supplier介面的物件")。當提供一個Function物件時,這個Function被用於根據key來計算或者獲取結果。使用一個Supplier介面時,value的獲取和key沒有關係。

CacheBuilder

The CacheBuilder is used to construct cache instances. It uses the fluent style of building and gives you the option of setting the following properties on the cache:

  • Cache Size limit (removals use a LRU algorithm)

  • Wrapping keys in WeakReferences (Strong references used by default for keys)

  • Wrapping values in either WeakReferences or SoftReferences (Strong references used by default)

  • Time to expire entires after last access

  • Time based expiration of entries after being written or updated

  • Setting a RemovalListener that can recieve events once an entry is removed from the cache

  • Concurrency Level of the cache (defaults to 4)

CacheBuilder被用來建立cache例項(譯註:是指被cache的例項)。它使用fluent style(譯註:就是.xx().xx().xx()的模式)來建立,使你可以指定cache的下列的屬性: 

  • Cache大小限制('移除'是使用LRU演算法)
  • 是否把keys包裝成WeakReference(預設對於key是使用strong reference(譯註:Java的弱引用和強引用))
  • 把值包裝成WeakReference或者SoftReference(預設使用strong reference)
  • 在最後訪問一個條目(譯註:entry,就是cache裡的kv對)後多長時間過這個條目過期(expire)
  • 在寫入或者更新以後多長時間這個條目過期
  • 設定一個RemovalListener,在一個條目過期以後,這個RemovalListener用來接收事件(譯註:指'哪個條目'過期了,這個事件)
  • cache的併發度(預設為4)

The concurrency level option is used to partition the table internally such that updates can occur without contention. The ideal setting would be the maximum number of threads that could potentially access the cache at one time. Here is an example of a possible usage scenario for Guava Cache.

併發度選擇用來在給內部的表做分割槽(譯註:指cache實現時,在內部儲存條目用的表),使得更新可以無競爭的進行。最理想的設定是有可能同時訪問這個cache的執行緒的數目。下面是一個可能使用Guava Cache的場景

public class PersonSearchServiceImpl implements SearchService<List<Person>> {

public PersonSearchServiceImpl(SampleLuceneSearcher luceneSearcher, SampleDBService dbService) {
        this.luceneSearcher = luceneSearcher;
        this.dbService = dbService;
        buildCache();
    }

    @Override
    public List<Person> search(String query) throws Exception {
        return cache.get(query);
    }

    private void buildCache() {
        cache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(1000)
                .build(new CacheLoader<String, List<Person>>() {
                    @Override
                    public List<Person> load(String queryKey) throws Exception {
                        List<String> ids = luceneSearcher.search(queryKey);
                        return dbService.getPersonsById(ids);
                    }
                });
    }
}

In this example, I am setting the cache entries to expire after 10 minutes of being written or updated in the cache, with a maximum amount of 1,000 entires. Note the usage of CacheLoader on line 15.

在這個例子中,我設定cache的條目會在寫入或者更新10分鐘後過期,最大數目數量是1000。注意第15行的CacheLoader的例子

RemovalListener

The RemovalListener will receive notification of an item being removed from the cache. These notifications could be from manual invalidations or from a automatic one due to time expiration or garbage collection. The RemovalListener<K,V> parameters can be set to listen for specific type. To receive notifications for any key or value set them to use Object. It should be noted here that a RemovalListener will receive a RemovalNotification<K,V> object that implements the Map.Entry interface. The key or value could be null if either has already been garbage collected. Also the key and value object will be strong references, regardless of the type of references used by the cache.

RemovalListener會在條目被從cache移除以後收到通知。這個通知可能源於手動地使條目失效,或者由於時間過期或者垃圾回收而自動地移除條目。RemovalListener<K,V>的型別引數可以被設定以監聽指定的型別。如果要接收任何的kv的通知,把它們設成Object。需要說明的是,RemovalListener會收到一個RemovalNotification<K,V>型別的物件,這個物件實現了Map.Entry介面。如果key或者value被垃圾回收了,那麼key和value可能會為null.而且key和value物件是是strong reference,不管在cache中的時候的reference的型別。

CacheStats

There is also a very useful class CacheStats that can be retrieved via a call to Cache.stats(). The CacheStats object can give insight into the effectiveness and performance of your cache by providing statistics such as:

有一個非常有用CacheStats類的物件,可以使用Cache.status()來獲取。CacheStats物件通過給你下面的統計,可以給出關於你的cache的效率和效能的洞察。

  • hit count  命中總數

  • miss count 未命中總數

  • total load time 總的載入時間

  • total requests 總的請求數目

CacheStats provides many other counts in addition to the ones listed above.

除了上邊列出的統計結果,CacheStatus還提供了很多其它的值。

Conclusion

The Guava Cache presents some very compelling functionality. The decision to use a Guava Cache really comes down to the tradeoff between memory availability/usage versus increases in performance. I have added a unit test CacheTest demonstrating the usages discussed here. As alway comments and suggestions are welcomed. Thanks for your time.

GuavaCache提供了一些非常有競爭力的功能。使用Guava Cache源於對可用/使用的記憶體以及效能的折衷。我新增了一個單元測試來展示這裡討論的使用情況。像往常一樣,歡迎評論和建議。謝謝你的時間。

 

相關文章