做過的項目中Hibernate都是直接采用ehcache做為緩存,ehcache是一個好東西,采用內存+文件系統 結合可以勝任大多數情況,而且Hibernate和ehcache簡直就是天造地設的一對,配合非常之默契。
但是在集群環境下緩存不同步的問題日益凸顯,盡管最新版本的ehcache已經支持通過multicast來實 現不同進程的緩存數據同步的功能,這樣的結構在集群的節點很多的時候性能下降得厲害,而且也不清楚 其穩定性如何,因此ehcache暫且擱下。
對memcached早有耳聞,它是一種采用客戶端服務器工作模式的集中式緩存系統,在很多非常大的網站 中被采用。之前試過Java版的客戶端API,發現問題多多容易出錯,由於同步的問題導致性能也超級差。 最近Java的客戶端API發布了新的版本,再次試用已不可同日而語,於是開始在項目中編寫Memcached的 CacheProvider供Hibernate使用,使用過程中碰到一些問題,現在把這些問題的中心思想寫出來,希望對 大家有所幫助。
首先ehcache和memcached的結構是完全不相同的。一個ehcache緩存系統可以同時定義多個cache,每 個cache使用key-value方式存儲數據,而memcahced只有key-value,它是一個大的哈希表。因此當我們在 Hibernate配置了多個緩存的時候在memcached就會出現問題,這些問題具體表現出來的異常是 ClassCastException,因為不同的對象使用同一個key進行緩存數據的讀寫。這在ehcache中是沒有問題的 ,因為這就是ehcache的結構。由此,為了讓Hibernate使用memcached緩存系統,我們需要在Provider這 個級別上對緩存的key進行包裝,我們可以將Hibernate傳遞過來的緩存名跟key結合起來生成一個新的key ,讀寫緩存數據都是用這個key,這樣就不會發生緩存數據沖突導致的異常。
還有另外一個問題是關於查詢的緩存,當我們執行一個稍微復雜點的HQL語句並對這個語句的執行禁果 進行緩存的時候可能會出錯,這些錯誤的原因就是key的內容包含某些memcached通訊協議上定義的字符導 致memcached在解析協議的時候出現異常,因此還是使用前面提到的方法,對key進行二次包裝。做法不外 乎兩種:直接將key轉成hashcode然後把hashcode做為新的key;如果擔心生成的hashcode可能會重復(事 實上這個可能性微乎其微),那還可以用MD5算法生成新的字符串來做為key,這樣就不用擔心我們的key 存在一些memcached保留的字符而導致錯誤。
經過如此改造後,直接將DLOG4J改為memcached做為緩存系統,到目前未知還沒發現什麼問題,運行非 常良好。
詳細的使用方法請查看MemcachedCacheProvider.java中的注釋
本文配套源碼:http://www.bianceng.net/java/201212/800.htm