本篇讲述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控制台部署
Tomcat7部署多个Web项目的方法-有图有真相,不下你后悔。
Tomcat部署,Tomcat部署,Tomcat部署,Tomcat部署,Tomcat部署,Tomcat部署,Tomcat部署
本文档主要针对tomcat热部署需要修改哪些配置文件,如何实现热部署,提供解决说明
jdk和tomcat安装部署jdk和tomcat安装部署jdk和tomcat安装部署
详细地说明在Tomcat中部署JavaWeb应用
ApacheTomcat集群部署配置整合方案
Tomcat的热部署(以后就不用重起了) tomcat上的部署问题,有时候也是个麻烦的问题,要是不采用热部署, 我们就只能每次对原来的文件做一次改动的时候就要重新部署。
maven项目完成tomcat的部署,完美解决maven建立的项目转成web项目,并且部署到tomcat的解决方法
测试demo: tomcat服务器servlet实现
IDEA+Tomcat热部署配置.doc
在tomcat中部署web项目的基本方式,简单明了,希望能帮助到大家。
重启Tomcat即可,以后调试就方便了!替换.class文件就不用再重启Tomcat了。
ssh Tomcat自动部署无需手动重启服务器设置
NULL 博文链接:https://yunlong167167.iteye.com/blog/2087430
在用maven项目的时候,很多时候不想去再把项目部署到Tomcat上,然后发布并启动,这个时候我们就可以运用Tomcat热部署来配置,只需要再maven的配置文件加上一小段代码即可,非常方便! 启动的时候直接:右键项目--...
如何在Tomcat6.0上运行项目? 如何在Myeclipse IDE部署运行项目? 下载看看吧,希望有帮助!
IIS+Tomcat项目部署IIS+Tomcat项目部署IIS+Tomcat项目部署
单tomcat 实例下 部署多应用程序实现。 实现简单,容易上手。。。
linux下按照tomcat并部署web项目