采用Memcached实现分布式Session
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
歡迎跳轉到本文的原文鏈接:https://honeypps.com/backend/distributed-session-with-memcached/
?memcached-session-manager是一個開源的高可用的Tomcat session共享解決方案,它支持Sticky模式和Non-Sticky模式。Sticky模式表示每次請求都會被映射到同一臺后端Web服務器,知道該Web服務器宕機,這樣session可先存放在服務器本地,等到請求處理完成再同步到后端memcached服務器;而當Web服務器宕機時,請求被映射到其他Web服務器,這時候,其他Web服務器可以從后端memcache中恢復session。對于Non-Sticky模式來說,請求每次映射的后端Web服務器是不確定的,當請求到來時,從memcached中加載session;當請求處理完成時,將session再協會到memcached。
?以Non-Sticky模式為例,首先需要安裝memcached的服務器,這個在上一篇中已經講述過了。然后在Tomcat的$CATALINA_HOME/conf/context.xml文件配置SessionManager,具體配置如下:
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:10.10.195.112:11211" sticky="false" sessionBackupAsync="false" sessionBackupTimeout="1000"lockingMode="auto" requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />?其中,memcachedNodes指定了memcached的節點;sticky表示是否采用sticky模式;sessionBackuoAsync表示是否采用異步方式備份session;lockingMode表示session的鎖定模式;auto表示對于只讀請求,session將不會被鎖定,如果包含寫入請求,則session會被鎖定;requestUriIgnorePattern表示忽略的url; transcoderFactoryClass用來指定序列化的方式,這里采用的是Kryo序列化,也是memcached-session-manager比較推薦的一種序列化方式。也可以采用其他序列化方式,譬如:javolution-serializer, xstream-serializer, flexjson-serializer。
?memcached-session-manager依賴于memcached-session-manager-{version}.jar,如果使用的是tomcat6,則還需要下載memcached-session-manager-tc6-{version}.jar,如果是tomcat7則采用memcached-session-manager-tc7-{version}.jar的包(博主采用的是tomcat7+jdk7)。還需要spymemcached-2.7.3.jar,在啟動tomcat之前需要將這些jar包放到tomcat的lib目錄下。如果采用Kryo方式序列化,還需要加入其他一些包,所有包如下:
注意這些包的版本,搞錯一下就不能實現其功能。這里博主已經整理好了,可以在這里下載。
##常見錯誤
1 啟動tomcat出現錯誤案例1
這個是包版本問題,memcached-session-manager以及msm-kryo-serializer版本不對。
2 啟動tomcat出現錯誤案例2
嚴重: Error manager.start() org.apache.catalina.LifecycleException: Failed to start component [de.javakaffee.web.msm.MemcachedBackupSessionManager[]]at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5501)at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1245)at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1895)at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)at java.util.concurrent.FutureTask.run(Unknown Source)at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)at java.lang.Thread.run(Unknown Source) Caused by: java.lang.NoSuchMethodError: de.javakaffee.web.msm.MemcachedSessionService$SessionManager.getContainerClassLoader()Ljava/lang/ClassLoader;at de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory.createTranscoder(KryoTranscoderFactory.java:47)at de.javakaffee.web.msm.MemcachedSessionService.createTranscoderService(MemcachedSessionService.java:449)at de.javakaffee.web.msm.MemcachedSessionService.startInternal(MemcachedSessionService.java:425)at de.javakaffee.web.msm.MemcachedBackupSessionManager.startInternal(MemcachedBackupSessionManager.java:509)at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)... 12 more這個也是包版本問題,msm-kryo-serializer版本不對
3 在context.xml中配置failoverNodes節點,如下
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:10.10.195.112:11211" sticky="false" failoverNodes="n1"sessionBackupAsync="false" lockingMode="auto" requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />啟動tomcat報錯:
嚴重: Error manager.start() org.apache.catalina.LifecycleException: Failed to start component [de.javakaffee.web.msm.MemcachedBackupSessionManager[/Architecture]]at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5501)at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:672)at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1859)at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)at java.util.concurrent.FutureTask.run(Unknown Source)at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)at java.lang.Thread.run(Unknown Source) Caused by: java.lang.IllegalArgumentException: For a single memcached node there should/must no failoverNodes be specified.at de.javakaffee.web.msm.MemcachedNodesManager.createFor(MemcachedNodesManager.java:224)at de.javakaffee.web.msm.MemcachedSessionService.createMemcachedNodesManager(MemcachedSessionService.java:445)at de.javakaffee.web.msm.MemcachedSessionService.startInternal(MemcachedSessionService.java:410)at de.javakaffee.web.msm.MemcachedBackupSessionManager.startInternal(MemcachedBackupSessionManager.java:509)at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)... 12 more可以看到報錯中“Caused by: java.lang.IllegalArgumentException: For a single memcached node there should/must no failoverNodes be specified.”這句,需要把failoverNodes去掉。
##應用舉例
?這里博主采用keepalived+lvs進行負載均衡搭建。詳細可以參考LVS+Keepalived實現負載均衡和雙機熱備,不了解也沒關系,這個不是本篇的重點。
?(配的是雙機熱備+負載均衡,主備機會虛擬出一個訪問的ip,當主機宕機時,會自動切換到備機,對于用戶而言完全透明。了解即可)
?在主備機web路徑的根目錄下放入test.jsp,代碼如下(備機的就把 10.10.195.107換成10.10.195.187):
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %> <%@ page session="true" %> <%String path = request.getContextPath();String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>Memcached-session-manager</title> </head> <body >10.10.195.107<%out.print("<br> SESSION-ID:"+session.getId()+"<br>");%> </body> </html>通過瀏覽器訪問:http://10.10.195.188:8080/test.jsp
可以看到頁面顯示:
在主機中輸入: sudo service keepalived stop之后(切換到備機),頁面顯示:
10.10.195.187 SESSION-ID:6F9B1255A1C9E3F7D5FC144DD81217CD-n1可以看到訪問的頁面變了,但是session并沒有改變,因為它存在memcached服務器中。
歡迎跳轉到本文的原文鏈接:https://honeypps.com/backend/distributed-session-with-memcached/
參考資料:
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
總結
以上是生活随笔為你收集整理的采用Memcached实现分布式Session的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Memcached安装与配置
- 下一篇: Jedis对redis的操作详解