J2EE集羣之failover小點子

J2EE集羣不太瞭解的人首先能夠看看附件裏面的《解開J2EE集羣的神祕面紗》, 講的挺好的。javascript

 

J2EE的服務器集羣主要的就是負載均衡 失敗轉移 這些。java

負載均衡這個話題都爛大街了,隨處能夠找到相關的帖子或博文,我也就不談了。編程

可是這些帖子中大部分都只談了負載均衡,頂多再說一下 Tomcat 的 HttpSession 複製(失敗轉移的一種解決方案吧)。更有甚者,直接決定「集羣中服務器節點宕機丟失的部分  HttpSession 不礙事」。。。緩存

 

個人感受就是,tomcat

像 Tomcat 的 HttpSession 交叉複製,若是集羣中服務器過多對性能的影響確定很是之大。服務器

像 JBoss、WebLogic 等的服務器鏈式 HttpSession 複製,若是一個服務器節點宕機,此節點的下一個服務器節點就得負責兩個服務器的用戶請求。是否是有點怕人奧。session

至於「集羣中某個節點宕機就宕機, HttpSession 丟失無所謂」這樣的觀點也是挺匪夷所思的,畢竟後臺中2000個 HttpSession 同時丟失的後果不是那麼容易承擔的。併發

 

 

爲了解決上面這些問題,我本身琢磨了一套方案,感受挺不錯的(不知道網上是否是有相似「輪子」,反正我是沒有搜索到)。 就發出來共享一下,嘿嘿app

我想到的是緩存服務器和Web服務器雙向備份HttpSession ,這個。。。。咱語文挺爛的,表達的很差。負載均衡

 

雙向備份就是集羣中多個Web服務器分散保存 HttpSession ,同時在緩存服務器中也分散保存這些 HttpSession (每一個 HttpSession 正常狀況下只須要複製一次),至於怎麼分散各位且聽我慢慢說來。

我使用了三個緩存服務器(Memcached),三個Web服務器(Tomcat)進行思路實現和測試。

先說說思路吧:    三個緩存服務器和三個Web服務器以下分佈

 

Tomcat_A Tomcat_B Tomcat_C
Memcached_A Memcached_B Memcached_C

 

 

Tomcat_A 的 HttpSession 分佈備份在Memcached_B 和 Memcached_C 

Tomcat_B 的 HttpSession 分佈備份在Memcached_A 和 Memcached_C 

Tomcat_C 的 HttpSession 分佈備份在Memcached_A 和 Memcached_B 

 

個人構思就是這樣: 在服務器正常運行狀況下,使用 Stick-Session 方式,同一個 HttpSession 由負載均衡器判斷 HttpSession 歸屬交給同一個服務器執行,這樣一來,正常狀況下,服務器節點的運行就是徹底獨立的、就好像是單臺服務器運行同樣。 HttpSession 複製備份也是隱式的,經過哈希碼將這個 HttpSession 隱式備份在相應哈希碼分佈的 Memcached 上。

 

假設運行中 Tomcat_A 忽然宕機了(我咔嚓關了Tomcat_A,嘿嘿),那麼負載均衡器就會沒法將請求分發給 Request 相對應的Tomcat_A ,負載均衡器便會把請求分發給其餘的Tomcat_B 或 Tomcat_C ,這兩臺服務器會接收到原屬於綁定在 Tomcat_A上的請求 ,他們沒有相應的 HttpSession 啊, 而後他們就主動從 Memcached 集羣中尋找這個 HttpSession 。若是找到的話,他們便主動把這個 HttpSession 「收錄」爲本身的, 即將 JSESSIONID 修改成本身的。這樣一來,原屬於 Tomcat_A 的 HttpSession 會隨機分佈給其餘沒有宕機的服務器節點。

 

這是服務器節點宕機的狀況、

若是緩存器節點宕機了怎麼辦?

 

假設 Memcached_A 宕機,那麼整個集羣中保存在 Memcached_A 中的Session備份就丟失,那麼 Tomcat_B 和 Tomcat_C中的Session就沒有了備份。 若是這時這兩臺服務器再掛斷的話,Session就真的丟失了(用戶感情傷不起啊)。爲了保證 「整個集羣中隨時都存有同一個Session的備份 」, Tomcat_B 和 Tomcat_C 應該爲自身的Session負責。他們應該主動把本身的 Session 再備份一次(能夠採用臨時新建線程的方式, 畢竟宕機不是頻繁的麼。屬於特殊狀況),再次備份到其餘的可用 Memcached 節點中。

 

這樣,整個程序中能夠徹底無視 單臺機器的忽然宕機, 一分鐘內整個集羣應該能把宕機服務器的 Session 再備份一次吧!

 

 

關於這個想法,網上有一個開源項目叫作 memcached-session-manager 。 我試過它,感受不怎麼好用。它只能說實現了部分個人想法吧,沒有徹底實現。測試中,仍然存在 HttpSession 丟失的狀況。而且它有着使人髮指的效率問題!

 

我測試了一下, 普通的 JSP 頁面處理只耗費 62.3ms (機子挫)。而添加上這個插件以後,普通的 JSP 頁面處理須要消耗2.18s !!!這真是使人髮指的效率!

 

靠人不如靠本身、我便本身實現了本身的思路。

 

使用的緩存程序就是 Memcached 2.6, 我添加在附件裏了。

我使用的 Memcached 客戶端是 XMemcached (國產)、支持國產麼,而且它的效率據某公司測試證實,比 SynMemcached 略高一點點。

下載地址:XMemcached

 

我就是經過替換了 Tomcat 原有的 StandardManager(MemcachedManager替換)、StandardSession(MemcachedSession替換) 來實現的, 而後加入了隱式的 HttpSession 備份操做。若是須要的話,還會從緩存程序中嘗試獲取 HttpSession。

 

我還經過在 MemcachedManager 中向 Context 中加入閥門(Valve)在每次請求以後再根據 MemcachedSession 的屬性是否被修改來判斷是否更新緩存(事務一致性麼,整個請求處理過程是一個原子)。  不涉及setAttrubute、removeAttribute的操做是不會觸發緩存更新的,而且 setAttribute 若是設置重複值也是不會引發緩存更新的。

 

在 XMemcached 中我添加了DisConnect 事件的監聽器、 若是某條鏈接斷開(Memcached服務器節點宕機)的話,會觸發Web服務器將 Session 再次更新入其餘未斷開的Memcached服務器節點中。

 

整個過程實現其實挺簡單的、 jar 包我也放在附件中。

 

最後就說說我實現的這個「無名」插件的效率、 測試中我挺費解的, 添加了這個插件的 Tomcat 竟然比正常的 Tomcat 處理JSP頁面還快。使用它以後,處理一個正常一樣JSP頁面只須要 了 57.5ms ,嘿嘿,快了幾毫秒(應該是測試數據偏差)。

 

使用這個「無名」插件挺簡單的、 就是修改 context.xml ,添加一個:

 

Xml代碼    收藏代碼
  1. <Manager     className="net.sulin.mem.MemcachedManager"  
  2.             queueSize="300"  
  3.             addr="127.0.0.1:11211 127.0.0.1:11212 127.0.0.1:11213"  
  4.             poolSize="3"  
  5.             protocol="text"  
  6.             maxInactiveInterval="30"/>  
  7.   
  8. <!--  
  9.   
  10. className : 替換的Manager  
  11.   
  12. queueSize : 我採用了異步隊列更新 HttpSession 緩存,隊列用於存儲須要更新的HttpSession對象,若是值過小的話。隊列空間不夠用  
  13.   
  14. addr : 就是 Memcached 的服務器地址和端口了,每一個之間用空格隔開(XMemcached就是這樣處理的,我不想費事)  
  15.   
  16. poolSize : XMemcached 客戶端與 Memcached 服務器的鏈接池,據XMemcached 做者說即使是高併發也 30 以內吧,由於這是用NIO處理的,不須要太多鏈接。  
  17.   
  18. protocol : XMemcached 客戶端與 Memcached 服務器之間的數據傳輸協議,能夠是「text」也能夠是「binary」, binary 的話它可使用 XMemcached 的touch方法等, 可是須要 1.4 以上版本的XMemcached。 我沒使用  
  19.   
  20. maxInactiveInterval :HttpSession過時時間, 分鐘爲單位  
  21.   
  22. -->  
 

在測試中,我胡亂關閉Web服務器和Memcached服務器, 每次請求的 HttpSession 都沒有碰見丟失的狀況,嘿嘿,感受挺不錯的。性能上也是毫無影響。 可是這是沒有經受過任何生產考研的!

 

有想法的人能夠試試,源碼就在jar包中。若是有什麼優化想法咱歡迎交流!

 

 

 

 

感受俺寫的不錯的、頂一個啊。點個精華、良好神馬的安慰一下俺嘛

 

 

 

========================================================================

 

關於這個 failover 解決方案的設計思想:

 

我是感受不必爲了 HttpSession failover再另外添置一個 Memcached 服務器集羣。 在現有的 Tomcat 集羣上的每一個節點上都綁定一個 Memcached 節點這樣構成一個附加的 Memcached 服務器集羣是否是更好? 既不花錢、對性能基本上沒什麼影響(Memcached 效率很高的,有人測試了上億數據量也僅僅佔用了10%的CPU)。

 

 

關於 attribute 可能被修改而沒有觸發緩存更新的問題:

 

這個問題就是這樣 session.getAttribute("key") = newObject; 這樣的代碼, 我沒有深看因此還不太清楚此 getAttribute 方法是獲取"引用"仍是"複製"。

若是是「複製」的話就好說了,若是是引用的話。。。嘿嘿,我目前是沒有好辦法處理了,只有靠開發人員本身注意編程規範了(通常設置session屬性的話都是調用setAttribute吧?)。 但願有哪位朋友想到了解決辦法更俺交流一下。

 

相關文章
相關標籤/搜索