LNMT群集基于Redis实现Session共享

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LNMT群集基于Redis实现Session共享相关的知识,希望对你有一定的参考价值。

博文大纲:
一、Redis概述
二、如何保持session会话
三、部署LNMT群集基于Redis实现Session共享
(1)搭建nginx服务器配置为反向搭理
(2)配置Tomcat服务器
(3)配置Redis缓存服务器
(4)配置Tomcat服务器可以连接Redis服务器
(5)安装部署mysql数据库
(6)配置Tomcat连接MySQL数据库

一、Redis概述

Redis是完全开源免费的、高性能的key-value数据库,它所支持的、存储的value类型相对更多。与Memcached一样 ,为了保证效率,数据都是缓存在内存中的。区别就是redis会周期性的将更新的数据写入磁盘或者把修改文件写入追加的记录文件,并且在此基础上实现master-slave(主从同步)!

Redis的出现,很大程度补偿了Memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。

Redis和Memcached的区别:
1)Redis不仅仅支持简单的k/v类型的数据,同时还提供list、set、zset、hash等数据结构的存储;
2)Redis支持数据的备份,及master-slave模式的数据备份;
3)Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启时可以再次加载进行使用;

在Redis中,并不是所有的数据都一直存储在内存中的。这就是和Memcached相比一个最大的区别。Redis只会缓存所有的key的信息,如果Redis发现内存的使用量超过了某个阈值,将触发swap的操作,Redis会根据自己的算法计算出哪些key对应的value需要swap到磁盘。然后再将这些key对应的value持久化到磁盘中,同时在内存中清除。这种特性使得Redis可以保持超过其机器本身内存大小的数据。当然,机器本身的内存必须要能够保持所有的key,因为这些数据是不会进行swap操作的。

当从Redis中读取数据的时候,如果读取的key对应的value不在内存中,那么Redis就需要从swap文件中加载相应数据,然后再返回给请求方。

Memcached和Redis的比较

(1)网络IO模型

Memcached是多线程,非阻塞IO复用的网络模型。分为监听主线程和worker子线程,监听线程监听网络连接,接收请求后,将连接描述字传递给worker线程,进行读写IO,网络层使用libevent封装的事件库,多线程可以发挥多核作用;

Redis使用单线程的IO复用模型,自己封装一个简单的AeEvent事件处理框架,主要实现了epoll、kqueue和select,对于单纯只有IO操作来说,单线程可以将速度优势发挥到最大,但是Redis也提供了一些简单的计算功能,比如排序、聚合等,对于这些操作,单线程模型实际会严重影响整体吞吐量,CPU计算过程中,整个IO调度都是被阻塞的;

(2)内存管理方面

Memcached使用预分配的内存池的方式,使用slab和大小不同的chunk来管理内存,value根据大小选择合适的chunk存储;

Redis使用现场申请内存的方式来存储数据;

(3)存储方式及其他方面

Memcached基本只支持简单的key-value存储,不支持持久化和复制等功能,Redis除key/value之外,还支持list、set、sortedset、hash等众多数据结构;

二、如何保持session会话

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

在集群系统下实现session统一的方案:

(1)请求精确定位(sessionsticky)

类似于基于访问的IP的hash策略,即当前用户的请求都集中定位到一台服务器中,这样单台服务器保存了用户的session登录信息,如果宕机,则等同于单点部署,会丢失,会话不复制;

(2)session复制共享(sessionreplication)

比如Tomcat自带session共享,主要是指集群环境下,多台应用服务器之间同步session,使session保持一致,对外透明。如果其中一台服务器发生故障,根据负载均衡的原理,调度其会遍历寻找可用节点 ,分发请求,由于session已同步,故能保证用户的session信息不会丢失,会话复制;

缺陷:

session复制带来的性能损失会快速增加.特别是当session中保存了较大的对象,而且对象变化较快时, 性能下降更加显著,会消耗系统性能。这种特性使得web应用的水平扩展受到了限制。Session内容通过广播同步给成员,会造成网络流量瓶颈,即便是内网瓶颈。在大并发下表现并理想!

(3)基于memcache/redis缓存的 session 共享

使用cacheDB存取session信息,应用服务器接受新请求将session信息保存在cache DB中,当应用服务器发生故障时,调度器会遍历寻找可用节点,分发请求,当应用服务器发现session不在本机内存时,则去cache DB中查找,如果找到则复制到本机,这样实现session共享和高可用。

三、部署LNMT群集基于Redis实现Session共享

1)案例环境

技术图片

2)准备环境

技术图片

3)案例实施

(1)搭建Nginx服务器配置为反向搭理

配置Nginx服务可能过于简单,如果想要对nginx服务有深入的了解,可以参考博文:Nginx初步优化深度优化Nginx(一)Nginx深度优化(二)这三篇博文对Nginx服务有详细的介绍,包括nginx的优化!

下载Nginx软件包

[root@Nginx ~]# yum -y install pcre-devel zlib-devel openssl-devel
//安装nginx服务所需依赖
[root@Nginx ~]# tar zxf nginx-1.14.0.tar.gz -C /usr/src
[root@Nginx ~]# cd /usr/src/nginx-1.14.0/
[root@Nginx nginx-1.14.0]# ./configure && make && make install
//解压、编译、安装(由于本次案例不要nginx过多的功能,所以什么参数都不加了)
[root@Nginx ~]# ln -s /usr/local/nginx/sbin/nginx  /usr/local/sbin
//创建符号链接
[root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
//编辑Nginx的配置文件
 20         upstream backend_tomcat {             
 21         server 192.168.1.5:8080 weight=1 max_fails=2 fail_timeout=10s;
 22         server 192.168.1.6:8080 weight=1 max_fails=2 fail_timeout=10s;
 23         }
//在nginx配置文件的http模块中添加后端服务器群组(前面为行号)
 47         location / {
 48         proxy_pass http://backend_tomcat;            //定义转发后端那个服务器群组
 49         proxy_redirect off;
 50         proxy_set_header Host $host;
 51         proxy_set_header X-Real-IP $remote_addr;
 52         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 53         proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
 54         }
//编写location规则,可以基于原本的location进行修改!
[root@Nginx ~]# nginx -t                     //检查Nginx服务的配置文件
[root@Nginx ~]# nginx                        //启动nginx服务

(2)配置Tomcat服务器

下载Tomcat软件包

TomcatA服务器:

[root@TomcatA ~]# tar zxf apache-tomcat-8.5.35.tar.gz -C /usr/src
[root@TomcatA ~]#  mv /usr/src/apache-tomcat-8.5.35 /usr/local/tomcat
[root@TomcatA ~]# vim /usr/local/tomcat/conf/server.xml
150  <Context docBase="/web/webapp1" path="" reloadable="true"/>
//定义虚拟目录,网页根目录是/web/webapp1,这行内容必须写在Host模块中才会生效(前面为行号)
[root@TomcatA ~]# mkdir -p /web/webapp1         //创建网页根目录
[root@TomcatA ~]# vim /web/webapp1/index.jsp      //创建测试页面
<%@page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>tomcat-1</title>          //主要就是在这个标题这里区分两台tomcat,第二台自行修改
</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@TomcatA ~]# /usr/local/tomcat/bin/startup.sh          //启动tomcat服务

TomcatB服务器
TomcatB服务器与TomcatA服务器的配置一模一样,注意自行修改测试标题内容,避免无法分辨!

配置完成后,客户端测试访问:
技术图片
技术图片

很显然,这种情况在实际工作中是绝对不允许的,那么就需要使用——Redis缓存服务器!

(3)配置Redis缓存服务器

下载Redis软件包其中包括了Tomcat连接Redis、Mysql所需的jar包!

[root@Redis ~]# tar zxf redis-4.0.14.tar.gz -C /usr/src
[root@Redis ~]# mv /usr/src/redis-4.0.14/ /usr/local/redis
[root@Redis ~]# cd /usr/local/redis/
[root@Redis redis]# make && make install         //编译安装redis
[root@Redis redis]# cd utils/
[root@Redis utils]# ./install_server.sh                //对redis服务执行初始化脚本,保持默认回车即可
[root@Redis ~]# vim /etc/redis/6379.conf               //编写redis主配置文件
  70 bind 192.168.1.7                  //修改其监听为网卡IP,也可以修改为0.0.0.0
     502 requirepass 123.com              //添加redis服务的密码为123.com
[root@Redis ~]# vim /etc/init.d/redis_6379              //修改redis服务的脚本,以便使用脚本启动
 43             $CLIEXEC -a 123.com -p $REDISPORT shutdown
//在原本的基础上添加“-a”并指定密码
[root@Redis ~]# /etc/init.d/redis_6379 restart     //初选警告信息可以忽略
[root@Redis ~]# netstat -anpt | grep redis            //确认redis服务已经正在运行
tcp        0      0 192.168.1.7:6379        0.0.0.0:*               LISTEN      5400/redis-server 1 

至此redis服务器已经配置完成!

(4)配置Tomcat服务器可以连接Redis服务器

TomcatA服务器

[root@TomcatA ~]# cd /usr/local/tomcat/lib/          //此目录就是tomcat服务专用于存放jar包的位置
//将刚才redis软件包中的所有jar包上传到此目录中
[root@TomcatA ~]# vim /usr/local/tomcat/conf/context.xml 
 30 <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
 31 <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
 32 host="192.168.1.7"            //指定redis服务器IP地址
 33 password="123.com"        //指定连接redis服务器的密码
 34 port="6379"                       //指定redis服务器开放的端口
 35 database="0"                    //是否允许写入Redi数据库,0为允许
 36 maxInactiveInterval="60" />        //指定session会话时间的失效时间
 37 </Context>                                 //必须写在这个标签之上
[root@TomcatA ~]# /usr/local/tomcat/bin/shutdown.sh
[root@TomcatA ~]# /usr/local/tomcat/bin/startup.sh       //重新启动tomcat服务

TomcatB服务器

此服务器操作与TomcatA服务器的操作一致,这里就不介绍了!

配置完成后,客户端进行访问测试:
技术图片
技术图片

并且可以在Redis服务器上查询到其对应的键、值:

[root@Redis ~]# redis-cli -h 192.168.1.7 -a 123.com
//登录redis服务器,
192.168.1.7:6379> KEYS *
1) "B82B4C0D2390ECD8C9A86ACF1687ED456BnQWK"
//这个键就是浏览器访问的session键(其对应的值,可以自行查询,都是乱码,也看不懂)

(5)安装部署Mysql数据库

由于编译安装Mysql数据库太浪费时间,所以提供了Mysql数据库一键安装脚本
对编译安装Mysql数据库感兴趣的可以参考博文编译安装MySQL数据库系统

[root@localhost ~]# ls
anaconda-ks.cfg       mysql-5.7.22-linux-glibc2.12-x86_64.tar.gz
initial-setup-ks.cfg  mysql.sh
[root@localhost ~]# sh mysql.sh                //执行mysql安装脚本
Starting MySQL. SUCCESS! 
mysql: [Warning] Using a password on the command line interface can be insecure.
//出现以上信息则表示mysql数据库安装完成!

(6)配置Tomcat连接MySQL数据库

TomcatA服务器

[root@TomcatA ~]# mv /usr/local/tomcat/webapps/ROOT /web/webapp1/
//将原本的Tomcat的配置文件复制到Tomcat服务的网页根目录下

客户端访问:
技术图片
技术图片
技术图片
根据以下的配置步骤没有问题!

接下来将步骤详细写出。

Mysql服务器

[root@localhost ~]# mysql -u root -p123        //登录mysql数据库,脚本提供的默认密码是123
mysql> grant all on *.* to javauser@‘192.168.1.%‘ identified by ‘123.com‘;
//授权用户
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 values(null, ‘hello‘, 12345);
mysql> insert into testdata values(null, ‘lzj‘, 88888);
mysql> insert into testdata values(null, ‘xjj‘, 66666);      //随便插入一些数据进行测试
mysql> select * from testdata;
+----+-------+-------+
| id | foo   | bar   |
+----+-------+-------+
|  1 | hello | 12345 |
|  2 | lzj   | 88888 |
|  3 | xjj   | 66666 |
+----+-------+-------+

TomcatA服务器

[root@TomcatA ~]# vim /usr/local/tomcat/conf/context.xml 
 37 <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
 38                maxTotal="100" maxIdle="30" maxWaitMillis="10000"
 39                username="javauser" 
 40                 password="123.com" 
 41                 driverClassName="com.mysql.jdbc.Driver"
 //指定其使用的用户名、密码
 42                url="jdbc:mysql://192.168.1.8:3306/javatest"/>          //指定mysql数据库的IP地址端口号
 43 </Context>                   //同样以上操作必须在这个标签中
[root@TomcatA ~]# mkdir /web/webapp1/WEB-INF       //创建目录
[root@TomcatA ~]# 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@TomcatA ~]# vim /web/webapp1/mysql.jsp
//创建测试连接数据库的脚本
<%@ page language="java" import="java.sql.*" pageEncoding="GB2312"%>
<html>
<head>
<title>MySQL-1</title>                  //注意根据标签来区分
</head>
<body>
connect MySQL<br>
<%
String driverClass="com.mysql.jdbc.Driver";                   
String url="jdbc:mysql://192.168.1.8:3306/javatest";         //指定msyql数据库IP地址、端口号
String username = "javauser";               //连接数据库的用户
String password = "123.com";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@TomcatA ~]# /usr/local/tomcat/bin/shutdown.sh 
[root@TomcatA ~]# /usr/local/tomcat/bin/startup.sh       //重新启动Tomcat服务

同样的方法将TomcatB服务器进行配置,这里就略过了!

客户端访问测试:
技术图片
技术图片

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

——————————————本篇博文到此结束,感谢阅读————————————————

以上是关于LNMT群集基于Redis实现Session共享的主要内容,如果未能解决你的问题,请参考以下文章

基于LNMT的session持久机制的多种方法

RedisRedis 的共享 session 应用(短信登录)

RedisRedis 的共享 session 应用(短信登录)

RedisRedis 的共享 session 应用(短信登录)

Tomcat8+Redis+Nginx实现集群

session的实现方式