使用memcache緩存數據,減少對數據庫的直接訪問,提高網站性能已經成了各大網站最基本的技術.如何更好的提高memcache緩存的利用率及命中次數會在後面的blog中單獨介紹,本文主要探討爲何及如何使用本地緩存(java localcache)提高網站性能.
localcache與memcache性能比較
先來個本地緩存與memcache緩存的性能比較,有個直觀上的概念
Cache | 請求方式 | 次數 | 時間 | 平均 |
Localcache | hashmap中get請求 | 1億 | 1344ms | 0.00001344ms |
Memcache | 簡單的get請求,不做序列化 | 1萬 | 4437ms | 0.4437ms |
Db | 單表查詢(有索引) |
|
| 1-2ms |
以上測試在開發機器.生產環境採集的數據顯示memcache的一次請求大約在0.2ms左右,如果存儲的是java object,那算上發序列化的時間在0.5ms以上.與測試數據在同一個數量級上.
通過以上數據對比,可以得知localcache的效率比memcache高1萬倍以上.這個數字讓我對使用本地緩存充滿了極大的興趣.
使用localcache會帶來哪些問題
localcache有着極大的性能優勢,單機情況下,適當使用localcache會使程序的效率得到很大的提升.但在集羣環境下localcache就存在很多問題了,主要體現在多個jvm之間cache的同步問題.
有很多框架在這上面做了很多工作,比如ehcache ,主要是通過cache複製(copy或invalidate)來解決,大概的思路是使用消息多播機制,當一個jvm中的數據做了更新操作後,首先更新本jvm內的localcache,然後廣播消息,其他jvm接收到消息後更新自己的localcache. 但這種機制可能帶來併發操作時出現髒數據的問題,具體見Potential Issues with Replicated Caching.
其他cache產品也遇到類似的問題,不再一一介紹.
那有沒有很好的方法來解決localcache的同步問題,從而可以放心的品嚐localcache這塊"甜餅"呢?
這個問題我也很糾結,通過多種方案的組合及補償機制似乎可以實現一個完美的方案.但也註定成爲了一個複雜的方案.類似的方案可以有如下幾種:
1.localcache作爲一級緩存,通過廣播的方式同步緩存,同時設置緩存過期時間,以達到數據同步和出現髒數據後自動修復的功能.
2.localcache作爲一級緩存,數據更新後發送異步消息(MQ等),其餘localcache訂閱異步消息,並根據消息來同步緩存.
3.localcache作爲一級緩存,memcache中存放緩存變更的信息,定時任務定時獲取memcache的信息,並決定是否更新localcache.
4.localcache作爲一級緩存,每次從memcache中獲取數據更改的標記位,如果標記發生變化,更新localcache
以上的這些實現方案,都在一定程度上加大了架構的複雜性,當localcache中數據出現髒數據時,排查問題及清理數據都會變得複雜.
他人經驗之談
1.sohu早期使用廣播的方式(jgroup)同步localcache,結果經常會出現髒數據的問題,在後來的架構設計上乾脆摒棄了localcache(即使使用,也不再作數據同步),全部使用memcache.
2.taobao在生產環境也很少使用localcache同步,對於非敏感性數據,只是通過簡單的過期策略,來保證數據的一致性.
總結
集羣環境下對於敏感性要求不高的數據可以使用localcache,只配置簡單的失效機制來保證數據的一致性.
對敏感性高的數據直接使用集中式緩存,減低複雜度.
複雜方案看似完美的解決了問題,實際上性能和穩定性卻很可能大打折扣.
感謝William 、放翁提出的寶貴建議。