本篇讲述tomcatmsm,实现由memcached集中式管理会话模式。
实验环境
主机 |
端口 |
开源软件 |
192.168.161.73 |
8081 |
tomcat |
192.168.161.73 |
8080 |
tomcat |
192.168.161.73 |
11213 |
memcached |
192.168.161.73 |
11214 |
memcached |
192.168.161.73 |
8888 |
nginx |
说明:
8080、8081分别为tomcat两实例;
11212、11213分别为memcached两实例;
web应用示例工程casdemo部署在tomcat两实例上。
Nginx8888端口,如果为非80端口,用ngnix分发tomcat中J2ee应用重定向会自动跳转到80端口,需要做特殊处理。
MSM介绍
传统tomcat集群,会话复制随着结点数增多,扩展性成为瓶颈。Msm使用memcached完成统一管理tomcat会话,避免tomcat结点间过多会话复制。MSM会话分为sticky与no-ticky模式。
sticky:会话粘连模式。客户端在一台tomcat实例上完成登录后,以后的请求均会根据IP直接绑定到该tomcat实例。
no-sticky:会话非粘连模式。客户端的请求是随机分发,多台tomcat实例均会收到请求。
MSM依赖包
spymemcached-2.11.1.jar
reflectasm-1.01.jar
msm-kryo-serializer-1.8.3.jar
msm-javolution-serializer-1.8.3.jar
msm-flexjson-serializer-1.8.3.jar
minlog-1.2.jar
memcached-session-manager-tc8-1.8.3.jar--tc8为tomcat的版本号。不同版本号tomcat,对应的包不同。此处为tomcat8的jar包
memcached-session-manager-1.8.3.jar
kryo-serializers-0.11.jar
kryo-1.04.jar
asm-3.2.jar
放到tomcat/lib下
tomcat配置
1.8080端口tomcat实例关键配置
修改tomcat目录下conf/server.xml。修改的内容下面用红色加粗标注。
<Server port="8005" shutdown="SHUTDOWN"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"> ---非必选 ,只有选择了sticky模式才加入jvmRoute属性。不同的tomcat实例 jvmRoute取值不能相同。例:8080端口的tomcat实例jvmRoute=tomcat1,8081端口的tomcat实例jvmRoute=tomcat2
2.8081端口tomcat实例关键配置
<Server port="9005" shutdown="SHUTDOWN"> <Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector port="9009" protocol="AJP/1.3" redirectPort="8443" /> <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2"> ---非必选 ,只有选择了sticky模式才加入jvmRoute属性。不同的tomcat实例 jvmRoute取值不能相同。例:8080端口的tomcat实例jvmRoute=tomcat1,8081端口的tomcat实例jvmRoute=tomcat2
3.msm配置
修改tomcat目录下conf/context.xml。修改的内容下面用红色加粗标注。
No-Stick模式
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.161.73:11213,n2:192.168.161.73:11214" lockingMode="auto" sticky="false" requestUriIgnorePattern=".*\.(png|gif|jpg|css|js|ico|jpeg|htm|html)$" sessionBackupAsync="false" sessionBackupTimeout="1800000" copyCollectionsForSerialization="false" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
Stick模式
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.161.73:11213,n2:192.168.161.73:11214" lockingMode="auto" sticky="true" failoverNodes="n1" requestUriIgnorePattern=".*\.(png|gif|jpg|css|js|ico|jpeg|htm|html)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTransco derFactory" />
运行memcached
1.运行11213端口memcached实例
./memcached-d-m128-p11213-uroot
2.运行11214端口memcached实例
./memcached-d-m128-p11214-uroot
运行ngnix
cdsbin
./ngnix
conf/nginx.conf供参考
#user nobody; user root root; worker_processes 2; worker_rlimit_nofile 65535; #error_log logs/error.log; error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { use epoll; worker_connections 65535; } 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_body_buffer_size 1K; client_header_buffer_size 1k; client_max_body_size 1k; large_client_header_buffers 2 1k; ##cache## proxy_connect_timeout 5; proxy_read_timeout 60; proxy_send_timeout 5; proxy_buffer_size 16k; proxy_buffers 4 64k; gzip_proxied any; proxy_busy_buffers_size 128k; proxy_temp_file_write_size 128k; proxy_temp_path /home/temp_dir; proxy_cache_path /home/cache levels=1:2 keys_zone=cache_one:200m inactive=1d max_size=1g; #gzip# gzip on; gzip_vary on; gzip_min_length 1k; gzip_buffers 4 8k; gzip_comp_level 4; gzip_http_version 1.0; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_disable "MSIE [1-6]\."; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; upstream tc{ #ip_hash; server 192.168.161.73:8080; server 192.168.161.73:8081; } server { listen 8888; server_name localhost; charset utf-8; #access_log logs/host.access.log main; location /casdemo { proxy_pass http://tc/casdemo/; # $server_port 可以不要,只有nginx的端口是非80情况下有效 proxy_set_header Host $host:$server_port; #proxy_set_header X-Real-IP $remote_addr; #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location ~ .*\.(jsp|do|action)?$ { # $server_port 可以不要,只有nginx的端口是非80情况下有效 proxy_set_header Host $host:$server_port; #proxy_set_header X-Real-IP $remote_addr; #proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://tc; } # location ~ .*\.(js)?$ # { # proxy_pass http://tc; # proxy_redirect off; # proxy_cache_key $host$uri$is_args$args; # proxy_set_header Host $host; # proxy_cache cache_one; # proxy_cache_valid 200 302 1h; # proxy_cache_valid 301 1d; # proxy_cache_valid any 1m; # expires 1h; # } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
casdemo应用
login.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <h1>TOMCAT实例1</h1> <!--此处在不同8080与8081端口tomcat实例上分别为TOMCAT实例1 、TOMCAT实例2--> <form action="login" method="post" > <input type="text" name="username"/> <input type="submit" name="login" value="login" /> </form> </body> </html> usr/index.jsp <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <h1>TOMCAT实例2</h1> <!--此处在不同8080与8081端口tomcat实例上分别为TOMCAT实例1 、TOMCAT实例2--> Hello <%=request.getSession().getAttribute("user")%>!!! <a href="../login">exit</a> </body> </html>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>casdemo</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <filter> <filter-name>CheckLoginFilter</filter-name> <filter-class>casdemo.CheckLoginFilter</filter-class> </filter> <listener> <listener-class>casdemo.DebugSessionListener</listener-class> </listener> <servlet> <servlet-name>login</servlet-name> <servlet-class>casdemo.Login</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <filter-mapping> <filter-name>CheckLoginFilter</filter-name> <url-pattern>/usr/*</url-pattern> </filter-mapping> </web-app>
CheckLoginFilter
package casdemo; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.http.HttpSession; public class CheckLoginFilter implements Filter { @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //System.out.println("====="); HttpServletRequest req=((HttpServletRequest) request); //System.out.println("getRequestURL :"+req.getRequestURL()); //System.out.println("getQueryString :"+req.getQueryString()); System.out.println((req.getSession(false)==null)+"isRequestedSessionIdFromCookie :"+req.isRequestedSessionIdFromCookie()); System.out.println((req.getSession(false)==null)+"isRequestedSessionIdValid :"+req.isRequestedSessionIdValid()); if(req.getSession(false)!=null&&!req.isRequestedSessionIdValid()){ System.out.println("====session is not valid"); } HttpSession session=req.getSession(); session.setMaxInactiveInterval(1000*60*30); if(session.getAttribute("user")!=null&&!session.getAttribute("user").equals("")){ System.out.println("alreay login"); chain.doFilter(request, response); }else{ System.out.println("not login"); //HttpServletResponse resp=((HttpServletResponse) response); HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper( (HttpServletResponse) response); wrapper.sendRedirect("/casdemo/login.jsp"); } } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
Login
package casdemo; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class Login */ public class Login extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public Login() { super(); // TODO Auto-generated constructor stub } private ApplicationContext applicationContext; /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session=request.getSession(); session.invalidate(); response.sendRedirect("login.jsp"); } public void init(ServletConfig config) throws ServletException { // TODO Auto-generatedmethod stub super.init(config); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session=request.getSession(); String username=request.getParameter("username"); session.setAttribute("user",username); response.sendRedirect("usr/index.jsp"); } }
DebugSessionListener
package casdemo; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class DebugSessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent event) { HttpSession session = event.getSession(); String sessionId = session.getId(); System.out.println(">>>>>>>>>>>create session id " + sessionId); } public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); String sessionId = session.getId(); System.out.println(">>>>>>>>>>>destory session id" + sessionId); } }
部署测试
访问http://localhost:8888/casdemo
1.测试负载分发:
测试网页是来自于tomcat1或者tomcat2的页面请求,如果是来自于tomcat1,登录页面(login.jsp)显示“TOMCAT1”,登录成功后跳转页面(index.jsp),显示“TOMCAT1”。
2.测试tomcat单点故障
登录成功后跳转页面(index.jsp),根据网页上显示的tomcat实例号,手工关闭该tomcat实例。
刷新跳转页面(index.jsp),查看页面是否还能维持会话。如果跳转到登录页,说明会话丢失。如果不跳转,显示新tomcat实例,说明会话已经在新的tomcat实例完成共享。
3.测试memcached单点故障
关闭某台memcached,测试会话是否正常。如果两台memcached没有保持同步,关闭会话没有缺失的memcached,会造成会话丢失,因为余下的memcached会话数据不完整。
相关推荐
【标题】:“Tomcat集群——使用MSM管理集群Session” 在分布式系统中,尤其是在基于Java的Web应用中,实现session的共享是确保用户状态在不同服务器之间无缝切换的关键。Tomcat,作为流行的开源Servlet容器,提供...
【标题】"Tomcat+memcached-session-manager1.8(MSM)" 是一个针对Tomcat应用服务器的解决方案,用于实现基于Memcached的会话管理。在Web应用中,session是存储用户状态的重要机制,但随着应用的扩展,单一服务器的...
Tomcat是Apache软件基金会的一个开源项目,它是一个轻量级的应用服务器,特别适合部署Java Servlet和JavaServer Pages(JSP)。 提到的`javolution`库则是一个高性能、线程安全的Java库,它提供了对序列化...
1. 在所有Tomcat服务器上部署Memcached客户端库。 2. 配置Tomcat的`context.xml`文件,设置session的持久化策略为使用Memcached客户端。 3. 配置Memcached服务,确保所有Tomcat实例都能够访问。 4. 可能还需要在应用...
7. **msm-session-manager文件**:可能包含MSM的软件包、配置示例或使用手册,帮助用户理解和部署。 对于开发和运维人员来说,掌握这些知识点是实现高效、稳定的Tomcat集群服务的关键。理解并正确实施MSM可以提高...
Memcached Session Manager (MSM) 是一个专门为Tomcat设计的开源项目,它使得Tomcat可以利用Memcached作为持久化会话存储,从而实现跨服务器的会话复制和高可用性。 **核心功能:** 1. **会话复制**:当用户的会话...
在这个压缩包中,包含的"msm"可能是指“Memcached Session Manager”,一个流行的开源解决方案,用于在Tomcat服务器之间共享Session。 Memcached Session Manager(MSM)是基于Memcached的,Memcached是一个高性能...
`msm集群session共享`是指在多个Tomcat服务器之间实现用户session数据的共享,以保证用户在集群中的任意一台服务器上都能保持登录状态和其他会话信息的连续性。这种技术常用于提升网站的可用性和负载均衡能力。 `...
在MSM的部署中,首先需要安装Memcached。对于Windows环境,可以直接在下载的memcached1.4目录中双击运行memcached.exe,它默认会在11211端口上监听。如果是Linux环境,则需要下载相应的Linux安装包进行安装。...
然而,当部署在多台Tomcat服务器上时,会话管理成为一个挑战,因为默认情况下,每个服务器只能访问其自身的session数据。为了解决这个问题,引入了分布式缓存系统memcached。 memcached(版本1.4.13)是一个高性能...
4. **测试与优化**:部署应用并测试Session共享功能。确保用户在系统中的状态在不同服务器间保持一致。可能需要调整Memcached的超时时间、Tomcat的Session超时设置等参数,以适应应用需求。 5. **安全考虑**:虽然...
标题中的“tomcat 做session共享所需jar包压缩包”指的是在多个Tomcat...在部署时,需要正确配置Tomcat和这些库,确保Session数据在集群中的无缝迁移。对于更详细的配置和实现步骤,建议参考提供的博客或其他相关文档。
在构建高性能、高可用性的Web应用系统时,会话保持是一个关键环节,它涉及到用户登录状态、购物车信息等重要数据的...在部署时,务必根据实际网络环境和服务器配置进行适当的调整,确保所有组件能正确通信和协同工作。
在实际部署中,可能还需要考虑一些其他因素,例如安全性(加密Session数据)、负载均衡策略(如何决定用户Session在哪个节点上创建)、以及性能优化(例如,调整Memcached的缓存策略)。同时,确保Memcached服务器的...
在分布式系统中,为了提高应用的可用性和扩展性,通常会采用多台服务器集群部署的方式来提供服务。对于 Java Web 应用而言,Tomcat 是一个常见的应用服务器选择。然而,在多台 Tomcat 服务器之间如何保持用户会话...
在部署时,需将这些jar包添加到Tomcat的lib目录,然后配置相关的session管理器以启用Memcache支持。在处理过程中,Kryo库被用来高效地序列化和反序列化session对象,而其他辅助库如Objenesis和ReflectASM则提高了...
- **Tomcat6**: Apache Tomcat 6是一个开源的Servlet容器,它实现了Java Servlet和JavaServer Pages (JSP) 规范,用于部署和运行Java Web应用程序。 - **Memcached**: 是一个高性能的分布式内存对象缓存系统,用于...
在部署和配置这些jar包时,你需要确保它们被正确地添加到Tomcat的类路径中。通常,这可以通过将它们放置在`$CATALINA_HOME/lib`目录下完成。然后,需要在Tomcat的`server.xml`配置文件中设置`Manager`元素,指定使用...
5. `msm-javolution-serializer-2.1.1.jar`:这是Memcached Session Manager的一个序列化模块,使用Javolution进行session对象的序列化和反序列化,以适应Memcached的数据格式。 6. `memcached-session-manager-tc8...
在实际部署时,还需要将相关的jar包(例如:`memcache-session-manager.jar`和依赖的transcoder库)添加到Tomcat的`lib`目录,以便Tomcat能够识别和使用这个Session Manager。 此外,配合使用文档,可以更深入地...