摘自:http://snowolf.iteye.com/blog/1576818,感謝作者。
爲了將N個前端數據同步,通過Memcached完成數據打通,但帶來了一些新問題:
- 使用iBatis整合了Memcached,iBatis針對每臺server生成了唯一標識,導致同一份數據sql會產生不同的key,造成重複緩存。——通過重寫iBatis部分原碼,終止了唯一標識的生成,同一個SQL產生同一個Key,同時對生成key做hash,控制長度,使得數據統一在Memcached。
- 爲了迎合iBatis的架構,通過CacheModel模式,對緩存數據分組管理。最初通過Map實現CacheModel,就是簡單的Key對應最終的Object。爲了後臺操作數據時,前臺能及時響應,以CacheModel爲基準點。後臺操作數據時,做Flush,清空對應的CacheModel,可以及時同步數據。但,由於前後臺Domain對象可能不一致,調用CacheModel(Map)反序列化時,發生ClassNotFonudException(CNF)。——將CacheModel的Map實現改爲Set,CacheModel僅存需要Flush掉的key,Object按原有方式緩存。
- 以前一直用EhCache,也很少會把List<List>這樣的重量級對象放進緩存裏。即便如此,只要EhCache沒有拋異常,我們恐怕也無感知。這次改用Memcached,沒有注意到緩存List過大,導致“Cannot cache data larger than 1MB memcached”,即緩存對象體積不能超過1MB——使用Memcached數據壓縮,優化SQL,可以暫時維持
說了這麼多,簡要總結如下:
- Memcached的Key,要杜絕使用空格,且長度控制在250個字符。
- Memcached的Value,要控制體積,必須小於1MB,必要時進行使用壓縮。
- 失效時間,0爲永久有效,最大值不得超過30天(2592000s),否則重新計算可能緩存只有1秒
- Memcached僅支持LRU算法,完全適用你的需要。
- 儘量不要將List這種重體積對象扔到Memcached中,傳輸、存儲都會產生瓶頸。
- 使用一致性哈希算法實現,提高多個Memcacehd Server利用率。
關於使用XMemcached實現時,參考如下實現:
- private MemcachedClientBuilder createMemcachedClientBuilder(
- Properties properties) {
- String addresses = properties.getProperty(ADDRESSES).trim();
- if (logger.isInfoEnabled()) {
- logger.info("Configure Properties:[addresses = " + addresses + "]");
- }
- MemcachedClientBuilder builder = new XMemcachedClientBuilder(
- AddrUtil.getAddresses(addresses));
- // 使用二進制文件
- builder.setCommandFactory(new BinaryCommandFactory());
- // 使用一致性哈希算法(Consistent Hash Strategy)
- builder.setSessionLocator(new KetamaMemcachedSessionLocator());
- // 使用序列化傳輸編碼
- builder.setTranscoder(new SerializingTranscoder());
- // 進行數據壓縮,大於1KB時進行壓縮
- builder.getTranscoder().setCompressionThreshold(1024);
- return builder;
- }
主要有以下幾點參考:
- 使用二進制文件模式
- 使用一致性哈希算法
- 使用序列化編碼
- 對數據進行壓縮
關於SET&ADD
- SET&ADD都屬於更新操作,都要先申請內存
- SET,會擦除這個鍵所對應的內存,不管原先是否有內容
- ADD,會先查看這個鍵對應的內存是否有內容,如果有,則等待;若沒有,則獲取鎖,並更新內存。
緩存命中率,通常認爲:緩存命中率低於95%的設計都是不合理的,存在設計缺陷的。