業務場景描述:
有這樣的業務架構,一台nginx将用戶端請求分發到2台tomcat中,現在的問題是當tomcat1挂掉之後,nginx将請求轉發到tomcat2中,此時tomcat2會要求使用者重新登入,造成使用者感覺不好(實際使用者已經登入成功過了)。
現在想做到tomcat1挂掉之後,當nginx将請求分發到tomcat2的時候,不讓使用者再次登入,即完成兩個tomcat的Session共享功能
解決方案:
1:安裝并啟動Memcached
Memcached的安裝和服務啟動,請參考本人編寫的博文《MemCached的安裝和JAVA用戶端連接配接Memcached示例代碼》,記得一定要保證Memcached能連接配接,用Java用戶端緩存資料後在取出來試一下。
2:下載下傳需要的包,tomcat7版本,這裡面坑很多,切記版本一緻一緻一緻,不然啟動報錯,把你繞死
asm-3.2.jar
couchbase-client-1.4.8.jar:msm依賴這個包
kryo-1.04.jar
kryo-serializers-0.9.jar
memcached-session-manager-1.6.5.jar
memcached-session-manager-tc7-1.6.5.jar:不同版本Tomcat需要使用不同的Jar包,tc7代表tomcat7版本
minlog-1.2.jar
msm-kryo-serializer-1.6.0.jar
reflectasm-1.01.jar
spymemcached-2.10.3.jar:Jave用戶端連接配接memcached的jar包,這個包可以選擇安裝memcached安裝版本對應的jar包
将上面這些包放到tomcat的lib目錄下面,記得是tomcat的lib目錄,不是web應用的lib目錄
3:配置web應用
這裡有兩種方式修改web應用,讓應用在啟動的時候連接配接memcached服務,并同步tomcat Session。
第一種方式,修改tomcat的server.xml
<Context docBase="webApp" path="/" reloadable="false" source="org.eclipse.jst.jee.server:webApp">
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes= "n1:111.111.111.1:11211"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
</Context>
第二種方式,在webApp應用的webApp\WebRoot\META-INF\目錄下面增加context.xml,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes= "n1:111.111.111.1:11211"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
</Context>
測試驗證:
1:隻啟動一台經過配置的tomcat
浏覽器中登入系統,請求一個接口,可以看到接口請求中的Request Header中帶了JSESSION屬性,背景日志列印也有JSESSION屬性,
這時關閉tomcat伺服器,然後在重新開機伺服器完成之後,還是在上面開啟的浏覽器中請求另外一個接口,可以看到請求中的Request Header中帶了JSESSION屬性沒變,背景日志中JSESSION屬性也沒變,memcached中管理的session同步過來了,不需要再次登入了。
2:啟動兩台tomcat,nginx配置分發到這兩台伺服器,兩台伺服器互為主備
浏覽器中登入系統,請求一個接口,可以看到接口請求中的Request Header中帶了JSESSION屬性,背景日志列印也有JSESSION屬性,
這時關閉tomcat1伺服器, 同浏覽器中繼續請求接口,可以看到請求中的Request Header中JSESSION屬性沒變,tomcat2中背景日志JSESSION屬性沒變,不要再次登入系統驗證。
這時啟動tomcat1,關閉tomcat2, 同浏覽器中繼續請求接口,可以看到請求中的Request Header中JSESSION屬性沒變,tomcat1中背景日志JSESSION屬性也沒變,業務場景功能實作啦。
走過的坑:
1:確定memcached能通,能緩存資源
2:下載下傳的Jar包放到tomcat的lib目錄中,不是web應用的lib目錄
3:切記下載下傳的jar包的版本一緻,不然各種缺少列
4:注意選擇合适的修改應用的配置方式
5:配置檔案中的标簽都是大寫字母打頭,如:是<Context>而不是<context>,是<Manager>而不是<manager>
6:更新生産環境的時候,一般生産環境都有端口和防火牆隔離的,記得需要将和memcached互動的端口打開
如上配置的不足點與解決方法:
如上的配合會導緻A機器session變動,不同同步到B機器同session,可以有如下兩種方式解決此問題:
一:修改tomcat的server.xml(這種方式會偶爾出現session變動的情況,不太穩定)
這個時候需要如下配置不同tomcat的server.xml,修改<Engine屬性,最後加上jvmRoute屬性,這樣就可以強制session變化後備份到memcached,并且另外一台機器要使用session的時候從memcached中獲得,詳細配置如下
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
二:修改memcached-session-manage的同步方式,在webApp應用的webApp\WebRoot\META-INF\目錄下面增加context.xml,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes= "n1:111.111.111.1:11211"
sessionBackupAsync="false"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
</Context>
這種方式的參考文章: https://code.google.com/archive/p/memcached-session-manager/