1. 程式人生 > >Tomcat7叢集共享Session 基於redis進行統一管理(轉)

Tomcat7叢集共享Session 基於redis進行統一管理(轉)

背景:

      很多時候,生產環境,需要多個tomcat協作,那麼session的統一管理是一個首先需要解決的問題。session的統一管理有很多解決方案,比如儲存至資料庫、memcache、redis。那麼我想給大家介紹的是將session儲存至redis這個方案。

實驗環境:

作業系統:windows 7 64位

Redis版本:Redis 2.8.2101(Redis安裝方法這裡不介紹了,請自行Google、Baidu)

Tomcat版本:tomcat7.0.64(2個tomcat例項,注意同一臺機器上試的話,啟動另一個tomcat例項的時候需要修改埠號,如果是不同機器上的tomcat,那就不用修改了)

JDK版本:jdk1.7.0_80(生產環境請使用servre版本)

請求監聽埠
Shutdown監聽埠
AJP監聽埠

tomcat_1
8080
8005
8009

tomcat_2
8090
8015
8019

準備:

tomcat_1埠按照預設配置(不改server.xml)

tomcat_2埠改為下面的配置(修改server.xml)

Xml程式碼 收藏程式碼

  1. <span style="line-height: 1.5; font-size: 18px;"><Server port="8015" shutdown="SHUTDOWN">
  2. <Service name="Catalina">
  3. <Connector port="8090" protocol="HTTP/1.1"
  4. connectionTimeout="20000"
  5. redirectPort="8443" />
  6. .... 
  7. <Connector port="8019" protocol="AJP/1.3" redirectPort="8443" />
  8. .... 
  9. </Service>
  10. </Server></span>

tomcat_1,tomcat_2都要修改contenxt.xml

Xml程式碼 收藏程式碼

  1. <Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" />
  2. <Manager className="com.radiadesign.catalina.session.RedisSessionManager"
  3. host="localhost"
  4. port="6379"
  5. database="0"
  6. maxInactiveInterval="60" />

下載所需jar包(為了方便大家,我在附件裡上傳了所有的jar包)

1)redis的java客戶端

2) tomcat-redis-session-manager的jar包,我用的是自己編譯的(作者只給了gradle,⊙﹏⊙b汗沒有maven的,我把它改成了maven工程的),見附件,原始碼也給到大家。

3) apache-commons-pool2

將下載好的jar包,放到tomcat_1\lib及tomcat_2\lib目錄下,

開始實驗:

首先開啟redis服務 redis-server.exe redis.windows.conf

開啟redis命令列客戶端以便監視redis的狀態變化,redis-cli -p 6379  monitor(如果有密碼則 redis-cli -p 6379 -a mypass monitor)


分別通過catalina.bat run 開啟tomcat_1,tomcat_2

   在命令列終端,看到了如下資訊,表明redis的session manager初始化成功

Java程式碼 收藏程式碼

  1. ... 
  2. 十月 15, 2015 4:52:39 下午 com.radiadesign.catalina.session.RedisSessionManager startInternal 
  3. 資訊: Attached to RedisSessionHandlerValve 
  4. 十月 15, 2015 4:52:39 下午 com.radiadesign.catalina.session.RedisSessionManager initializeSerializer 
  5. 資訊: Attempting to use serializer :com.radiadesign.catalina.session.JavaSerializer 
  6. 十月 15, 2015 4:52:39 下午 com.radiadesign.catalina.session.RedisSessionManager startInternal 
  7. 資訊: Will expire sessions after 1800 seconds 
  8. 十月 15, 2015 4:52:39 下午 org.apache.catalina.startup.HostConfig deployDirectory 
  9. 資訊: Deployment of web application directory E:\WorkFolder\Temp\Redis-Session\apache-tomcat1-8080\webapps\manag 
  10. 十月 15, 2015 4:52:39 下午 org.apache.catalina.startup.HostConfig deployDirectory 
  11. 資訊: Deploying web application directory E:\WorkFolder\Temp\Redis-Session\apache-tomcat1-8080\webapps\ROOT 
  12. 十月 15, 2015 4:52:39 下午 org.apache.catalina.startup.TldConfig execute 
  13. 資訊: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a co 
  14. 十月 15, 2015 4:52:39 下午 com.radiadesign.catalina.session.RedisSessionManager startInternal 
  15. 資訊: Attached to RedisSessionHandlerValve 
  16. 十月 15, 2015 4:52:39 下午 com.radiadesign.catalina.session.RedisSessionManager initializeSerializer 
  17. 資訊: Attempting to use serializer :com.radiadesign.catalina.session.JavaSerializer 
  18. 十月 15, 2015 4:52:39 下午 com.radiadesign.catalina.session.RedisSessionManager startInternal 
  19. 資訊: Will expire sessions after 1800 seconds 
  20. ... 

然後我們分別在tomcat_1/webapp/ROOT,tomcat_2/webapp/ROOT下放setsession.jsp,getsession.jsp

setsession.jsp內容:

Java程式碼 收藏程式碼

  1. <% 
  2.   session.setAttribute("name","jaychang"); 
  3.   session.setAttribute("id","1001"); 
  4. %> 

getsession.jsp內容:

Java程式碼 收藏程式碼

  1. <%=session.getAttribute("id")%> 
  2. ID:<%=session.getAttribute("name")%> 
  3. NAME:<%=session.getAttribute("id")%> 

  好了,至此,你應該也明白了,現在要幹嘛了,那麼重點來了,見證奇蹟的時刻到了!

開啟瀏覽器,輸入 http://127.0.0.1:8080/setsession.jsp回車


D741CDC41F66331883AAB70DC6252046就是SESSIONID

值為

Java程式碼 收藏程式碼

  1. \xac\xed\x00\x05w\b\x00\x00\x01Pj\xc8\xf5\xb2sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01Pj\xc8\xf5\xb2sq\x00~\x00\x00\x00\x00\x01Pj\xc8\xf5\xb2sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexq\x00~\x00\x01\x00\x00\a\bsr\x00\x11java.lang.Boolean\xcd r\x80\xd5\x9c\xfa\xee\x02\x00\x01Z\x00\x05valuexp\x01q\x00~\x00\asq\x00~\x00\x00\x00\x00\x01Pj\xc8\xf5\xb4t\x00 D741CDC41F66331883AAB70DC6252046sq\x00~\x00\x04\x00\x00\x00\x02t\x00\x04namet\x00\bjaychangt\x00\x02idt\x00\x041001 

最後我們看到了...jaychang ...1001

好了,那我們再看看getsession.jsp,先看tomcat_1的getsession.jsp

看下redis變化,get "D741CDC41F66331883AAB70DC6252046"


再看看tomcat_2的getsession.jsp,頁面上獲取到了


再看看redis的變化,又一次get "D741CDC41F66331883AAB70DC6252046"

獲取的sessionId是同一個,說明成功了

待解決的問題:

Xml程式碼 收藏程式碼

  1. java.lang.IllegalStateException: Race condition encountered: attempted to load session[32405E7F668A227E154AC6FF5E4A4F6A] which has been created but not yet serialized. 
  2.         at com.radiadesign.catalina.session.RedisSessionManager.loadSessionFromRedis(RedisSessionManager.java:389) 
  3.         at com.radiadesign.catalina.session.RedisSessionManager.findSession(RedisSessionManager.java:315) 
  4.         at org.apache.catalina.connector.Request.isRequestedSessionIdValid(Request.java:2460) 
  5.         at org.apache.catalina.connector.CoyoteAdapter.parseSessionCookiesId(CoyoteAdapter.java:1067) 
  6.         at org.apache.catalina.connector.CoyoteAdapter.postParseRequest(CoyoteAdapter.java:754) 
  7.         at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:418) 
  8.         at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079) 
  9.         at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625) 
  10.         at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316) 
  11.         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
  12.         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
  13.         at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 

參考: