环境:Cent OS 7.0(虚拟机环境)、Nginx 1.9.8、Redis 3.2.1
一、背景
在使用Nginx+Tomcat实现负载均衡的时候,由于Nginx对不同的请求分发到某一个Tomcat,Tomcat在运行的时候分别是不同的容器里,因为会出现session不同步或者丢失的问题。
二、Nginx安装与配置
1、Nginx安装
网上的资源对于安装Nginx的介绍比较多,例如最简单的为:
(1) 获取nginx,在http://nginx.org/download/上可以获取当前最新的版本下载,例如:
wget http://nginx.org/download/nginx-1.9.8.tar.gz
(2)解压缩tar -xvf nginx-1.9.8.tar.gz包。
(3)进入解压缩目录,执行./configure --prefix=/usr/local/nginx-1.9.8 将Nginx安装到/usr/local/nginx-1.9.8目录下
(4)make & make install
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
安装的过程会将Nginx安装到/usr/local/nginx-1.9.8目录下,启动Nginx测试是否可以正常启动。
2、修改Nginx配置多Tomcat服务器
2.1、修改conf/nginx.conf文件,在server标签上边添加upstream如下:
upstream mynginxserver {
#weigth参数表示权值,权值越高被分配到的几率越大
#本机上的Squid开启3128端口
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8060 weight=1;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
这里指定了本机下的两个Tomcat实例,端口分别为8080,8060,权重都为1,后边配置Tomcat实例,mynginxserver这个是自己随意命名的,下边要用到
2.2、配置server标签;
server {
listen 80;
server_name 192.168.1.149;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
# root html;
# index index.html index.htm;
proxy_pass http://mynginxserver;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
2.3、配置之后的完整内容如下(1.9.8版本删去了注释后的配置内容):
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream mynginxserver {
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8060 weight=1;
}
server {
listen 80;
server_name 192.168.1.149;
location / {
proxy_pass http://mynginxserver;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
2.4、具体的配置项和配置项的具体意义请参考
https://www.nginx.com/resources/wiki/start/topics/examples/full/
三、Tomcat多实例的配置
1、解压apache-tomcat-7.0.67.zip 得到apache-tomcat-7.0.67
[root@localhost www]# unzip apache-tomcat-7.0.67.zip
- 1
- 2
- 1
- 2
2、将apache-tomcat-7.0.67重命名为tomcat1
[root@localhost www]# mv apache-tomcat-7.0.67 tomcat1
- 1
- 2
- 1
- 2
重复1、2过程得到tomcat1和tomcat2如下所示:
3、修改Tomcat1的端口为8080和部署项目文件
编辑tomcat下的conf/server.xml,修改端口号为8080,
自己写的用于测试Nginx反向代理的web项目war包下载地址:http://download.csdn.net/detail/u010870518/9585683
下载好之后将解压之后的编译好的项目文件放到tomcat1/webapps/ROOT/目录下:
修改index.jsp和login.jsp文件分别标识为具体的Tomcat容器
4、修改Tomcat2的端口为8060和部署项目文件
编辑tomcat下的conf/server.xml,修改端口号为8060,然后和上述3中的一样,下载war内容,放在tomcat2/webapps/ROOT/下,修改index.jsp和login.jsp用于标识具体的Tomcat容器
5、分别启动tomcat1和tomcat2
6、重启Nginx服务,访问IP地址:192.168.1.149:80(这个是访问的虚拟机IP地址)
7、观看效果
可以看出,Nginx已经进行了请求分发,转发到具体的某一个Tomcat
四、Redis的安装与配置
由于篇幅过长,请参考本人写的:http://blog.csdn.net/xlgen157387/article/details/52022793
五、tomcat-redis-session-manager开源项目的使用
1、开源项目地址:https://github.com/jcoleman/tomcat-redis-session-manager
2、下载代码之后需要进行重新编译,生成所需要的jar,任意创建maven项目,将src下的代码拷贝到具体位置,如下:
maven的pom.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ufind.session</groupId>
<artifactId>tomcat-redis-session</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>7.0.27</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
3、然后打开terminal,执行mvn clean 和mvn install 将编译好的代码打包为:tomcat-redis-session-1.0-SNAPSHOT.jar
4、将tomcat-redis-session-1.0-SNAPSHOT.jar、jedis-2.7.2.jar、commons-pool2-2.0.jar 三个jar包分别放在tomcat1和tomcat2实例下的lib目录下。
免费下载这三个jar:http://download.csdn.net/detail/u010870518/9585716
5、修改tomcat实例下conf/contex.xml文件
<?xml version=‘1.0‘ encoding=‘utf-8‘?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- tomcat-redis-session共享配置 -->
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.1.149"
port="6379"
database="0"
maxInactiveInterval="60" />
</Context>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
如果Redis配置了访问权限,请添加密码为:
<?xml version=‘1.0‘ encoding=‘utf-8‘?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- tomcat-redis-session共享配置 -->
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.1.149"
port="6379"
database="0"
password="redispassword"
maxInactiveInterval="60" />
</Context>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
如果不设置密码会报错,如下:
六、效果演示
案例演示的一个登陆请求,登陆成功之后将用户信息放在session中,在界面中显示出来(tomcat1实例,tomcat2的实例中只是在 h2 标签中做了一下标识)
1、login.jsp文件:
<body>
<h2>Session Demo in Tomcat1</h2>
<form action="/user?type=login" method="post">
用户名:<input type="text" name="userName"/><br/>
密码:<input type="password" name="userPassword"/><br/>
<input type="submit" value="login">
</form>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2、index.jsp 将登录之后的信息显示在界面上
<body>
<h2>Session Demo in Tomcat1</h2>
<%
User user = (User) request.getSession().getAttribute("USER");
if (user == null) {
%>
用户为空,没有登录!!!
<%
} else {
%>
欢迎: <%=user.getUserName()%>
<%
}
%>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
3、servlet处理请求代码
public class UserServlet extends BaseServlet {
public String login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
User user = new User();
user.setUserName(request.getParameter("userName"));
user.setUserPassword(request.getParameter("userPassword"));
request.getSession().setAttribute("USER", user);
return "index.jsp";
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
4、效果如下:
可以看出在登录界面的时候刷新请求的tomcat已经由Nginx进行分发请求,登录之后再两个tomcta中已经共享了session
5、查看Redis对session的存储
在对contex.xml文件进行配置的时候默认使用的database为0,通过redis-cli工具可看到
七、总结
tomcat-redis-session-manager是一个对用户完全透明的分布式session存储框架,用户只需要在tomcat中进行简单的配置,就可以使用,我们的业务代码是完全和单实例的时候的代码是一样的的,也就是写代码的时候完全不用担心你写的是一个多tomcat实例的代码,完全透明。
如何对框架的原理进行简单的理解,我们首先要知道,在请求过程中的session操作,首先要解析请求中的sessionId信息,然后将sessionId存储到request的参数列表中。然后再从 request获取session的时候,如果存在sessionId那么就根据Id从session池中获取session,如果sessionId不存在或者session失效,那么则新建session并且将session信息放入session池,供下次使用。
如果我们想自己写一个类似于tomcat-redis-session-manager的项目,我们应该知道Tomcat的Session管理机制,在默认的情况下Tomcat的Session管理,如果不进行设置的话是由Tomcat自带的StandardManager类进行控制的,我们可以根据这个类自定义一个Manager,主要重写的就是org.apache.catalina.session.ManagerBase里边的具体写的操作,
这也是tomcat-redis-session-manager的基本原理,将tomcat的session存储位置指向了Redis
RedisSessionManager继承了org.apache.catalina.session.ManagerBase并重写了add、findSession、createEmptySession、remove等方法,并将对session的增删改查操作指向了对Redis数据存储的操作
有兴趣可参考一篇Tomcat中session的管理机制:http://www.cnblogs.com/interdrp/p/4935614.html