研究tomcat做負載均衡的時候如何實現ha,還有就是不采用session復制的方法做集群。
想到的是將session全部存儲在后端的緩存服務器中。
正好網上有這么一個工具Memcached-session-manager(后面簡稱msm),所以直接扒下來用了。
地址如下:
http://code.google.com/p/memcached-session-manager/
msm支持 stickty(沾粘會話)和non-sticky(非沾粘會話)兩種集群方式。
sticky就是前端的loadbanlence能保證每個用戶的請求都路由到了同一個tomcat上。
non-sticky則每一次請求都可能路由到了不同的tomcat中。
至於msm在這兩種方式是怎么處理的看下圖:
下圖來自javaeye的xxtianxiaxing的博客,我這里引用一下,原文地址為http://xxtianxiaxing.iteye.com/blog/1269704
1. sticky
2. non-sticky
用msm的session管理manager替代tomcat自身的standardManager。
可以配置在虛擬服務器的context標簽中,也可以在context.xml里面全局配置。
<!--sticky
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:localhost:11211"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
copyCollectionsForSerialization="false"
<!--下面這個是可選的,自己定義特殊的類注冊到kryo自定義轉換器中,實現序列化-->
customConverter="com.test.serializer.CustomKryoRegistration"
/>
-->
<!--non sticky
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:localhost:11211"
sticky="false"
sessionBackupAsync="false"
lockingMode="auto"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
上面采用的序列化方式是kryo,根據官方提供的數據,這個的序列化效率是最好的,我下面有一些簡單的測試。
感 覺kryo的效率主要體現在高並發下面。如果非高並發感覺跟java的自帶io差不多。如果不使用kryo進行序列化,采用java默認方式的話,請將 transcoderFactoryClass改 為:de.javakaffee.web.msm.JavaSerializationTranscoderFactory
另外在使用 kryo進行序列話的時候,有時候會報序列話錯誤。我開始就報ConcrrentHashMap這個類不能序列化的錯誤。tomcat在的session 的Atrribute使用了這個數據結構來保存。要解決這個問題,需要自己寫一個類,將這些特殊的類注冊進去。然后打個jar包放tomcat的lib 下。就ok了。
下面是例子:
package com.test.serializer;
import java.util.concurrent.ConcurrentHashMap;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.serialize.MapSerializer;
import de.javakaffee.web.msm.serializer.kryo.KryoCustomization;
public class CustomKryoRegistration implements KryoCustomization {
public void customize(Kryo kryo) {
kryo.register(ConcurrentHashMap.class, new MapSerializer(kryo));
}
}
把這個類打好jar包放tomcat的lib目錄下。然后還需要在context中配置customConverter="com.test.serializer.CustomKryoRegistration",這樣就OK了。
另外集成kryo序列化的環境需要以下jar包。剛開始googleCode的官方網站上沒寫。搞了半天,后來提醒原作者加上了:
kryo-serializer: msm-kryo-serializer, kryo-serializers, kryo, minlog, reflectasm, asm-3.2
其他序列化方式(java自帶的序列化方式外的3方序列化方式)需要的jar:
javolution-serializer: msm-javolution-serializer, javolution-5.4.3.1
xstream-serializer: msm-xstream-serializer, xstream, xmlpull, xpp3_min
flexjson-serializer: msm-flexjson-serializer, flexjson
可以查看官方網站的文檔:http://code.google.com/p/memcached-session-manager/wiki/SetupAndConfiguration
搭建好所有環境之后,采用1 nginx(ip_hash)+2 tomcat6.0.35+sticky(最好用6.0.2以上版本,因為新的msm包里面使用了6.0.2才有的新方法,不然會報NoSuchMethod-changeSessionId()的錯誤)
驗證是否成功:
登錄發布的系統(發現這個時候請求全部路由到tomcat1),之后,關閉tomcat1,繼續在里面做有關session的操作。發現這個時候請求被tomcat2接管,而且session依然保持(從memcached中拿出)。ok,這樣就說明成功了。
non_sticky的配置一樣按上面的方法來驗證是否成功。
*********最后是我在搭建好msm環境后做的一些簡單測試:***************
測試環境:T5870 2.0G cpu,內存2G小本本,win7系統。tomcat,memcache全部裝win7上。啟動一個memcahed服務給了32m內存。tmcat52m內存。
ok,首先是前面沒有負載均衡,單個tomcat的情況,請求一個sevlet鏈接,鏈接就是從session取個值出來的操作。
用apache ab,-C 參數帶上cookie參數模擬有session的請求,100人,共5000次請求是下面的結果:
不用msm: 1000req/s
msm-sticky kryo: 850req/s
msm-sticky java標准序列化: 830req/s
msm-nonsticky kryo : 440/s(50人並發) 430/s(100人並發)
msm-nosticky java標准序列化 : 480/s(50人並發) 270/s(100人並發)
在sticky的情況下,因為在本地有session的情況下,省略了從memcached取session緩存的情況,序列化次數不多,因此性能只有大概1/10的損耗。
在non-stikcy的情況下,集中的每次從memcached取session,性能損失了大概一半。
而 可以看出,在高並發的情況下,kryo序列化比java標准序列化要好。並發性能大概在java標准序列化一倍以上。而且在搞並發的non-sticky 的情況下,session中的多線程並行操作沖突嚴重。lock很多(當然這個lock模式可以設置,甚至可以完全不要鎖)。這也嚴重降低了速度。
又測試了1台nginx(ip_hash做負載均衡)+2tomcat的情況。
因為暫時沒法模擬多ip的請求,所以所有請求都只路由到了tomcat1上。采用kryo序列化的策略依然保持了高並發下處理速度不下降的優勢。
還是400多r/s,而java標准序列化還是要低一半多。
最后推薦采用sticky+kryo的策略來實現msm~!
