Memcached Client 使用手冊

y_keven發表於2013-10-29

Memcached Client 使用手冊
Author: cenwenchu
Email: wenchu.cenwc@alibaba-inc.com
Blog:http://blog.csdn.net/cenwenchu79/
Project: http://code.google.com/p/memcache-client-forjava/


Cache Client介面定義
 
圖 1 Memcached Cache Client介面類圖

 ICache和IMemcachedCache介面是Cache的基礎介面,定義了基本的Cache操作,詳細地說明參看附錄,使用方式參看Demo和使用注意。ICacheManager是Cache生命週期管理類,一個應用只需要一個ICacheManager來管理所有的Cache,具體介紹參看Cache Demo中的Cache Manager介紹。

Cache Client依賴及配置
Cache Client第三方依賴
commons-logging-1.0.4.jar or high version
log4j-1.2.12.jar or high version
codehaus/woodstox/wstx-asl-3.2.1.jar or high version
codehaus/staxapi/stax-api-1.0.1.jar or high version

 2.5.2版本以後還需要caucho/hessian/hessian-3.2.0.jar or high version

Cache Client支援預設(在Classpath中查詢Memcached.xml作為客戶端配置)和指定配置檔案。配置檔案是Cache Client的正常執行的基礎,系統如果要在執行中使用Cache Client的話,必須在使用前(一般最好是應用啟動時)初始化Cache Client元件(讀取配置檔案,建立連線池等等)。具體使用方式可以參看後面章節中的Demo。
Cache Client單客戶端配置
<?xml version="1.0" encoding="UTF-8"?>
<memcached>
      <client name="mclient0" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool0">
         <errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>      </client>
<socketpool name="pool0" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="5000"
           nagle="false" socketTO="3000" aliveCheck="true">
          <servers>10.2.224.36:33001,10.2.224.46:33001</servers>
   <weights>3,7</weights>
      </socketpool>
</memcached>
建立memcached的標籤。
建立 client的標籤。
注意:
name 屬性是程式中使用Cache的唯一標識。
socketpool 屬性將會關聯到後面的socketpool配置。
errorHandler 可選,用來處理出錯情況。注意在Tag中不要使用空格或者Tab鍵。
建立socketpool的標籤。
注意:
name 屬性和client 配置中的socketpool 屬性相關聯。
maintSleep屬性是後臺執行緒管理SocketIO池的檢查間隔時間,如果設定為0,則表明不需要後臺執行緒維護SocketIO執行緒池,預設需要管理。
socketTO 屬性是Socket操作超時配置,單位ms。
aliveCheck 屬性表示在使用Socket以前是否先檢查Socket狀態。
建立 servers 標籤作為socketPool的子標籤.設定memcache服務端例項地址,支援多個地址設定,例如“10.2.224.36:33001” 或 “10.2.224.36:33001, 10.2.224.46:33002”.
建立 weights 標籤作為socketPool的子標籤(可選),它表明了上面設定的伺服器例項的Load權重. 例如 <weights>3,7</weights> 表示30% load 在 10.2.224.36:33001, 70% load 在 10.2.224.46:33001

好了,基礎的配置就如上。現在可以直接到後面章節去學習使用Memcache客戶端,或者繼續看如何配置Cluster。


Cache Client叢集配置
<?xml version="1.0" encoding="UTF-8"?>
<memcached>
      <client name="mclient0" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool0">
         <errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
      </client>
  <client name="mclient0-bck" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool0-bck">
         <errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
      </client>
<socketpool name="pool0" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="5000"
           nagle="false" socketTO="3000" aliveCheck="true">
          <servers>10.2.224.36:33001,10.2.224.46:33001</servers>
      </socketpool>
<socketpool name="pool0-bck" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="5000" nagle="false" socketTO="3000" aliveCheck="true">
          <servers>10.2.224.36:33002,10.2.224.46:33002</servers>
      </socketpool>

<cluster name="cluster1" mode="active">//mode = active,standby
          <memCachedClients> mclient0, mclient0-bck</memCachedClients>
      </cluster>
</memcached>
 
 Memcache是集中式的Cache,因此它存在單點問題(雖然資料可以分散到多臺伺服器上,但是還會丟失部分資料)。為了解決單點問題,Memcache客戶端支援配置叢集。
 叢集配置很簡單. 1.建立cluster標籤 2. 建立memCachedClients 標籤作為cluster的子標籤,然後將客戶端配置到memCachedClients 標籤中。3.可以配置cluster mode(如果沒有設定mode屬性,預設採用active)。
 叢集當前的特性:
叢集中多節點軟負載均衡。(當前採用簡單的Hash演算法加取餘來分發資料)
資料在多節點上非同步冗餘儲存。(防止資料丟失最基本要求)
節點不可用切換功能。(當根據演算法分發到某一失敗節點時可以轉向到其他可用節點)
節點恢復可用後資料Lazy複製。(當A,B兩臺機器作為叢集的時候,如果A出現了問題,系統會去B獲取資料,當A正常以後,如果應用在A中沒有拿到資料可以去B獲取資料,並且複製到A上,這種方式也是一種lazy的複製。)

 


Cache Client Demo
 在Google專案中有sample包,內部包含了測試用例和測試所需要的配置檔案(配置檔案中的具體伺服器埠和地址需要自己修改)。

下載地址為:http://memcache-client-forjava.googlecode.com/files/alisoft-xplatform-asf-cache-sample%282.5version%29.zip

類IMemcachedCacheTest是Cache功能單元測試類。
類StressCacheTest是Cache壓力測試類。
類MemcachedClusterTest是Cache叢集測試類。

Cache Manager
 在使用Cache Client的應用中都需要有一個Cache Manager來管理各個Cache Client的生命週期。Cache Manager通過讀取配置初始化各個Cache Client,應用通過Cache Manager獲取到Cache Client進行資料互動。Cache Manager結束後,Cache Client也就被結束並釋放。Cache Manager也可以動態的重新載入配置檔案,實現動態擴容。
 建議一個應用只需要設定一個Cache Manager,在應用啟動時將Cache Manager啟動,在應用結束時將Cache Manager結束。測試用例程式碼如下:

static ICacheManager<IMemcachedCache> manager;//可以直接設定為靜態的單例

 @BeforeClass
 public static void setUpBeforeClass() throws Exception
 {
  manager = CacheUtil.getCacheManager(IMemcachedCache.class,
   MemcachedCacheManager.class.getName());//manager初始化,可以通過配置來替換CacheManager實現
  manager.setConfigFile("memcached1.xml");//設定Cache Client配置檔案
  manager.setResponseStatInterval(5*1000);//設定Cache響應統計間隔時間,不設定則不進行統計
  manager.start();//Manager啟動
 }

 @AfterClass
 public static void tearDownAfterClass() throws Exception
 {
  manager.stop();//manager結束
 }


通過manager.reload("memcached_cluster2.xml");可以實現動態擴容,同時支援將memcached_cluster2.xml為http://10.2.226.41/sip/memcached_cluster2.xml,實現遠端獲取配置。具體使用,請參看叢集測試用例中的程式碼。(請注意測試用例中的sleep程式碼,這些是系統在關閉和啟動時的延時)

使用注意
使用Clear方法時,如果立即去獲取資料可能會因為回收速度問題導致獲取到被刪除的資料,需要有部分的延時,採用sleep來避免問題發生。
Manager的reload會重新載入配置,但是對於服務端的資料不會刪除,因此需要注意新的配置中叢集資料相互拷貝問題。同時reload以後對於cache client需要重新獲取物件,否則保留的還是原來的cache client,將無法使用。(資料複製採用lazy的方式,如果需要立即全部重新分配,可以採用Manager的ClusterCopy介面實現)
對於get,put聯合操作的一些場景,建議採用計數器來實現原子操作。(計數器需要通過getCounter,storeCounter,incr,decr等等介面來操作,不是普通的get,put操作)
可以使用add,replace來滿足一些需要對內容是否儲存有不同策略的場景。
使用本地Cache和Memcached Cache組合的情況中,在快取資料到本地以後,如果對此資料作了修改,會讓本地快取失效,但是無法通知到其他應用或者其他伺服器的本地快取。
叢集的active和standby兩種模式,前者速度可能在某些情況下稍慢(當key的確沒有存在於叢集任何一節點時,active模式會去嘗試兩個節點獲取資料),但是具有資料恢復功能,後者速度比較快,但是沒有資料恢復功能。


附錄:
介面定義說明:
/**
 * Cache統一介面
 * @author wenchu.cenwc
 *
 */
public interface ICache<K,V>
{
 /**
  * 儲存資料
  * @param key
  * @param value
  * @return
  */
 public V put(K key,V value); 
 
 /**
  * 儲存有有效期的資料
  * @param key
  * @param value
  * @param 有效期(取的是客戶端時間)
  * @return
  */
 public V put(K key,V value, Date expiry);
 
 /**
  * 儲存有有效期的資料
  * @param key
  * @param value
  * @param 設定有效期為距離當前時間後TTL秒。
  * @return
  */
 public V put(K key,V value, int TTL);
 
 /**
  * 獲取快取資料
  * @param key
  * @return
  */
 public V get(K key);
 
 /**
  * 移出快取資料
  * @param key
  * @return
  */
 public V remove(K key); 
 
 /**
  * 刪除所有快取內的資料
  * @return
  */
 public boolean clear();
 
 /**
  * 快取資料數量(Memcached介面當前不支援)
  * @return
  */
 public int size();
 
 /**
  * 快取所有的key的集合
  * @return
  */
 public Set<K> keySet();
 
 /**
  * 快取的所有value的集合
  * @return
  */
 public Collection<V> values();
 
 /**
  * 是否包含了指定key的資料
  * @param key
  * @return
  */
 public boolean containsKey(K key);
 
 /**
  * 釋放Cache佔用的資源
  */
 public void destroy();
}

/**
 * Memcached Cache的介面定義
 * @author wenchu.cenwc<wenchu.cenwc@alibaba-inc.com>
 */
public interface IMemcachedCache extends ICache<String,Object>
{
 /**
  * 降低memcache的互動頻繁造成的效能損失,因此採用本地cache結合memcache的方式
  * @param key
  * @param 本地快取該資料有效秒數
  * @return
  */
 public Object get(String key,int localTTL);
 
 /**
  * 獲取多個keys對應的值
  * @param keys
  * @return
  */
 public Object[] getMultiArray(String[] keys);
 /**
  * 獲取多個keys對應的key&value Entrys
  * @param keys
  * @return
  */
 public Map<String,Object> getMulti(String[] keys);
 
 
 /**
  * key所對應的是一個計數器,實現增加inc的數量
  * @param key
  * @param inc
  * @return
  */
 public long incr(String key,long inc);
 
 /**
  * key所對應的是一個計數器,實現減少decr的數量
  * @param key
  * @param decr
  * @return
  */
 public long decr(String key,long decr);
 
 /**
  * key所對應的是一個計數器,實現增加inc的數量
  * @param key
  * @param inc
  * @return
  */
 public long addOrIncr(String key,long inc);
 
 /**
  * key所對應的是一個計數器,實現減少decr的數量
  * @param key
  * @param decr
  * @return
  */
 public long addOrDecr(String key,long decr);
 
 /**
  * 儲存計數器
  * @param key
  * @param count
  */
 public void storeCounter(String key,long count);
 
 /**
  * 獲取暫存器,-1表示不存在
  * @param key
  */
 public long getCounter(String key);
 
 
 /**
  * 這個介面返回的Key如果採用fast模式,
  * 那麼返回的key可能已經被清除或者失效,但是在記憶體中還有痕跡,如果是非fast模式,那麼就會精確返回,但是效率較低
  * @param 是否需要去交驗key是否存在
  * @return
  */
 public Set<String> keySet(boolean fast);
 
 /**
  * 統計伺服器的Slab的情況
  * @return
  */
 public MemcacheStatsSlab[] statsSlabs();
 
 /**
  * 統計Memcache使用的情況
  * @return
  */
 public MemcacheStats[] stats();
 
 /**
  * 統計Items的儲存情況
  * @param servers
  * @return
  */
 @SuppressWarnings("unchecked")
 public Map statsItems();
 
 /**
  * 統計Cache的響應時間(必需設定statisticsInterval大於0才會開始統計)
  * @return
  */
 public MemcachedResponse statCacheResponse();
 
 /**
  * 設定統計時間,單位為秒
  * @param checkInterval
  */
 public void setStatisticsInterval(long checkInterval);
 
 /**
  * 儲存資料,前提是key不存在於memcache中,否則儲存不成功
  * @param key
  * @param value
  * @return
  */
 public boolean add(String key,Object value); 
 
 /**
  * 儲存有有效期的資料,前提是key不存在於memcache中,否則儲存不成功
  * @param key
  * @param value
  * @param 有效期
  * @return
  */
 public boolean add(String key,Object value, Date expiry);
 
 
 /**
  * 儲存資料,前提是key必須存在於memcache中,否則儲存不成功
  * @param key
  * @param value
  * @return
  */
 public boolean replace(String key,Object value); 
 
 /**
  * 儲存有有效期的資料,前提是key必須存在於memcache中,否則儲存不成功
  * @param key
  * @param value
  * @param 有效期
  * @return
  */
 public boolean replace(String key,Object value, Date expiry); 

 /**
  * 非同步存入資料,當前立即返回,稍後存入資料
  * @param key
  * @param value
  */
 public void asynPut(String key,Object value);
 
 
 /**
  * 非同步累減計數器,不保證累減成功
  * @param key
  * @param decr
  */
 public void asynAddOrDecr(String key,long decr);
 
 /**
  * 非同步累加計數器,不保證累加成功
  * @param key
  * @param incr
  */
 public void asynAddOrIncr(String key,long incr);
 
 /**
  * 非同步累減計數器,不保證累減成功
  * @param key
  * @param decr
  */
 public void asynDecr(String key,long decr);
 
 /**
  * 非同步累加計數器,不保證累加成功
  * @param key
  * @param incr
  */
 public void asynIncr(String key,long incr);
 
 /**
  * 非同步儲存計數器,不保證儲存成功
  * @param key
  * @param count
  */
 public void asynStoreCounter(String key,long count);
}

相關文章