Nginx+Memcached+Tomcat集群配置实践(Sticky Session)

准备工作

创建一个简单的web应用,名为session。其中有两个页面,分别如下所示:
  • 页面login.jsp
[html]  view plain copy
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
  2.      pageEncoding="UTF-8"%>  
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  4. <html>  
  5. <head>  
  6. <title>登录页面</title>  
  7. <meta http-equiv="pragma" content="no-cache">  
  8. <meta http-equiv="cache-control" content="no-cache">  
  9. <meta http-equiv="expires" content="0">  
  10. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
  11. <meta http-equiv="description" content="This is my page">  
  12. </head>  
  13. <body>  
  14.      <table bgcolor="#F8C3C3" border="1" borderColor="#FF0000"  
  15.           align="center" width="260" height="160">  
  16.           <tr>  
  17.                <td height="15" colspan="2" align="center"  
  18.                     style="background-color: #000000; font-size: 28px; color: #FFFF00"><b>用户登录</b></td>  
  19.           </tr>  
  20.           <form method="post" action="login">  
  21.                <tr>  
  22.                     <td width="80" align="center"><b>用户名</b></td>  
  23.                     <td><input type="text" name="userName" value="" /></td>  
  24.                </tr>  
  25.                <tr>  
  26.                     <td align="center"><b>密 码</b></td>  
  27.                     <td><input type="password" name="password" value="" /></td>  
  28.                </tr>  
  29.                <tr>  
  30.                     <td colspan="2" align="center" style="background-color: #000000;">  
  31.                          <input type="submit" value="登 录" />  <input type="reset"  
  32.                          value="重 置" />  
  33.                     </td>  
  34.                </tr>  
  35.           </form>  
  36.      </table>  
  37. </body>  
  38. </html>  
  • 登录成功页面success.jsp
[html]  view plain copy
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  3. <html>  
  4. <head>  
  5. <title>登录成功页面</title>  
  6. <meta http-equiv="pragma" content="no-cache">  
  7. <meta http-equiv="cache-control" content="no-cache">  
  8. <meta http-equiv="expires" content="0">  
  9. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
  10. <meta http-equiv="description" content="This is my page">  
  11. </head>  
  12. <%  
  13.      String userName = (String) request.getSession().getAttribute("userName");  
  14. %>  
  15. <body bgcolor="#000000">  
  16.      <table width="500" height="200" align="center" border="1"  
  17.           style="background-color: #000000;">  
  18.           <tr>  
  19.                <td align="center"  
  20.                     style="background-color: #F8C3C3; color: #00FF00; font-weight: bold; font-size: 30px">  
  21.                     当前登录用户:<%=userName %>  
  22.                </td>  
  23.           </tr>  
  24.      </table>  
  25. </body>  
  26. </html>  
还有一个Servlet,负责请求的转发,并设置session数据,如下所示:
[java]  view plain copy
  1. package org.shirdrn.cluster.tomcat.servlet;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.http.HttpServlet;  
  9. import javax.servlet.http.HttpServletRequest;  
  10. import javax.servlet.http.HttpServletResponse;  
  11.   
  12. import org.apache.commons.logging.Log;  
  13. import org.apache.commons.logging.LogFactory;  
  14.   
  15. public class LoginSevlet extends HttpServlet {  
  16.      private static final long serialVersionUID = 1L;  
  17.      private static final Log LOG = LogFactory.getLog(LoginSevlet.class);  
  18.     private static Map<String, String> accountDB = new HashMap<String, String>();  
  19.     static {  
  20.          accountDB.put("shirdrn""123456");  
  21.          accountDB.put("admin""999999");  
  22.          accountDB.put("dev""000888");  
  23.          accountDB.put("007""007007");  
  24.     }  
  25.      
  26.     public LoginSevlet() {  
  27.         super();  
  28.     }  
  29.   
  30.      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  31.           this.doPost(request, response);  
  32.      }  
  33.   
  34.      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  35.           String userName = request.getParameter("userName");  
  36.           String password = request.getParameter("password");  
  37.           LOG.info("Raw input:userName=" + userName + ",password=" + password);  
  38.            
  39.           if(userName!=null && password!=null  
  40.                     && accountDB.containsKey(userName)  
  41.                     && accountDB.get(userName).equals(password)) {  
  42.                LOG.info("Login;status=SUCCESS");  
  43.                request.getSession().setAttribute("userName", userName);  
  44.                request.getRequestDispatcher("success.jsp").forward(request, response);                
  45.           } else {  
  46.                LOG.info("Login;status=FAIL");  
  47.                request.getRequestDispatcher("login.jsp").forward(request, response);  
  48.           }  
  49.      }  
  50.   
  51. }  
这里模拟了一个账号数据库,对用户的登录请求进行处理。
最后打成WAR包,部署到Tomcat集群中的每个结点上。
Memcached安装、配置、启动

在Ubuntu系统下,如果没有安装Memcached,可以执行如下命令进行安装:
[plain]  view plain copy
  1. sudo apt-get install memcached  
然后,启动Memcached服务进程,这里,我启动了两个服务进程,分别监听端口11211、11311,启动命令如下所示:
[plain]  view plain copy
  1. sudo /usr/bin/memcached -m 64 -d -u memcache -p 11211 -l 192.168.1.104 -c 5000 -P /tmp/n1-memcached.pid  
  2. sudo /usr/bin/memcached -m 64 -d -u memcache -p 11311 -l 192.168.1.104 -c 5000 -P /tmp/n2-memcached.pid  
查询Memcached服务状态:
[plain]  view plain copy
  1. shirdrn@dev:~/servers/cluster/nginx_tomcat_memcached$ ps -ef | grep memcached  
  2. memcache  1578     1  0 Jan25 ?        00:00:00 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1  
  3. memcache  3300     1  0 Jan25 ?        00:00:00 /usr/bin/memcached -m 64 -d -u memcache -p 11211 -l 192.168.1.104 -c 5000 -P /tmp/n1-memcached.pid  
  4. memcache  3308     1  0 00:00 ?        00:00:00 /usr/bin/memcached -m 64 -d -u memcache -p 11311 -l 192.168.1.104 -c 5000 -P /tmp/n2-memcached.pid  
  5. shirdrn   3318  3095  0 00:00 pts/5    00:00:00 grep --color=auto memcached  

Tomcat集群配置

Tomcat集群配置,集群中各个结点通过共享存储在缓存Memcached中session来实现session的共享:如果有一台机器上的Tomcat服务停掉了,对于其他对等服务器上的session数据仍然可以从Memcached缓存中读取,从而不会发生session丢失的问题。
对于满足这种配置的实现方案,可以在 https://code.google.com/p/memcached-session-managerhttps://spymemcached.googlecode.com上下载相关的jar文件。因为基于不同的序列化方案,可以有多种配置方法,下面是选择Javolution序列化框架,需要提供如下库文件:
下载上述jar文件,拷贝到$CATALINA_HOME/lib目录下,然后需要配置$CATALINA_HOME/conf/server.xml文件。
Tomcat集群中,每个结点的$CATALINA_HOME/conf/server.xml基本配置都是相同的,不同配置内容分别如下:
  • 如果在同一台机器上,要保证各个服务端口不相冲突
  • <Manager>元素中failoverNodes属性值不同
例如,我们在同一台机器上配置了两个Tomcat服务器实例,所在目录分别为tomcat-1和tomcat-2,对应的conf/server.xml配置内容如下:
  • tomcat-1/conf/server.xml
[html]  view plain copy
  1. <?xml version='1.0' encoding='utf-8'?>  
  2.   
  3. <Server port="8085" shutdown="SHUTDOWN">  
  4.      <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />  
  5.      <Listener className="org.apache.catalina.core.JasperListener" />  
  6.      <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />  
  7.      <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />  
  8.      <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />  
  9.   
  10.      <GlobalNamingResources>  
  11.           <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase"  
  12.                description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory"  
  13.                pathname="conf/tomcat-users.xml" />  
  14.      </GlobalNamingResources>  
  15.   
  16.      <Service name="Catalina">  
  17.           <Connector port="8088" protocol="HTTP/1.1" connectionTimeout="20000"  
  18.                redirectPort="8443" />  
  19.           <Connector port="8089" protocol="AJP/1.3" redirectPort="8443" />  
  20.           <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">  
  21.   
  22.                <Realm className="org.apache.catalina.realm.LockOutRealm">  
  23.                     <Realm className="org.apache.catalina.realm.UserDatabaseRealm"  
  24.                          resourceName="UserDatabase" />  
  25.                </Realm>  
  26.   
  27.                <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" deployOnStartup="true">  
  28.                     <Context docBase="/home/shirdrn/servers/cluster/nginx_tomcat_memcached/webapps/session.war" path="/session" reloadable="true">  
  29.                          <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"  
  30.                                             memcachedNodes="n1:192.168.1.104:11211,n2:192.168.1.104:11311"  
  31.                                             failoverNodes="n1"  
  32.                                             requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$"  
  33.                                             sessionBackupAsync="false"  
  34.                                             sessionBackupTimeout="100"  
  35.                              transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"  
  36.                              copyCollectionsForSerialization="false" />  
  37.                     </Context>  
  38.                     <Valve className="org.apache.catalina.valves.AccessLogValve"  
  39.                          directory="logs" prefix="localhost_access_log." suffix=".txt"  
  40.                          pattern="%h %l %u %t "%r" %s %b" />  
  41.                </Host>  
  42.   
  43.           </Engine>  
  44.      </Service>  
  45. </Server>  
这里面,failover的Memcached结点是n1,也就是说,如果tomcat-1和n1在同一台机器上的话,session数据会优先复制到存储到Memcached结点n2,这样即使n1所在的结点宕机了,n2所在结点仍然存储了之前的session数据。
  • tomcat-2/conf/server.xml
[html]  view plain copy
  1. <?xml version='1.0' encoding='utf-8'?>  
  2.   
  3. <Server port="9085" shutdown="SHUTDOWN">  
  4.      <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />  
  5.      <Listener className="org.apache.catalina.core.JasperListener" />  
  6.      <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />  
  7.      <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />  
  8.      <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />  
  9.   
  10.      <GlobalNamingResources>  
  11.           <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase"  
  12.                description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory"  
  13.                pathname="conf/tomcat-users.xml" />  
  14.      </GlobalNamingResources>  
  15.   
  16.      <Service name="Catalina">  
  17.           <Connector port="9088" protocol="HTTP/1.1" connectionTimeout="20000"  
  18.                redirectPort="9443" />  
  19.           <Connector port="9089" protocol="AJP/1.3" redirectPort="9443" />  
  20.           <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">  
  21.   
  22.                <Realm className="org.apache.catalina.realm.LockOutRealm">  
  23.                     <Realm className="org.apache.catalina.realm.UserDatabaseRealm"  
  24.                          resourceName="UserDatabase" />  
  25.                </Realm>  
  26.   
  27.                <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" deployOnStartup="true">  
  28.                     <Context docBase="/home/shirdrn/servers/cluster/nginx_tomcat_memcached/webapps/session.war" path="/session" reloadable="true">  
  29.                          <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"  
  30.                                             memcachedNodes="n1:192.168.1.104:11211,n2:192.168.1.104:11311"  
  31.                                             failoverNodes="n2"  
  32.                                             requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$"  
  33.                                             sessionBackupAsync="false"  
  34.                                             sessionBackupTimeout="100"  
  35.                              transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"  
  36.                              copyCollectionsForSerialization="false" />  
  37.                     </Context>  
  38.                     <Valve className="org.apache.catalina.valves.AccessLogValve"  
  39.                          directory="logs" prefix="localhost_access_log." suffix=".txt"  
  40.                          pattern="%h %l %u %t "%r" %s %b" />  
  41.                </Host>  
  42.   
  43.           </Engine>  
  44.      </Service>  
  45. </Server>  
和上面类似,failover的Memcached结点是n2,也就是说,如果tomcat-2和n2在同一台机器上的话,Session数据会优先复制到存储到Memcached结点n1,这样即使n2所在的结点宕机了,n1所在结点仍然存储了之前的Session数据。

上面的配置实现了Tomcat集群中,通过Memcached实现了Sticky Session(粘性Session),主要是通过配置failover结点来达到目的的。如果采用Non-sticky Session方式,就不需要考虑failover的问题,详细配置扩参考文档( https://code.google.com/p/memcached-session-manager/wiki/SetupAndConfiguration),下面截取一个片段:

The following example shows a configuration for non-sticky sessions. In this case there's no need for failoverNodes, as sessions are served by all tomcats round-robin and they're not bound to a single tomcat. For non-sticky sessions the configuration (for both/all tomcats) would look like this:

<Context>
  ...
  <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
    memcachedNodes="n1:host1.yourdomain.com:11211,n2:host2.yourdomain.com:11211"
    sticky="false"
    sessionBackupAsync="false"
    lockingMode="uriPattern:/path1|/path2"
    requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
    transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
    />
</Context>
分别启动tomcat-1和tomcat-2,如下所示:
[plain]  view plain copy
  1. shirdrn@dev:~/servers/cluster/nginx_tomcat_memcached$ tomcat-1/bin/catalina.sh start  
  2. Using CATALINA_BASE:   /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1  
  3. Using CATALINA_HOME:   /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1  
  4. Using CATALINA_TMPDIR: /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1/temp  
  5. Using JRE_HOME:        /home/hadoop/installation/jdk1.6.0_30  
  6. Using CLASSPATH:       /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1/bin/bootstrap.jar:/home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1/bin/tomcat-juli.jar  
  7.   
  8. shirdrn@dev:~/servers/cluster/nginx_tomcat_memcached$ tomcat-2/bin/catalina.sh start  
  9. Using CATALINA_BASE:   /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2  
  10. Using CATALINA_HOME:   /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2  
  11. Using CATALINA_TMPDIR: /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2/temp  
  12. Using JRE_HOME:        /home/hadoop/installation/jdk1.6.0_30  
  13. Using CLASSPATH:       /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2/bin/bootstrap.jar:/home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2/bin/tomcat-juli.jar  
可以查看两个tomcat的启动日志,对比一下:
  • tomcat-1的日志
[plain]  view plain copy
  1. shirdrn@dev:~/servers/cluster/nginx_tomcat_memcached$ tail -100f tomcat-1/logs/catalina.out  
  2. Jan 26, 2013 12:03:25 AM org.apache.catalina.core.AprLifecycleListener init  
  3. INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /home/hadoop/installation/jdk1.6.0_30/jre/lib/i386/client:/home/hadoop/installation/jdk1.6.0_30/jre/lib/i386:/home/hadoop/installation/jdk1.6.0_30/jre/../lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib  
  4. Jan 26, 2013 12:03:26 AM org.apache.coyote.AbstractProtocol init  
  5. INFO: Initializing ProtocolHandler ["http-bio-8088"]  
  6. Jan 26, 2013 12:03:26 AM org.apache.coyote.AbstractProtocol init  
  7. INFO: Initializing ProtocolHandler ["ajp-bio-8089"]  
  8. Jan 26, 2013 12:03:26 AM org.apache.catalina.startup.Catalina load  
  9. INFO: Initialization processed in 1743 ms  
  10. Jan 26, 2013 12:03:26 AM org.apache.catalina.core.StandardService startInternal  
  11. INFO: Starting service Catalina  
  12. Jan 26, 2013 12:03:26 AM org.apache.catalina.core.StandardEngine startInternal  
  13. INFO: Starting Servlet Engine: Apache Tomcat/7.0.26  
  14. Jan 26, 2013 12:03:27 AM de.javakaffee.web.msm.MemcachedSessionService startInternal  
  15. INFO: MemcachedSessionService starts initialization... (configured nodes definition n1:192.168.1.104:11211,n2:192.168.1.104:11311, failover nodes n1)  
  16. 2013-01-26 00:03:27.441 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/192.168.1.104:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue  
  17. 2013-01-26 00:03:27.442 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/192.168.1.104:11311, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue  
  18. Jan 26, 2013 12:03:27 AM de.javakaffee.web.msm.RequestTrackingHostValve <init>  
  19. INFO: Setting ignorePattern to .*\.(png|gif|jpg|css|js)$  
  20. 2013-01-26 00:03:27.459 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@5b0668  
  21. 2013-01-26 00:03:27.460 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@1d5a0  
  22. Jan 26, 2013 12:03:27 AM de.javakaffee.web.msm.MemcachedSessionService setLockingMode  
  23. INFO: Setting lockingMode to null  
  24. Jan 26, 2013 12:03:27 AM de.javakaffee.web.msm.MemcachedSessionService createTranscoderFactory  
  25. INFO: Creating transcoder factory de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory  
  26. Jan 26, 2013 12:03:27 AM de.javakaffee.web.msm.MemcachedSessionService startInternal  
  27. INFO: MemcachedSessionService finished initialization, sticky true, operation timeout 1000, with node ids [n2] and failover node ids [n1]  
  28. Jan 26, 2013 12:03:27 AM org.apache.catalina.startup.HostConfig deployDirectory  
  29. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1/webapps/host-manager  
  30. Jan 26, 2013 12:03:27 AM org.apache.catalina.startup.HostConfig deployDirectory  
  31. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1/webapps/manager  
  32. Jan 26, 2013 12:03:27 AM org.apache.catalina.startup.HostConfig deployDirectory  
  33. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1/webapps/docs  
  34. Jan 26, 2013 12:03:27 AM org.apache.catalina.startup.HostConfig deployDirectory  
  35. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1/webapps/examples  
  36. Jan 26, 2013 12:03:28 AM org.apache.catalina.startup.HostConfig deployDirectory  
  37. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-1/webapps/ROOT  
  38. Jan 26, 2013 12:03:28 AM org.apache.coyote.AbstractProtocol start  
  39. INFO: Starting ProtocolHandler ["http-bio-8088"]  
  40. Jan 26, 2013 12:03:28 AM org.apache.coyote.AbstractProtocol start  
  41. INFO: Starting ProtocolHandler ["ajp-bio-8089"]  
  42. Jan 26, 2013 12:03:28 AM org.apache.catalina.startup.Catalina start  
  43. INFO: Server startup in 1487 ms  
  • tomcat-2的日志
[plain]  view plain copy
  1. shirdrn@dev:~/servers/cluster/nginx_tomcat_memcached$ tail -100f tomcat-2/logs/catalina.out  
  2. Jan 26, 2013 12:04:34 AM org.apache.catalina.core.AprLifecycleListener init  
  3. INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /home/hadoop/installation/jdk1.6.0_30/jre/lib/i386/client:/home/hadoop/installation/jdk1.6.0_30/jre/lib/i386:/home/hadoop/installation/jdk1.6.0_30/jre/../lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib  
  4. Jan 26, 2013 12:04:34 AM org.apache.coyote.AbstractProtocol init  
  5. INFO: Initializing ProtocolHandler ["http-bio-9088"]  
  6. Jan 26, 2013 12:04:34 AM org.apache.coyote.AbstractProtocol init  
  7. INFO: Initializing ProtocolHandler ["ajp-bio-9089"]  
  8. Jan 26, 2013 12:04:34 AM org.apache.catalina.startup.Catalina load  
  9. INFO: Initialization processed in 742 ms  
  10. Jan 26, 2013 12:04:34 AM org.apache.catalina.core.StandardService startInternal  
  11. INFO: Starting service Catalina  
  12. Jan 26, 2013 12:04:34 AM org.apache.catalina.core.StandardEngine startInternal  
  13. INFO: Starting Servlet Engine: Apache Tomcat/7.0.26  
  14. Jan 26, 2013 12:05:07 AM org.apache.catalina.util.SessionIdGenerator createSecureRandom  
  15. INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [33,094] milliseconds.  
  16. Jan 26, 2013 12:05:07 AM de.javakaffee.web.msm.MemcachedSessionService startInternal  
  17. INFO: MemcachedSessionService starts initialization... (configured nodes definition n1:192.168.1.104:11211,n2:192.168.1.104:11311, failover nodes n2)  
  18. 2013-01-26 00:05:07.873 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/192.168.1.104:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue  
  19. 2013-01-26 00:05:07.876 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/192.168.1.104:11311, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue  
  20. Jan 26, 2013 12:05:07 AM de.javakaffee.web.msm.RequestTrackingHostValve <init>  
  21. INFO: Setting ignorePattern to .*\.(png|gif|jpg|css|js)$  
  22. 2013-01-26 00:05:07.896 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@701a27  
  23. 2013-01-26 00:05:07.897 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@1d5a0  
  24. Jan 26, 2013 12:05:07 AM de.javakaffee.web.msm.MemcachedSessionService setLockingMode  
  25. INFO: Setting lockingMode to null  
  26. Jan 26, 2013 12:05:07 AM de.javakaffee.web.msm.MemcachedSessionService createTranscoderFactory  
  27. INFO: Creating transcoder factory de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory  
  28. Jan 26, 2013 12:05:07 AM de.javakaffee.web.msm.MemcachedSessionService startInternal  
  29. INFO: MemcachedSessionService finished initialization, sticky true, operation timeout 1000, with node ids [n1] and failover node ids [n2]  
  30. Jan 26, 2013 12:05:08 AM org.apache.catalina.startup.HostConfig deployDirectory  
  31. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2/webapps/host-manager  
  32. Jan 26, 2013 12:05:08 AM org.apache.catalina.startup.HostConfig deployDirectory  
  33. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2/webapps/manager  
  34. Jan 26, 2013 12:05:08 AM org.apache.catalina.startup.HostConfig deployDirectory  
  35. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2/webapps/docs  
  36. Jan 26, 2013 12:05:08 AM org.apache.catalina.startup.HostConfig deployDirectory  
  37. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2/webapps/examples  
  38. Jan 26, 2013 12:05:08 AM org.apache.catalina.startup.HostConfig deployDirectory  
  39. INFO: Deploying web application directory /home/shirdrn/servers/cluster/nginx_tomcat_memcached/tomcat-2/webapps/ROOT  
  40. Jan 26, 2013 12:05:08 AM org.apache.coyote.AbstractProtocol start  
  41. INFO: Starting ProtocolHandler ["http-bio-9088"]  
  42. Jan 26, 2013 12:05:08 AM org.apache.coyote.AbstractProtocol start  
  43. INFO: Starting ProtocolHandler ["ajp-bio-9089"]  
  44. Jan 26, 2013 12:05:08 AM org.apache.catalina.startup.Catalina start  
  45. INFO: Server startup in 34163 ms  
已经成功启动了。

Nginx安装、配置、启动

在Ubuntu系统下,如果没有安装Nginx,可以执行如下命令进行安装:
[plain]  view plain copy
  1. sudo apt-get install nginx  
默认情况下,Nginx使用默认的配置文件/etc/nginx/nginx.conf,该配置文件直接包含了虚拟目录配置文件/etc/nginx/sites-available/default,修改该文件的内容为,如下所示:
[plain]  view plain copy
  1. # You may add here your  
  2. # server {  
  3. #     ...  
  4. # }  
  5. # statements for each of your virtual hosts to this file  
  6.   
  7. ##  
  8. # You should look at the following URL's in order to grasp a solid understanding  
  9. # of Nginx configuration files in order to fully unleash the power of Nginx.  
  10. # http://wiki.nginx.org/Pitfalls  
  11. # http://wiki.nginx.org/QuickStart  
  12. # http://wiki.nginx.org/Configuration  
  13. #  
  14. # Generally, you will want to move this file somewhere, and start with a clean  
  15. # file but keep this around for reference. Or just disable in sites-enabled.  
  16. #  
  17. # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.  
  18. ##  
  19.   
  20.   
  21.   
  22. upstream dev.shirdrn.org {  
  23.      server 192.168.1.104:8088 weight=1;  
  24.      server 192.168.1.104:9088 weight=1;  
  25. }  
  26.   
  27.   
  28. server {  
  29.      #listen   80; ## listen for ipv4; this line is default and implied  
  30.      #listen   [::]:80 default ipv6only=on; ## listen for ipv6  
  31.   
  32.      root /usr/share/nginx/www/session;  # session是我们配置的虚拟目录,实际直接指向Tomcat下名为session的web应用  
  33.      index index.html index.htm;  
  34.   
  35.      # Make site accessible from http://localhost/  
  36. #######     server_name localhost;  
  37.      server_name dev.shirdrn.org; # Nginx服务所在主机  
  38.      charset utf-8;  
  39.   
  40.      location / {  
  41.           proxy_pass     http://dev.shirdrn.org; #直接代理tomcat集群  
  42.           proxy_set_header  X-Real-IP  $remote_addr;  
  43.           client_max_body_size  100m;  
  44.   
  45.   
  46.   
  47.           # First attempt to serve request as file, then  
  48.           # as directory, then fall back to index.html  
  49. #######          try_files $uri $uri/ /index.html;  
  50.           # Uncomment to enable naxsi on this location  
  51.           # include /etc/nginx/naxsi.rules  
  52.      }  
  53.   
  54.      location ~ ^/(WEB-INF)/ { # 禁止访问Tomcat下web应用的WEB-INF目录下的资源  
  55.           deny all;  
  56.      }  
  57.   
  58.      location /doc/ {  
  59.           alias /usr/share/doc/;  
  60.           autoindex on;  
  61.           allow 127.0.0.1;  
  62.           deny all;  
  63.      }  
  64.   
  65.      # Only for nginx-naxsi : process denied requests  
  66.      #location /RequestDenied {  
  67.           # For example, return an error code  
  68.           #return 418;  
  69.      #}  
  70.   
  71.      #error_page 404 /404.html;  
  72.   
  73.      # redirect server error pages to the static page /50x.html  
  74.      #  
  75.      #error_page 500 502 503 504 /50x.html;  
  76.      #location = /50x.html {  
  77.      #     root /usr/share/nginx/www;  
  78.      #}  
  79.   
  80.      # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000  
  81.      #  
  82.      #location ~ \.php$ {  
  83.      #     fastcgi_split_path_info ^(.+\.php)(/.+)$;  
  84.      #     # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini  
  85.      #  
  86.      #     # With php5-cgi alone:  
  87.      #     fastcgi_pass 127.0.0.1:9000;  
  88.      #     # With php5-fpm:  
  89.      #     fastcgi_pass unix:/var/run/php5-fpm.sock;  
  90.      #     fastcgi_index index.php;  
  91.      #     include fastcgi_params;  
  92.      #}  
  93.   
  94.      # deny access to .htaccess files, if Apache's document root  
  95.      # concurs with nginx's one  
  96.      #  
  97.      #location ~ /\.ht {  
  98.      #     deny all;  
  99.      #}  
  100. }  
  101.   
  102.   
  103. # another virtual host using mix of IP-, name-, and port-based configuration  
  104. #  
  105. #server {  
  106. #     listen 8000;  
  107. #     listen somename:8080;  
  108. #     server_name somename alias another.alias;  
  109. #     root html;  
  110. #     index index.html index.htm;  
  111. #  
  112. #     location / {  
  113. #          try_files $uri $uri/ /index.html;  
  114. #     }  
  115. #}  
  116.   
  117.   
  118. # HTTPS server  
  119. #  
  120. #server {  
  121. #     listen 443;  
  122. #     server_name localhost;  
  123. #  
  124. #     root html;  
  125. #     index index.html index.htm;  
  126. #  
  127. #     ssl on;  
  128. #     ssl_certificate cert.pem;  
  129. #     ssl_certificate_key cert.key;  
  130. #  
  131. #     ssl_session_timeout 5m;  
  132. #  
  133. #     ssl_protocols SSLv3 TLSv1;  
  134. #     ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;  
  135. #     ssl_prefer_server_ciphers on;  
  136. #  
  137. #     location / {  
  138. #          try_files $uri $uri/ /index.html;  
  139. #     }  
  140. #}  
上面配置中根目录为/usr/share/nginx/www,因为我们使用到了一个虚拟目录来对应Tomcat下部署的web应用的path,所以需要在/usr/share/nginx/www下面创建这个对应的虚拟目录:
[plain]  view plain copy
  1. shirdrn@dev:~/servers/cluster/nginx_tomcat_memcached$ sudo mkdir /usr/share/nginx/www/session  
最后,可以启动Nginx服务器,执行如下命令:
[plain]  view plain copy
  1. shirdrn@dev:~$ sudo /etc/init.d/nginx start  
查询Nginx服务启动状态:
[plain]  view plain copy
  1. shirdrn@dev:~/servers/cluster/nginx_tomcat_memcached$ sudo ps -ef | grep nginx  
  2. root      3199     1  0 Jan25 ?        00:00:00 nginx: master process /usr/sbin/nginx  
  3. www-data  3200  3199  0 Jan25 ?        00:00:00 nginx: worker process  
  4. www-data  3201  3199  0 Jan25 ?        00:00:00 nginx: worker process  
  5. www-data  3202  3199  0 Jan25 ?        00:00:00 nginx: worker process  
  6. www-data  3203  3199  0 Jan25 ?        00:00:00 nginx: worker process  
  7. shirdrn   3327  3095  0 00:01 pts/5    00:00:00 grep --color=auto nginx  
这是就可以通过Nginx访问(代理)Web应用首页了。

集群验证

上面配置完成,服务都已经启动成功,可以直接请求链接 http://dev.shirdrn.org/session,就会直接访问部署在Tomcat服务器上的Java Web应用,看到登录页面。
使用前面准备的Web应用session中账号数据进行模拟登录,就可以查看Memcached缓存的数据:
  • telnet 192.168.1.104 11211
telnet到memcached服务端口,查看缓存统计数据。
[plain]  view plain copy
  1. shirdrn@dev:~$ telnet 192.168.1.104 11211  
  2. Trying 192.168.1.104...  
  3. Connected to 192.168.1.104.  
  4. Escape character is '^]'.  
  5.   
  6. ERROR  
  7. stats  
  8. STAT pid 3300  
  9. STAT uptime 2148  
  10. STAT time 1359131741  
  11. STAT version 1.4.13  
  12. STAT libevent 2.0.16-stable  
  13. STAT pointer_size 32  
  14. STAT rusage_user 0.052003  
  15. STAT rusage_system 0.084005  
  16. STAT curr_connections 7  
  17. STAT total_connections 9  
  18. STAT connection_structures 8  
  19. STAT reserved_fds 20  
  20. STAT cmd_get 23  
  21. STAT cmd_set 6  
  22. STAT cmd_flush 0  
  23. STAT cmd_touch 0  
  24. STAT get_hits 2  
  25. STAT get_misses 21  
  26. STAT delete_misses 0  
  27. STAT delete_hits 0  
  28. STAT incr_misses 0  
  29. STAT incr_hits 0  
  30. STAT decr_misses 0  
  31. STAT decr_hits 0  
  32. STAT cas_misses 0  
  33. STAT cas_hits 0  
  34. STAT cas_badval 0  
  35. STAT touch_hits 0  
  36. STAT touch_misses 0  
  37. STAT auth_cmds 0  
  38. STAT auth_errors 0  
  39. STAT bytes_read 2675  
  40. STAT bytes_written 2835  
  41. STAT limit_maxbytes 67108864  
  42. STAT accepting_conns 1  
  43. STAT listen_disabled_num 0  
  44. STAT threads 4  
  45. STAT conn_yields 0  
  46. STAT hash_power_level 16  
  47. STAT hash_bytes 262144  
  48. STAT hash_is_expanding 0  
  49. STAT expired_unfetched 0  
  50. STAT evicted_unfetched 0  
  51. STAT bytes 858  
  52. STAT curr_items 2  
  53. STAT total_items 6  
  54. STAT evictions 0  
  55. STAT reclaimed 0  
  56. END  
  • telnet 192.168.1.104 11311
[plain]  view plain copy
  1. shirdrn@dev:~$ telnet 192.168.1.104 11311  
  2. Trying 192.168.1.104...  
  3. Connected to 192.168.1.104.  
  4. Escape character is '^]'.  
  5. stats  
  6. STAT pid 3308  
  7. STAT uptime 2398  
  8. STAT time 1359132000  
  9. STAT version 1.4.13  
  10. STAT libevent 2.0.16-stable  
  11. STAT pointer_size 32  
  12. STAT rusage_user 0.004000  
  13. STAT rusage_system 0.128008  
  14. STAT curr_connections 7  
  15. STAT total_connections 9  
  16. STAT connection_structures 8  
  17. STAT reserved_fds 20  
  18. STAT cmd_get 1  
  19. STAT cmd_set 2  
  20. STAT cmd_flush 0  
  21. STAT cmd_touch 0  
  22. STAT get_hits 0  
  23. STAT get_misses 1  
  24. STAT delete_misses 1  
  25. STAT delete_hits 0  
  26. STAT incr_misses 0  
  27. STAT incr_hits 0  
  28. STAT decr_misses 0  
  29. STAT decr_hits 0  
  30. STAT cas_misses 0  
  31. STAT cas_hits 0  
  32. STAT cas_badval 0  
  33. STAT touch_hits 0  
  34. STAT touch_misses 0  
  35. STAT auth_cmds 0  
  36. STAT auth_errors 0  
  37. STAT bytes_read 644  
  38. STAT bytes_written 2109  
  39. STAT limit_maxbytes 67108864  
  40. STAT accepting_conns 1  
  41. STAT listen_disabled_num 0  
  42. STAT threads 4  
  43. STAT conn_yields 0  
  44. STAT hash_power_level 16  
  45. STAT hash_bytes 262144  
  46. STAT hash_is_expanding 0  
  47. STAT expired_unfetched 1  
  48. STAT evicted_unfetched 0  
  49. STAT bytes 0  
  50. STAT curr_items 0  
  51. STAT total_items 2  
  52. STAT evictions 0  
  53. STAT reclaimed 1  
  54. END  

我们可以停掉某个Tomcat服务,然后观察Session会话数据的复制过程,能够保证当前集群中的会话数据不丢失,另一个结点仍然能提供基于该存在Session的服务。

1,tomcat8的配置: 1.1修改tomcat8.x/conf/context.xml的配置如下: <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- The contents of this file will be loaded for each web application --> <Context> <!-- Default set of monitored resources. If one of these changes, the --> <!-- web application will be reloaded. --> <WatchedResource>WEB-INF/web.xml</WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> <!-- Uncomment this to disable session persistence across Tomcat restarts --> <!-- <Manager pathname="" /> <Resources cachingAllowed="true" cacheMaxSize="100000" /> <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:127.0.0.1:11211" username="root" password="" sticky="false" sessionBackupAsync="false" lockingMode="uriPattern:/path1|/path2" requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" /> --> <Resources cachingAllowed="true" cacheMaxSize="100000" /> <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:127.0.0.1:11211" username="root" password="" sticky="false" sessionBackupAsync="false" lockingMode="uriPattern:/path1|/path2" requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" sessionBackupTimeout="18000" transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory" copyCollectionsForSerialization="false" /> </Context> 1.2添加memcached如下依赖的jar包到tomcat8.x/lib/: asm-5.1.jar couchbase-client-1.4.12.jar javolution-5.5.1.jar kryo-4.0.0.jar kryo-serializers-0.38.jar memcached-session-manager-2.0.0.jar memcached-session-manager-tc8-2.0.0.jar minlog-1.3.jar msm-javolution-serializer-2.0.0.jar msm-kryo-serializer-2.0.0.jar msm-xstream-serializer-2.0.0.jar objenesis-2.1.jar reflectasm-1.09.jar spymemcached-2.12.1.jar 2,nginx配置: #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; client_header_timeout 3m; client_body_timeout 3m; send_timeout 3m; sendfile on; tcp_nopush on; tcp_nodelay on; #keepalive_timeout 0; keepalive_timeout 65; gzip on; #设定负载均衡的服务器列表 upstream 127.0.0.1 { #设定负载均衡的服务器列表 #ip_hash; #同一机器在多网情况下,路由切换,ip可能不同 #weigth参数表示权值,权值越高被分配到的几率越大 server 127.0.0.1:8085 weight=1 max_fails=20 fail_timeout=600s; server 127.0.0.1:8086 weight=1 max_fails=20 fail_timeout=600s; } map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name localhost; charset UTF-8; #设定本虚拟主机的访问日志 access_log logs/host.access.log main; #对 "/" 所有应用启用负载均衡 location / { proxy_pass http://127.0.0.1; #保留用户真实信息 proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; index index.html index.htm index.aspx; } #对 "/Dossm3RabbitMQConsumer/" 启用负载均衡 location /Dossm3RabbitMQConsumer/ { proxy_pass http://localhost:8086; #保留用户真实信息 proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; index index.html index.htm index.aspx; } } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} } 3,cas的配置(): 3.1 修改/CAS/WEB-INF/spring-configuration/ticketRegistry.xml <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to Jasig under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. Jasig licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at the following location: http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <description> Configuration for the default TicketRegistry which stores the tickets in-memory and cleans them out as specified intervals. </description> <!-- memcached 配置开始 --> <!-- Ticket Registry --> <bean id="ticketRegistry" class="org.jasig.cas.ticket.registry.MemCacheTicketRegistry"> <constructor-arg index="0"> <bean class="net.spy.memcached.spring.MemcachedClientFactoryBean" p:servers="127.0.0.1:11211" p:protocol="BINARY" p:locatorType="ARRAY_MOD" p:failureMode="Redistribute" p:transcoder-ref="serialTranscoder"> <property name="hashAlg"> <util:constant static-field="net.spy.memcached.DefaultHashAlgorithm.FNV1A_64_HASH" /> </property> </bean> </constructor-arg> <!-- TGT timeout in seconds --> <constructor-arg index="1" value="36000" /> <!-- ST timeout in seconds --> <constructor-arg index="2" value="2" /> </bean> <bean id="serialTranscoder" class="net.spy.memcached.transcoders.SerializingTranscoder" p:compressionThreshold="2048" /> <!-- memcached 配置结束 --> <!--Quartz --> <!-- 默认配置开始 --> <!-- Ticket Registry --> <!-- <bean id="ticketRegistry" class="org.jasig.cas.ticket.registry.DefaultTicketRegistry" />--> <!-- TICKET REGISTRY CLEANER --> <!-- <bean id="ticketRegistryCleaner" class="org.jasig.cas.ticket.registry.support.DefaultTicketRegistryCleaner" p:ticketRegistry-ref="ticketRegistry" p:logoutManager-ref="logoutManager" /> <bean id="jobDetailTicketRegistryCleaner" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" p:targetObject-ref="ticketRegistryCleaner" p:targetMethod="clean" /> <bean id="triggerJobDetailTicketRegistryCleaner" class="org.springframework.scheduling.quartz.SimpleTriggerBean" p:jobDetail-ref="jobDetailTicketRegistryCleaner" p:startDelay="200000" p:repeatInterval="50000000" /> --> <!-- 默认配置结束 --> </beans> 3.2 添加cas和memcached整合的如下依赖jar包到/CAS/WEB-INF/lib: cas-server-integration-memcached-4.0.0.jar mockito-core-2.1.0-RC.1.jar spymemcached-2.11.2.jar 参考CAS官方配置:https://apereo.github.io/cas/4.2.x/installation/Memcached-Ticket-Registry.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值