改進基於filter的遠程分佈式session存儲

<!--StartFragment-->

 

參考了網上一些資料,實現了session通過filter存儲到memcached服務器上.

(參見: http://ooft.javaeye.com/blog/537841 )

實現方式:

a)    通過MemcachedSessionFilter過濾器攔截cookie,取得的sessionId,通過sessionId構造新的HttpServletRequestWrapper對象,傳給後面的應用.

b)    繼承重構HttpServletRequestWrapper,HttpSessionWrapper類,覆蓋原來和session存取相關的方法呢,都通過SessionService類來實現.

c)    SessionService連接memcached服務,以sessionId作爲key,存取的對象是一個map.map的內容即爲session的內容.

d)    讀取數據時,先通過sessionId從memcached服務器上獲取整個map對象,再以session的attributeName作爲key從map中獲取數據對象.寫數據的方式與讀數據類似,先獲取map,然後修改map中的值,然後將整個map保存到memcached服務器上.

改進內容:

(1)    使用xmemcached客戶端代替java memcached client.

XMemcached同樣是基於java nio的客戶端,java nio相比於傳統阻塞io模型來說,有效率高(特別在高併發下)和資源耗費相對較少的優點。

 

(2)    對修改和刪除session屬性時,使用cas方法實現,防止在併發時出現數據覆蓋的問題.

 

原來的代碼:

Java代碼 複製代碼
  1. public void saveSession(String id, Map session) {   
  2.   
  3.  long s1= System.currentTimeMillis();   
  4.   
  5.  MemCachedClient mc = this.getMemCachedClient();   
  6.   
  7.  mc.replace(id, session);   
  8.   
  9.  System.out.print("saveSession");   
  10.   
  11.  System.out.println(System.currentTimeMillis() -s1);   
  12.   
  13. }  
public void saveSession(String id, Map session) {

 long s1= System.currentTimeMillis();

 MemCachedClient mc = this.getMemCachedClient();

 mc.replace(id, session);

 System.out.print("saveSession");

 System.out.println(System.currentTimeMillis() -s1);

}

 

 

 

  其中保存進去的session是一個通過get方法從memcached上獲取的map對象,map中的值修改以後,map對象替換服務器上的對象.如果在多臺機器併發的情況下,很可能出現一個線程寫進去的數據被其它的覆蓋.

 

改進後的代碼:

   Memcached是通過cas協議實現原子更新,所謂原子更新就是compare and set,原理類似樂觀鎖,每次請求存儲某個數據同時要附帶一個cas值,memcached比對這個cas值與當前存儲數據的cas值是否相等,如果相等就讓新的數據覆蓋老的數據,如果不相等就認爲更新失敗,這在併發環境下特別有用。

Java代碼 複製代碼
  1. public void saveSession(String id,String key, Object arg1) {   
  2.     long s1= System.currentTimeMillis();   
  3.     final String k=key;   
  4.     final Object o=arg1;   
  5.   
  6.     try {              
  7.            mc.cas(id,0,new CASOperation<Map>(){   
  8.         //嘗試更新5次   
  9.         public int getMaxTries() {   
  10.             return 5;   
  11.         }                  
  12.         public Map getNewValue(long currentCAS, Map map) {   
  13.             map.put(k, o);   
  14.             return map;   
  15.         }});   
  16.            System.out.print("saveSession");        
  17.     }      
  18.     finally{   
  19.         System.out.println(System.currentTimeMillis() -s1);   
  20.     }   
  21. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章