tomcat msm部署

本篇讲述tomcat msm,实现由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两实例上。

Nginx 8888端口,如果为非80端口,用ngnix分发tomcatJ2ee应用重定向会自动跳转到80端口,需要做特殊处理。

MSM介绍

传统tomcat集群,会话复制随着结点数增多,扩展性成为瓶颈。Msm使用memcached完成统一管理tomcat会话,避免tomcat结点间过多会话复制。MSM会话分为stickyno-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      --tc8tomcat的版本号。不同版本号tomcat,对应的包不同。此处为tomcat8jar

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 -m 128 -p 11213 -u root

 

2. 运行11214端口memcached实例 

./memcached -d -m 128 -p 11214 -u root

运行ngnix

cd sbin

./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会话数据不完整。



1,在tomcat中找到文件apache-tomcat-6.0.37\conf\context.xml 加入内部 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.1.65:11211" requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$" sessionBackupAsync="false" sessionBackupTimeout="100" transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory" copyCollectionsForSerialization="false" /> 加入之后的content.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 --> <WatchedResource>WEB-INF/web.xml</WatchedResource> <!-- Uncomment this to disable session persistence across Tomcat restarts --> <!-- <Manager pathname="" /> --> <!-- Uncomment this to enable Comet connection tacking (provides events on session expiration as well as webapp lifecycle) --> <!-- <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" /> <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值