LNMT群集基于Redis实现Session共享

前言:
为了使web能适应大规模的访问,需要实现应用的集群部署。集群最有效的方案就是负载均衡,而实现负载均衡用户每一个请求都有可能被分配到不固定的服务器上,这样我们首先要解决session的统一来保证无论用户的请求被转发到哪个服务器上都能保证用户的正常用,也就是需要实现session的共享机制。

在集群系统下实现session统一的有如下几种方案:
1、请求精确定位:sessionsticky,例如基于访问ip的hash策略,即当前用户的请求都集中定位到一台服务器中,这样单台服务器保存了用户的session登录信息,如果宕机,则等同于单点部署,会丢失,会话不复制。
2、session复制共享:sessionreplication,如tomcat自带session共享,主要是指集群环境下,多台应用服务器之间同步session,使session保持一致,对外透明。 如果其中一台服务器发生故障,根据负载均衡的原理,调度器会遍历寻找可用节点,分发请求,由于sessio已同步,故能保证用户的session信息不会丢失,会话复制,。
此方案的不足之处:
必须在同一种中间件之间完成(如:tomcat-tomcat之间).
session复制带来的性能损失会快速增加.特别是当session中保存了较大的对象,而且对象变化较快时, 性能下降更加显著,会消耗系统性能。这种特性使得web应用的水平扩展受到了限制。Session内容通过广播同步给成员,会造成网络流量瓶颈,即便是内网瓶颈。在大并发下表现并不好。
3、基于cache DB缓存的session共享:即使用cacheDB存取session信息,应用服务器接受新请求将session信息保存在cache DB中,当应用服务器发生故障时,调度器会遍历寻找可用节点,分发请求,当应用服务器发现session不在本机内存时,则去cache DB中查找,如果找到则复制到本机,这样实现session共享和高可用。

这里将使用第三种方案,实现session会话共享,将采用Redis来做cache DB。


博文大纲:
一、环境准备
二、配置Nginx反向代理服务器
三、配置Tomcat服务器
四、配置Redis服务器
五、配置Tomcat连接Redis
六、安装部署MySQL数据库
七、配置Tomcat连接MySQL数据库

一、环境准备

LNMT群集基于Redis实现Session共享

在进行下面配置前,先下载我提供的源码包,并自行上传至对应的服务器。

二、配置Nginx反向代理服务器

这里配置Nginx反向代理,只是实现它一个简单的代理功能,若想优化这个反向代理服务器,那么最好参考博文:Nginx安装、实现反向代理及深度优化进行配置。

以下操作均在192.168.20.2的Nginx服务器上进行

[root@nginx ~]# yum -y erase httpd       #卸载自带的web服务
[root@nginx ~]# yum -y install openssl-devel pcre-devel       #安装所需依赖
[root@nginx ~]# tar zxf nginx-1.14.0.tar.gz -C /usr/src      #解包
[root@nginx ~]# cd /usr/src/nginx-1.14.0/      #切换至解压后的目录
[root@nginx conf]# ./configure --user=www --group=www --prefix=/usr/local/nginx && make && make install
#编译安装
[root@nginx nginx-1.14.0]# cd /usr/local/nginx/conf/     #切换至Nginx配置文件主目录
[root@nginx conf]# vim nginx.conf              #编辑Nginx配置文件,写入以下内容
http {                    #在http字段添加以下内容
upstream backend {
server 192.168.20.3:8080 weight=1 max_fails=2 fail_timeout=10s;
server 192.168.20.4:8080 weight=1 max_fails=2 fail_timeout=10s;
}
server {                      #定位到server字段
location / {                #在location字段下面添加以下内容,并注释掉下面开头两行
#root   html;
#index  index.html index.htm;
proxy_pass http://backend;       #主要写入这一行,以下的是优化,可选写入
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}
}
}
#修改完成后,保存退出即可
[root@nginx conf]# ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/           #对Nginx命令做软连接
[root@nginx conf]# useradd -M -s /sbin/nologin www   #创建运行用户
[root@nginx conf]# nginx -t          #检查配置文件
[root@nginx conf]# nginx            #启动Nginx服务

至此,这台Nginx就可以提供基本的反向代理功能了,接下来配置Tomcat服务器。

三、配置Tomcat服务器

以下操作需要在两台Tomcat服务器上分别配置

主机Tomcat1操作如下:

[root@tomcat1 ~]# ls | grep tomcat    #上传下面的源码包
apache-tomcat-8.5.35.tar.gz
[root@tomcat1 ~]# tar zxf apache-tomcat-8.5.35.tar.gz -C /usr/src
[root@tomcat1 ~]# mv /usr/src/apache-tomcat-8.5.35 /usr/local/tomcat
[root@tomcat1 ~]# cd /usr/local/tomcat/conf/
[root@tomcat1 conf]# vim server.xml
<Host name="localhost"  appBase="webapps"    #找到Host字段
unpackWARs="true" autoDeploy="true">   #在下面添加以下配置
<Context docBase="/web/webapp1" path="" reloadable="true"/>
#以上是配置虚拟主机,指定网页根目录是/web/webapp1。添加后保存退出
[root@tomcat1 conf]# mkdir -p /web/webapp1    #创建网页根目录
[root@tomcat1 conf]# vim /web/webapp1/index.jsp    #编写首页文件如下
<%@page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>tomcat-1</title>    #稍后在tomcat2主机上,需修改title字段中的数字改为2,以便查看负载均衡效果
</head>
<body>
<h1><font color="red">Session serviced by tomcat</font></h1>
<table aligh="center" border="1">
<tr>
<td>Session ID</td>
<td><%=session.getId() %></td>
<% session.setAttribute("abc","abc");%>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
<html>
[root@tomcat1 conf]# /usr/local/tomcat/bin/startup.sh     #启动tomcat服务

将以上Tomcat1主机的所有操作在Tomcat2主机上同样配置一次

当Tomcat2主机也配置完成后,即可使用客户端访问Nginx代理服务器(访问:192.168.20.2),多次刷新页面,会依次看到以下页面(注意,其Session ID并不一样):

LNMT群集基于Redis实现Session共享

LNMT群集基于Redis实现Session共享

接下来配置Redis缓存服务器,Redis缓存服务器存在的意义就是将客户端的session会话信息保存下来,用于Tomcat服务器共享这个session会话信息,从而使其不要每次客户端请求都更新session会话。

四、配置Redis服务器

[root@redis ~]# ls | grep redis     #上传下面的源码包
redis-4.0.14.tar.gz
[root@redis ~]# tar zxf redis-4.0.14.tar.gz -C /usr/src    #解包
[root@redis ~]# cd /usr/src    #切换至解压后的路径
[root@redis src]# mv redis-4.0.14/ /usr/local/redis    #直接移动到指定路径并重命名
[root@redis src]# cd /usr/local/redis/    #切换至redis目录
[root@redis redis]# make && make install    #无需配置,直接编译安装即可
[root@redis redis]# cd utils/       #进入该子目录
[root@redis utils]# ./install_server.sh     #对Redis进行初始化
#初始化的所有选项保持默认,一路回车确认即可
#是在确认监听端口、配置文件、日志文件、pid存放路径等信息
.............#省略部分内容
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
#出现上述内容,则表示初始化成功
[root@redis utils]# vim /etc/redis/6379.conf     #编辑Redis配置文件
bind 0.0.0.0           #找到没有被注释的这一行,修改为0.0.0.0
# requirepass foobared         #定位到改行,修改如下:
requirepass 123.com            #Redis的密码为123.com
#修改完成后,保存退出即可。
[root@redis utils]# /etc/init.d/redis_6379 restart     #重启Redis服务
[root@redis utils]# redis-cli -h 192.168.20.5    #登录数据库
192.168.20.5:6379> set a b      #插入数据测试
(error) NOAUTH Authentication required.    #插入失败,因为没有进行密码验证
192.168.20.5:6379> AUTH 123.com    #使用AUTH进行验证,密码就是配置文件中定义的“123.com”
OK
192.168.20.5:6379> set a b       #再次插入数据
OK      #成功

至此,Redis服务器就配置成功了。接下来配置Tomcat,使其可以将Session信息写入到Redis。

五、配置Tomcat连接Redis

1、主机Tomcat1配置如下:

[root@tomcat1 ~]# cd /usr/local/tomcat/lib/
[root@tomcat1 lib]# rz            #将我网盘中的以下四个包文件上传至当前目录
commons-pool2-2.4.2.jar  mysql-connector-java-5.1.22.jar
jedis-2.9.0.jar          tomcat85-session-redis-1.0.jar
[root@tomcat1 lib]# vim ../conf/context.xml    #编辑这个文件
<Manager pathname="" />   #定位到这行,去掉其注释符号,并在该行下写入以下内容
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.20.5"           #指定Redis服务器IP
password="123.com"         #指定Redis的密码
port="6379"                      #指定Redis监听端口
database="0"                     #是否可以写入Redi数据库,0为是
</Context>     #以上的内容在末尾这行上面添加
#编辑完成后,保存退出即可,然后重启Tomcat
[root@tomcat1 lib]# /usr/local/tomcat/bin/shutdown.sh
[root@tomcat1 lib]# /usr/local/tomcat/bin/startup.sh
#上述在../conf/context.xml文件中写入的无注释配置如下:
<Manager pathname="" />
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.20.5"
password="123.com"
port="6379"
database="0"
maxInactiveInterval="60" />

上述在主机Tomcat1上进行的操作,需要在主机Tomcat2上进行相同的配置(自行配置,这里就不写了)。

主机Tomcat2配置完成后,客户端访问Nginx反向代理进行测试,会看到客户端的请求依然是分发到后端两台Tomcat主机上,但是session会话ID不会发生变化了,说明session会话信息已经保存在了Redis服务器上,两台Tomcat主机从Redis上获取session会话信息,多次刷新页面,session会话都不会变化,如下:

LNMT群集基于Redis实现Session共享

LNMT群集基于Redis实现Session共享

并且可以在Redis服务器上查看到保存的session会话信息,如下:

LNMT群集基于Redis实现Session共享

六、安装部署MySQL数据库

这里只是测试环境,直接下载我提供的源码包中的MySQL包及mysql.sh脚本文件,进行脚本安装即可,若需要优化配置MySQL数据库,还请参考博文:Centos7搭建MySQL数据库进行安装。

脚本安装过程如下:

[root@mysql ~]# ls | grep mysql     #上传下面两个文件到MySQL服务器上
mysql-5.7.22-linux-glibc2.12-x86_64.tar.gz
mysql.sh
[root@mysql ~]# sh mysql.sh      #执行此命令后,先去进行第七节操作,这里安装时间较长
Starting MySQL... SUCCESS!      #输出此信息表示MySQL部署成功
mysql: [Warning] Using a password on the command line interface can be insecure.

七、配置Tomcat连接MySQL数据库

1、主机Tomcat1配置如下:

[root@tomcat1 lib]# cd /usr/local/tomcat/webapps    #切换至源码包默认的网页根目录
[root@tomcat1 webapps]# mv ROOT /web/webapp1/    #将ROOT目录复制到现在的根目录下

现在客户端访问主机Tomcat1的8080端口/ROOT,如下(这里主要是为了展示Tomcat为我们提供的连接MySQL数据库的方法,可以不跟做):

LNMT群集基于Redis实现Session共享

点击如下:
LNMT群集基于Redis实现Session共享

然后看到的页面就是官方给我们的连接MySQL数据库的文档:

LNMT群集基于Redis实现Session共享

接下来根据文档提示,在MySQL数据库上创建用于测试的用户及表等。

2、以下操作在MySQL数据库上进行配置:

[root@mysql ~]# mysql -uroot -p123     #登录到MySQL,脚本安装的默认密码是123
mysql> grant all on *.* to javauser@'192.168.20.%' identified by 'javapasswd';
#创建测试用户
mysql> create database javatest;    #创建测试库
mysql> use javatest;      #切换至创建的库
mysql> create table testdata(id int not null auto_increment primary key,foo varchar(25),bar int);
#创建表
mysql> insert into testdata(foo,bar) values ('hello','123456'),('ok','654321'),('lvtest','123123');
#向表中插入数据
mysql> select * from testdata;    #查询插入的数据如下:
+----+--------+--------+
| id | foo    | bar    |
+----+--------+--------+
|  1 | hello  | 123456 |
|  2 | ok     | 654321 |
|  3 | lvtest | 123123 |
+----+--------+--------+
3 rows in set (0.00 sec)

3、配置主机Tomcat1

[root@tomcat1 ~]# vim /usr/local/tomcat/conf/context.xml     #编辑context.xml配置文件
#在文件末尾</Context> 之上添加以下内容
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="javauser" password="javapasswd" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://192.168.20.6:3306/javatest"/>
</Context>      #在最后这行上面添加以上内容
#添加后保存退出即可
[root@tomcat1 ~]# mkdir /web/webapp1/WEB-INF   #创建目录
[root@tomcat1 ~]# vim /web/webapp1/WEB-INF/web.xml   #写入以下内容
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<description>MySQL Test App</description>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
#写入后,保存退出
[root@tomcat1 ~]# cd /web/webapp1/   #切换至网页根目录
[root@tomcat1 webapp1]# vim test.jsp     #编写测试文件
<%@ page language="java" import="java.sql.*" pageEncoding="GB2312"%>
<html>
<head>
<title>MySQL-1</title>    #在第二台Tomcat进行操作时,修改title中的1为2,以便测试负载均衡效果
</head>
<body>
connect MySQL<br>
<%
String driverClass="com.mysql.jdbc.Driver";
String url="jdbc:mysql://192.168.20.6:3306/javatest";    #指定MySQL监听IP及端口
String username = "javauser";         #连接MySQL的用户
String password = "javapasswd";     #用户密码
Class.forName(driverClass);
Connection conn=DriverManager.getConnection(url, username, password);
Statement stmt=conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from testdata");
while(rs.next()){
out.println("<br>foo:"+rs.getString(2)+"bar:"+rs.getString(3));
}
rs.close();
stmt.close();
conn.close();
%>
</body>
</html>
#写入后,保存退出即可,然后重启Tomcat服务
[root@tomcat1 lib]# /usr/local/tomcat/bin/shutdown.sh
[root@tomcat1 lib]# /usr/local/tomcat/bin/startup.sh 

配置至此,客户端访问主机Tomcat1的test.jsp文件,可以看到以下页面,说明主机Tomcat1连接数据库没有问题。得到的页面如下:

LNMT群集基于Redis实现Session共享

可以看到以上页面后,然后在Tomcat2进行以下操作(与主机Tomcat1一样的操作,所以就不写注释了)

4、配置主机Tomcat2:

[root@tomcat2 ~]# vim /usr/local/tomcat/conf/context.xml
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="javauser" password="javapasswd" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://192.168.20.6:3306/javatest"/>
</Context>
[root@tomcat2 ~]# mkdir /web/webapp1/WEB-INF
[root@tomcat2 ~]# vim /web/webapp1/WEB-INF/web.xml
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<description>MySQL Test App</description>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
[root@tomcat2 ~]# cd /web/webapp1/
[root@tomcat2 webapp1]# vim test.jsp
<%@ page language="java" import="java.sql.*" pageEncoding="GB2312"%>
<html>
<head><title>MySQL-2</title>
</head>
<body>
connect MySQL<br>
<%
String driverClass="com.mysql.jdbc.Driver";
String url="jdbc:mysql://192.168.20.6:3306/javatest";
String username = "javauser";
String password = "javapasswd";
Class.forName(driverClass);
Connection conn=DriverManager.getConnection(url, username, password);
Statement stmt=conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from testdata");
while(rs.next()){
out.println("<br>foo:"+rs.getString(2)+"bar:"+rs.getString(3));
}
rs.close();
stmt.close();
conn.close();
%>
</body>
</html>
[root@tomcat2 lib]# /usr/local/tomcat/bin/shutdown.sh
[root@tomcat2 lib]# /usr/local/tomcat/bin/startup.sh 

配置至此,客户端访问Nginx代理服务器(192.168.20.2/test.jsp),多次刷新,可以看到在Tomcat1和Tomcat2之间进行切换:

LNMT群集基于Redis实现Session共享

LNMT群集基于Redis实现Session共享

注意,在上面的环境中,Redis仅仅只是保存Session信息而已,不会像Memcached一样,缓存后端服务器的数据的。

———————— 本文至此结束,感谢阅读 ————————