一、redis介绍

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现master-slave(主从)同步。

Redis是一个高性能的key-value数据库。redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby等客户端,使用很方便。

如果简单地比较Redis与Memcached的区别,基本上有以下3点:
1、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
2、Redis支持数据的备份,即master-slave模式的数据备份。
3、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。

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

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

memcached和redis的比较

1、网络IO模型

Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描述字pipe 传递给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信息不会丢失,会话复制,。

此方案的不足之处:

必须在同一种中间件之间完成(如:tomcat-tomcat之间).

session复制带来的性能损失会快速增加.特别是当session中保存了较大的对象,而且对象变化较快时, 性能下降更加显著,会消耗系统性能。这种特性使得web应用的水平扩展受到了限制。

Session内容通过广播同步给成员,会造成网络流量瓶颈,即便是内网瓶颈。在大并发下表现并不好

3、基于cache DB缓存的session共享

基于memcache/redis缓存的 session 共享

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

三、nginx+tomcat+redis实现负载均衡、session共享

1、实验环境

主机 操作系统 IP地址
Nginx C7.4 192.168.6.240
Tomcat-1 C7.4 192.168.6.241
Tomcat-2 C7.4 192.168.6.242
redis C7.4 192.168.6.244
mysql C7.4 192.168.6.244

2、实验拓扑

在这个图中,nginx做为反向代理,实现静动分离,将客户动态请求根据权重随机分配给两台tomcat服务器,redis做为两台tomcat的共享session数据服务器,mysql做为两台tomcat的后端数据库。

3、nginx安装配置

使用Nginx作为Tomcat的负载平衡器,Tomcat的会话Session数据存储在Redis,能够实现零宕机的7x24效果。因为将会话存储在Redis中,因此Nginx就不必配置成stick粘贴某个Tomcat方式,这样才能真正实现后台多个Tomcat负载平衡。

部署nginx:

yum install pcre pcre-devel -y 
yum install openssl openssl-devel -y
mkdir -p /home/oldboy/tools
cd /home/oldboy/tools/
wget -q http://nginx.org/download/nginx-1.6.2.tar.gz
useradd nginx -s /sbin/nologin -M
mkdir /application/
tar xf nginx-1.6.2.tar.gz 
cd nginx-1.6.2
./configure --user=nginx --group=nginx --prefix=/application/nginx1.6.2 --with-http_stub_status_module --with-http_ssl_module --with-http_realip_module
echo $?
make && make install
echo $?
ln -s /application/nginx1.6.2/ /application/nginx
cd ../

配置nginx反向代理:反向代理+负载均衡+健康探测,nginx.conf文件内容:

[root@linux-node1 ~]# cat /application/nginx/conf/nginx.conf
worker_processes  4;
events {
        worker_connections  1024;
}
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for"';

    #blog lb by oldboy at 201303
        upstream backend_tomcat {
        #ip_hash;
        server 192.168.6.241:8080   weight=1 max_fails=2 fail_timeout=10s;
        server 192.168.6.242:8080   weight=1 max_fails=2 fail_timeout=10s;
        #server 192.168.6.243:8080   weight=1 max_fails=2 fail_timeout=10s;
        }

        server {
            listen       80;
            server_name  www.98yz.cn;
            charset utf-8;
            location / {
                root html;
                index  index.jsp index.html index.htm;
                    }
            location ~* \.(jsp|do)$ {
            proxy_pass  http://backend_tomcat;
            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;
                }
        }

    }

4、安装部署tomcat应用程序服务器

在tomcat-1和tomcat-2节点上安装JDK

在安装tomcat之前必须先安装JDK,JDK的全称是java development kit,是sun公司免费提供的java语言的软件开发工具包,其中包含java虚拟机(JVM),编写好的java源程序经过编译可形成java字节码,只要安装了JDK,就可以利用JVM解释这些字节码文件,从而保证了java的跨平台性。

安装JDK,Tomcat 程序:

[root@linux-node2 ~]# yum install java -y
[root@linux-node2 ~]# java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)

[root@linux-node2 ~]# mkdir /soft/src -p
[root@linux-node2 ~]# cd /soft/src
[root@linux-node2 ~]# wget https://mirrors.aliyun.com/apache/tomcat/tomcat-9/v9.0.16/bin/apache-tomcat-9.0.16.tar.gz
[root@linux-node2 ~]# tar xf apache-tomcat-9.0.16.tar.gz -C /soft
[root@linux-node2 ~]# cd ..
[root@linux-node2 ~]# cp -r apache-tomcat-9.0.16/ tomcat-8080
[root@linux-node2 soft]# cd tomcat-8080/

按照相同方法在tomcat-2也安装

下面我们来修改配置文件

[root@linux-node2 tomcat-8080]# vim conf/server.xml

设置默认虚拟主机,并增加jvmRoute

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat-1">

修改默认虚拟主机,并将网站文件路径指向/web/webapp1,在host段增加context段

<Host name="localhost"  appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context docBase="/web/webapp1" path="" reloadable="true"/>
</Host>

增加文档目录与测试文件

[root@linux-node2 ~]# mkdir -p /web/webapp1
[root@linux-node2 ~]# cd /web/webapp1
[root@linux-node2 webapp1]# cat index.jsp 
<%@page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
    <head>
        <title>tomcat-1</title>
    </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>
    tomcat-1
    </body>
<html>

Tomcat-2节点与tomcat-1节点配置基本类似,只是jvmRoute不同,另外为了区分由哪个节点提供访问,测试页标题也不同(生产环境两个tomcat服务器提供的网页内容是相同的)。其他的配置都相同。

用浏览器访问nginx主机,验证负载均衡

验证健康检查的方法可以关掉一台tomcat主机,用客户端浏览器测试访问。

从上面的结果能看出两次访问,nginx把访问请求分别分发给了后端的tomcat-1和tomcat-2,客户端的访问请求实现了负载均衡,但sessionid并一样。所以,到这里我们准备工作就全部完成了,下面我们来配置tomcat通过redis实现会话保持。

5、安装redis

这里采用宝塔安装的

6、配置tomcat session redis同步

通过TomcatClusterRedisSessionManager,这种方式支持redis3.0的集群方式
下载TomcatRedisSessionManager-2.0.zip包,https://github.com/ran-jit/tomcat-cluster-redis-session-manager,放到$TOMCAT_HOMA/lib下,并解压

[root@linux-node2 ]# cd /soft/tomcat-8080/lib/
[root@linux-node2 lib]# wget https://github.com/ran-jit/tomcat-cluster-redis-session-manager/releases/download/2.0.4/tomcat-cluster-redis-session-manager.zip
[root@linux-node2 lib]# unzip tomcat-cluster-redis-session-manager.zip 
Archive:  tomcat-cluster-redis-session-manager.zip
   creating: tomcat-cluster-redis-session-manager/conf/
  inflating: tomcat-cluster-redis-session-manager/conf/redis-data-cache.properties  
   creating: tomcat-cluster-redis-session-manager/lib/
  inflating: tomcat-cluster-redis-session-manager/lib/commons-logging-1.2.jar  
  inflating: tomcat-cluster-redis-session-manager/lib/commons-pool2-2.4.2.jar  
  inflating: tomcat-cluster-redis-session-manager/lib/jedis-2.9.0.jar  
  inflating: tomcat-cluster-redis-session-manager/lib/tomcat-cluster-redis-session-manager-2.0.4.jar  
  inflating: tomcat-cluster-redis-session-manager/readMe.txt 
[root@linux-node4 lib]# cp tomcat-cluster-redis-session-manager/lib/* ./
[root@linux-node4 lib]# cp tomcat-cluster-redis-session-manager/conf/redis-data-cache.properties ../conf/

[root@linux-node2 lib]# cat ../conf/redis-data-cache.properties     
#-- Redis data-cache configuration
//远端redis数据库的地址和端口
#- redis hosts ex: 127.0.0.1:6379, 127.0.0.2:6379, 127.0.0.2:6380, ....
redis.hosts=192.168.6.244:6379
//远端redis数据库的连接密码
#- redis password (for stand-alone mode)
redis.password=pwd@123
//是否支持集群,默认的是关闭
#- set true to enable redis cluster mode
redis.cluster.enabled=false
//连接redis的那个库
#- redis database (default 0)
#redis.database=0
//连接超时时间
#- redis connection timeout (default 2000)
#redis.timeout=2000
//在这个<Context>标签里面配置
[root@linux-node4 lib]# vim ../conf/context.xml
<Valve className="tomcat.request.session.redis.SessionHandlerValve" />
<Manager className="tomcat.request.session.redis.SessionManager" />

配置会话到期时间在../conf/web.xml

<session-config>
<session-timeout>60</session-timeout>
</session-config>

启动tomcat服务

[root@linux-node2 lib]# ../bin/startup.sh

Tomcat-2节点与tomcat-1节点配置相同

测试,我们每次强刷他的sessionID都是一致的,所以我们认为他的session会话保持已经完成,你们也可以选择换个客户端的IP地址来测试


文档更新时间: 2019-07-25 21:20   作者:李延召