一、利用 Nginx 反向代理至后端的 Tomcat

1.1 部署环境说明

IP地址

用途

192.168.131.11

Tomcat1,Memcached1

192.168.131.12

Tomcat2,Memcached2

192.168.131.13

Redis

192.168.131.14

Nginx

1.2 配置说明

Tomcat会话保持_Tomcat

利用Nginx反向代理功能,实现上图的代理功能,将用户请求转发至后端Tomcat主机。注意:生产环境中应用程序服务器(eg:Tomcat、Mysql)往往放在内网,不让用户直接访问。

#Nginx机器做如下配置
apt-get -y install nginx
vim /etc/nginx/conf.d/tomcat.conf
upstream tomcat {
    server 192.168.131.11:8080;
    server 192.168.131.12:8080;
}
server {
    listen 80;
    server_name www.wang.org;
    location / {
        proxy_pass http://tomcat;
    }
}

nginx -t
nginx -s reload

再将session.jsp文件上传到两台Tomcat机器用于后续测试。session.jsp内容如下:

<%@ page language="java" %>
<html>
		#这是192.168.131.12显示为Tomcat2,192.168.131.11的Tomcat中显示为Tomcat1
        <head><title>Tomcat2</title></head>
        <body>
                <h1><font color="red">Tomcat2</font></h1>
                <table align="centre" border="1">
                        <tr>
                                <td>Session ID</td>
                        <% session.setAttribute("username","wangxiaochun"); %>
                                <td><%= session.getId() %></td>
                        </tr>
                        <tr>
                                <td>Created on</td>
                                <td><%= session.getCreationTime() %></td>
                        </tr>
                </table>
        </body>
</html>

做好Hosts解析后测试:访问www.wang.org/session.jsp,多次访问就会发现请求被轮询到192.168.131.11和192.168.131.12两台Tomcat服务器上,均匀地分担请求。

Tomcat会话保持_Memcached_02


Tomcat会话保持_Memcached_03

但是我们发现,网页的Session总是变化的,如果是个网站则登录或出问题。会话保持问题后续会讲到。

1.3 利用Httpd实现基于AJP协议的反向代理至后端Tomcat

1.3.1 AJP协议说明

AJP(Apache JServ Protocol)是定向包协议,是一个二进制的TCP传输协议,相比HTTP这种纯文本的协议来说,效率和性能更高,也做了很多优化。但是浏览器并不能直接支持AJP协议,只支持HTTP协议。所以实际情况是,通过Apache的proxy_ajp模块进行反向代理,暴露成http协议给客户端访问。

1.3.2 启用&禁用AJP协议

注意:Tomcat/8.5.51之后版本基于安全需求默认禁用AJP协议

Tomcat的server.conf配置如下:

#取消注释,修改address和secretRequired的值
<Connector protocol="AJP/1.3" address="0.0.0.0" port="8009" redirectPort="8443" maxParameterCount="1000" secretRequired="" />

重启Tomcat服务后,就会发现有监听8009端口。

Tomcat会话保持_Memcached_04

二、Tomcat的会话保持

2.1 HTTP的无状态、有连接和短连接

2.1.1 无状态

无状态指的是服务器端无法知道2次请求之间的联系,即使是前后2次请求来自同一个浏览器,也没有任何数据能够判断出是同一个浏览器的请求。后来可以通过Cookie、Session机制来判断。

浏览器端第一次HTTP请求服务器端时,在服务器端使用Session这种技术,就可以在服务器端产生一个随机值即SessionID发给浏览器端,浏览器端收到后会保持这个SessionID在Cookie 当中,这个Cookie值一般不能持久存储,浏览器关闭就消失。浏览器在每一次提交HTTP请求的时候会把这个SessionID传给服务器端,服务器端就可以通过比对知道是谁了。

2.1.2 有连接

是因为它基于TCP协议,是面向连接的,需要3次握手、4次断开。

2.1.3 短连接

Http 1.1之前,都是一个请求一个连接,而Tcp的连接创建销毁成本高,对服务器有很大的影响。所以,自Http 1.1开始,支持keep-alive,默认也开启,一个连接打开后,会保持一段时间(可设置),浏览器再访问该服务器就使用这个Tcp连接,减轻了服务器压力,提高了效率。

2.2 会话保持方式

包括会话绑定、会话复制、会话服务器三类。

2.2.1 会话绑定

也叫会话粘性。只要是同一个客户端来访问,请求就路由到特定的后端服务器。比如这次我的电脑访问由Tomcat1处理请求,下次就还是Tomcat1去处理请求。而这样做的目的是确保在多个服务器之间保持用户的会话数据或状态的一致性,比如网上购物,银行交易等场景。

优点是简单易配置;缺点是如果目标服务器故障后,如果没有做Session持久化,就会丢失Session,此方式生产很少使用。

通常,会话粘性通过客户端的标识信息来实现,最常见的标识信息是客户端的 IP 地址或Cookie。

客户端和服务端之间的交互如下图所示。

Tomcat会话保持_Memcached_05

以下配置用到了Nginx负载均衡的IP_Hash策略(取IP地址前24位),确保来自同一IP的请求总是被分配到相同的后端服务器。tomcat.conf的配置如下:

upstream tomcat {
    ip_hash;
    server 192.168.131.11:8080;
    server 192.168.131.12:8080;
}
server {
    listen 80;
    server_name www.wang.org;
    location / {
        proxy_pass http://tomcat;
    }
}

刷新Nginx配置后,再刷新访问页面,发现访问会分配给特定的后端服务器处理,Session也是固定的。查看网页请求标头,注意到Cookie也带着呢,名为JSESSIONID。

Tomcat会话保持_会话保持_06

Tomcat会话保持_会话保持_07

但是这样会导致同网段的都会访问特定的后端服务器,匹配方式似乎不太精准。同时IP_Hash不会考虑服务器的负载问题,可能导致多个服务器负载不均衡的状况。可使用URL Hash策略,可以将同一 URL 的请求都分配到同一个后端服务器上,也能会话保持。

tomcat.conf配置文件内容如下:

upstream tomcat {
    #$remote_addr变量表示Nginx客户端地址
    hash $remote_addr;
    server 192.168.131.11:8080;
    server 192.168.131.12:8080;
}
server {
    listen 80;
    server_name www.wang.org;
    location / {
        proxy_pass http://tomcat;
    }
}

以上为基于IP地址的会话绑定,那基于Cookie的会话绑定又该如何实现?且看如下tomcat.conf配置:

upstream tomcat {
    #由于查看网页标头的Cookie的名字为JSESSIONID,需要以$cookie_加上它的小写名字,即$cookie_jsessionid为hash值
    hash $cookie_jsessionid;
    server 192.168.131.11:8080;
    server 192.168.131.12:8080;
}
server {
    listen 80;
    server_name www.wang.org;
    location / {
        proxy_pass http://tomcat;
    }
}

刷新Nginx配置后,分别用Edge浏览器和谷歌浏览器访问,可以看到不同的浏览器各自的Cookie是不同的。

Tomcat会话保持_Memcached_08

Tomcat会话保持_Memcached_09

还要注意一点,除了Nginx,前端也可以用LVS去做反向代理,只不过LVS不支持基于Cookie的调度,因为LVS只能做四层负载,而Cookie属于七层。但LVS可支持源地址哈希算法(sh)。

2.2.2 Session复制

Tomcat 官方实现了 Session 的复制集群,通过多播机制将每个Tomcat的Session进行相互的复制同步,从而保证所有 Tomcat都有相同的Session信息。

缺点:

  • Tomcat同步的节点不宜过多,互相即时通信同步Session需要带宽多。
  • 每台Tomcat都拥有全部Session,内存损耗大。因此并不适宜后端服务器众多的场景。

注意:需要在代理服务器(nginx/httpd)设置后端轮询。

2.2.2.1 修改server.conf

参考https://tomcat.apache.org/tomcat-10.0-doc/cluster-howto.html,修改server.conf(两台Tomcat服务器都要做)。注意将以下内容复制到Host块中。

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
 channelSendOptions="8">
 <Manager className="org.apache.catalina.ha.session.DeltaManager"
   expireSessionsOnShutdown="false"
   notifyListenersOnReplication="true"/>
 <Channel className="org.apache.catalina.tribes.group.GroupChannel">
 <Membership className="org.apache.catalina.tribes.membership.McastService"
 address="228.0.0.4"         #指定的多播地址
 port="45564"   #45564/UDP
 frequency="500"             #间隔500ms发送
 dropTime="3000"/>           #故障阈值3s
 <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
  address="auto"   #监听地址,此项建议修改为当前主机的IP(不支持0.0.0.0),如果不修改可能会导致服务无法启动
  port="4000" #监听端口
  autoBind="100" #如果端口冲突,自动绑定其它端口,范围是4000~4100
  selectorTimeout="5000"        #自动绑定超时时长5s
  maxThreads="6"/>
 <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
 <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
 </Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
</Channel>
 <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
 <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
 <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
 tempDir="/tmp/war-temp/"
 deployDir="/tmp/war-deploy/"
 watchDir="/tmp/war-listen/"
 watchEnabled="false"/>
 <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

配置说明

  • Cluster 集群配置
  • Manager 会话管理器配置
  • Channel 信道配置
  • Membership 成员判定。使用什么多播地址、端口多少、间隔时长ms、超时时长ms。同一个多播地址和端口认为同属一个组。使用时修改这个多播地址,以防冲突
  • Receiver 接收器,多线程接收多个其他节点的心跳、会话信息。默认会从4000到4100依次尝试可用端口 address="auto",auto可能绑定到127.0.0.1上,所以一定要改为当前主机可用的IP。
  • Sender 多线程发送器,内部使用了tcp连接池。
  • Interceptor 拦截器
  • Valve
  • ReplicationValve 检测哪些请求需要检测Session,Session数据是否有了变化,需要启动复制过程
  • ClusterListener
  • ClusterSessionListener 集群session侦听器
2.2.2.2 修改应用目录下WEB-INF/web.xml

注意:WEB-INF/web.xml文件的如果权限不对,会导致复制失败

#在web.xml添加以下内容
vim /usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml
</description>
<distributable/> #添加此行
</web-app>

重启Tomcat之后进行测试。用浏览器访问并刷新多次,发现SessionID 不变,但后端主机在轮询。

Tomcat会话保持_会话保持_10

Tomcat会话保持_Tomcat_11

三、Mencached

3.1 NoSQL介绍

NoSQL是对 Not Only SQL、非传统关系型数据库的统称。随着互联网时代的到来,数据爆发式增长,数据库技术发展日新月异,要适应新的业务需求。
       NoSQL分类

  • Key-value Store k/v数据库:性能好 O(1),如: redis、memcached
  • Document Store 文档数据库:mongodb、CouchDB
  • Column Store 列存数据库,Column-Oriented DB:HBase、Cassandra,大数据领域应用广泛
  • Graph DB 图数据库:Neo4j
  • Time Series 时序数据库:InfluxDB、Prometheus

3.2 Memcached介绍

Memcached 只支持能序列化的数据类型,不支持持久化,基于Key-Value的内存缓存系统。

Memcached 虽然没有像redis所具备的数据持久化功能,比如RDB和AOF都没有,但是可以通过做集群同步的方式,让各memcached服务器的数据进行同步,从而实现数据的一致性,即保证各memcached 的数据是一样的,即使有任何一台 memcached 发生故障,只要集群中有一台 memcached 可用就不会出现数据丢失,当其他memcached 重新加入到集群的时候,可以自动从有数据的memcached 当中自动获取数据并提供服务。

Memcached 借助了操作系统的 libevent 工具做高效的读写。libevent是个程序库,它将Linux的 epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥高性能。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。

Memcached 支持最大的内存存储对象为1M,超过1M的数据可以使用客户端压缩或拆分报包放到多个 key中,比较大的数据在进行读取的时候需要消耗的时间比较长,memcached 最适合保存用户的 session实现session共享。

Memcached存储数据时,Memcached会去申请1MB的内存, 把该块内存称为一个slab,也称为一个page。

Memcached 支持多种开发语言,包括:JAVA、C、Python、PHP、C#、Ruby、Perl等。

3.3 Memcached和Redis的对比

比较类别

Redis

Memcached

支持的数据结构

哈希、列表、集合、有序集合

纯kev-value

持久化支持

高可用支持

redis支持集群功能,可以实现主动复制,读写分离。官方也提供了sentinel集群管理工具,能够实现主从服务监控,故障自动转移,这一切,对于客户端都是透明的,无需程序改动,也无需人工介入

需要二次开发

存储value容量

最大512M

最大1M

内存分配

临时申请空间,可能导致碎片

预分配内存池的方式管理内存,能够省去内存分配时间

虚拟内存使用

有自己的VM机制,理论上能够存储比物理内存更多的数据,当数据超量时,会引发swap,把冷数据刷到磁盘上

所有的数据存储在物理内存里


网络模型

非阻塞IO复用模型,提供一些非KV存储之外的排序,聚合功能,在执行这些功能时,复杂的CPU计算,会阻塞整个IO调度

非阻塞IO复用模型

水平扩展的支持

Rediscluster可以横向扩展

暂无

多线程

Redis6.0之前是只支持单线程

Memcached支持多线程,CPU利用方面Memcache优于Redis

过期策略

有专门线程,清除缓存数据

懒淘汰机制:每次往缓存放入数据的时候,都会存一个时间,在读取的时候要和设置的时间做TTL比较来判断是否过期

单机QPS

约10W

约60W

源代码可读性

代码清爽简洁

可能是考虑了太多的扩展性,多系统的兼容性,代码不清爽

适用场景

复杂数据结构、有持久化、高可用需求、value存储,内容较大


纯KV,数据量非常大,并发量非常大的业务

3.4 Memcached工作机制

3.4.1 内存分配机制

应用程序运行需要使用内存存储数据,但对于一个缓存系统来说,申请内存、释放内存将十分频繁,非常容易导致大量内存碎片,最后导致无连续可用内存可用。

Memcached采用了Slab Allocator机制来分配、管理内存。

  • Page:分配给Slab的内存空间,默认为1MB,分配后就得到一个Slab。Slab分配之后内存按照固定字节大小等分成chunk。
  • Chunk:用于缓存记录k/v值的内存空间。Memcached会根据数据大小选择存到哪一个chunk中, 假设chunk有128bytes、64bytes等多种,数据只有100bytes存储在128bytes中,存在少许浪费。
  • Slab Class:Slab按照Chunk的大小分组,就组成不同的Slab Class,比如第一个Chunk大小为 96B的 Slab为Class1,Chunk 120B的Slab为Class 2,如果有100 bytes要存,那么Memcached会选择Slab Class 2 存储,因为它是120bytes的Chunk。Slab之间的差异可以使用启动因子控制,Memcached的启动因子默认(可使用-f选项指定)。

3.4.2 懒过期机制

memcached不会监视数据是否过期,而是在取数据时才看是否过期,如果过期,把数据有效期限标识为 0,并不清除该数据。以后可以覆盖该位置存储其它数据。

3.4.3 LRU

当内存不足时,memcached会使用LRU(Least Recently Used,最近最少使用)机制来查找可用空间,分配给新记录使用。淘汰的多为旧的、不常使用的数据。

3.5 安装和启动

3.5.1 包安装

apt -y update;apt -y install memcached
vim /etc/memcached.conf
#-l 127.0.0.1 注释此行
#查看版本
memcached -v
grep -Ev "#|^$" /etc/memcached.conf
-d
logfile /var/log/memcached.log
-m 1024 #最大内存空间,默认64M
-p 11211
#不允许以root用户运行
-u memcache
-c 10240 #最大并发连接,默认1024
-P /var/run/memcached/memcached.pid
systemctl restart memcached
#默认使用11211端口
ss -antulp | grep 11211

3.6 使用Memcached

3.6.1 memcached操作命令

包括set、add、replace、get、delete。

#前三个命令是用于操作存储在 memcached 中的键值对的标准修改命令,都使用如下所示的语法:
command <key> <flags> <expiration time> <bytes> <value>
#参数说明如下:
command set/add/replace
key key 用于查找缓存值
flags 可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息
expiration time 在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
bytes 在缓存中存储的字节数
value 存储的值(始终位于第二行)
##示例
#加
add name 0 0 3
wxd
STORED
#查
get name
VALUE name 0 3
wxd
END
#改
set name 0 0 3
lxc
STORED
#查
get name
VALUE name 0 3
lxc
END
#删
delete name
DELETED
#清空
flush_all
OK
#退出
quit

Tomcat会话保持_会话保持_12

如果是非交互式取信息,则使用如下命令(以获取最大连接数为例):

echo -e "stats\nquit" | nc 192.168.131.13 11211 | grep max_connections

Tomcat会话保持_Tomcat_13

3.7 Memcached报错解决

Memcached报错:CLIENT_ERROR bad data chunk

这是因为存储的字节长度与指定的长度不匹配造成的,如:set username 0 0 2。你是打算存储两个字节,但如果输入不等于2个字节就会报CLIENT_ERROR bad data chunk错误。

四、Session服务器

4.1 MSM介绍

MSM(memcached session manager)提供将Tomcat的session保持到memcached或Redis的程序,可以实现高可用。注意:当前MSM不支持 tomcat 10版本。

GitHub网站链接:https://github.com/magro/memcached-session-manager

4.2 安装相关软件包

参考https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration       将spymemcached.jar、memcached-session-manage、kyro相关的jar文件都放到Tomcat的lib目录中去,这个目录是 Tomcat安装目录下的lib目录 ,对应本次安装就是/usr/local/tomcat/lib。

kryo-3.0.3.jar
asm-5.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
minlog-1.3.1.jar
kryo-serializers-0.45.jar
msm-kryo-serializer-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
spymemcached-2.12.3.jar
memcached-session-manager-2.3.2.jar

4.3 Sticky模式

4.3.1 Sticky模式工作原理

Sticky 模式即前端tomcat和后端memcached有关联(粘性)关系。参考https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration
<t1> <t2>
. \       / .
 .    X    .
.  /      \ .
<m1> <m2>
       t1和m1部署可以在一台主机上,t2和m2部署也可以在同一台。

当新用户发请求到Tomcat1时,Tomcat1生成session返回给用户的同时,也会同时发给memcached2备份(简单地说就是斜对角备份,t1<->m2,t2<->m1。m1就备份t2的数据而非t1的数据)。即Tomcat1 session为主session,memcached2 session为备用session,使用memcached相当于备份了一份Session。

如果Tomcat1发现memcached2 失败,无法备份Session到memcached2,则将Session备份存放在memcached1中。

4.3.2 修改Tomcat配置

两台Tomcat机器分别打开Tomcat安装目录下的conf/context.xml。

特别注意,t1(Tomcat1的简称)配置中为failoverNodes="n1"(Memcached的备用节点), t2配置为failoverNodes="n2"。因为t1的数据往往是备份在n2节点(即另一台机器的Memcached),这样做的好处是由于这里Tomcat和Memcached是安装在同一台机器上的,可防止因服务器宕机而导致的数据全部丢失。

#以下是sticky的配置
<Context>
…
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
    memcachedNodes="n1:192.168.131.11:11211,n2:192.168.131.12:11211"
    failoverNodes="n1"
    requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
</Context>

之后重启Tomcat,再刷新之前的页面进行测试,发现由于调度到Tomcat1(192.168.131.11),按照斜对角备份的思路,此时会话在n2机器(即192.168.131.12)也存了一份。再次刷新,即使调度到了Tomcat2,但是SessionID不变。说明此时已经实现了会话保持。

Tomcat会话保持_会话保持_14

Tomcat会话保持_Memcached_15

在n2机器运行测试脚本,可看到备份的会话内容

Tomcat会话保持_Memcached_16

测试Python脚本内容如下:

#!/usr/bin/python3
import memcache # pip install python-memcached
mc = memcache.Client(['192.168.131.11:11211','192.168.131.12:11211'], debug=True)
#print('-' * 30)
# 查看全部key
for x in mc.get_stats('items'):  # stats items 返回 items:5:number 1
    print(x)
print('-' * 30)
for x in mc.get_stats('cachedump 5 0'):
print(x)

目前Tomcat1的Session只是在n2(192.168.131.12)备份,由于是基于内存工作的,故Memcached宕机或重启都会导致数据丢失(若再加上Tomcat服务异常,则以往存储的Session就彻底丢失了)。可以检验一下当n2的Memcached宕机或重启时Tomcat1的Session是否会在n1(192.168.131.11)的Memcached备份。

重启n2的memcached。从测试结果可得,之前Tomcat1以B6B2结尾的Session重新保存到n1机器去了。

Tomcat会话保持_会话保持_17

4.4 Non-Sticky模式

4.4.1 Non-Sticky模式工作原理

Non-Sticky 模式即前端tomcat和后端memcached无关联(无粘性)关系。

Tomcat session为中转Session,对每一个SessionID随机选中后端的memcached节点n1(或者n2)为主 session,而另一个memcached节点n2(或者是n1)为备session。产生的新的Session会发送给主、备 memcached,并清除本地Session。

后端两个memcached服务器对一个session来说是一个是主,一个是备;但对所有session信息来说每个 memcached既是主又是备。

4.4.2 Memcahced实现Non-Sticky模式

修改Tomcat关于Memcached的配置

vim conf/context.xml
<Context>
…
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
    memcachedNodes="n1:192.168.131.11:11211,n2:192.168.131.12:11211"
    sticky="false"
    sessionBackupAsync="false"
    lockingMode="uriPattern:/path1|/path2"
    requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
</Context>

重启Tomcat、Memcached,再次刷新页面测试访问。发现选中n1为主备份Session节点,n2为备用的Session备份节点(有bak标识)。Session会在两台Memcached机器均有备份,此时即使坏掉一台Memcached服务器另一台服务器亦有备份,不影响访问。显然其可用性比Sticky模式要更好。

Tomcat会话保持_Tomcat_18

Tomcat会话保持_Memcached_19

4.4.3 Redis实现Non-Sticky模式

在192.168.131.13安装并配置Redis监听0.0.0.0地址。之后修改两台Tomcat的配置去指定Redis服务器地址,还是conf/context.xml。

<Context>
…
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
    memcachedNodes="redis://192.168.131.13:6379"
    sticky="false"
    sessionBackupAsync="false"
    lockingMode="uriPattern:/path1|/path2"
    requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
</Context>

重启Tomcat后再次刷新浏览器页面进行测试,发现主机轮询,但新生成的SessionID不变。同时在Redis客户端也看到有存储的SessionID。只不过其局限性在于,Redis一旦单点故障,则SessionID就会变。

Tomcat会话保持_会话保持_20

Tomcat会话保持_Memcached_21

4.5 使用Redisson利用Redis实现Session共享

Redisson是Redis官方推荐的Java版的Redis客户端。它提供的功能非常多,也非常强大。

Redisson 是基于redis的扩展库,使得redis除了应用于缓存以外,还能做队列等数据结构,直接使用的分布式锁,以及事务调度器等。

此项目更新比较频繁,生产较为推荐。官网:https://github.com/redisson/redisson,Tomcat配置Redisson参考:https://github.com/redisson/redisson/tree/master/redisson-tomcat

首先下载相关jar包,并将其放到Tomcat安装目录下的lib目录。下载链接:https://repo1.maven.org/maven2/org/redisson/redisson-all/3.27.0/redisson-all-3.27.0.jar、https://repo1.maven.org/maven2/org/redisson/redisson-tomcat-9/3.27.0/redisson-tomcat-9-3.27.0.jar

首先在Tomcat的conf/context.xml添加如下内容:

<Context>
…
<Manager className="org.redisson.tomcat.RedissonSessionManager"
  configPath="${catalina.base}/conf/redisson.conf" 
  readMode="REDIS" updateMode="DEFAULT" broadcastSessionEvents="false"
  keyPrefix=""/>
</Context>

这里${catalina.base}变量的意思是执行catalina.sh脚本时CATALINA_BASE的值为/usr/local/tomcat,正是Tomcat的安装路径。

创建/usr/local/tomcat/conf/redisson.conf。内容如下:

{
   "singleServerConfig":{
      "idleConnectionTimeout":10000,
      "connectTimeout":10000,
      "timeout":3000,
      "retryAttempts":3,
      "retryInterval":1500,
      "password":null,
      "subscriptionsPerConnection":5,
      "clientName":null,
      "address": "redis://192.168.131.13:6379",
      "subscriptionConnectionMinimumIdleSize":1,
      "subscriptionConnectionPoolSize":50,
      "connectionMinimumIdleSize":32,
      "connectionPoolSize":64,
      "database":0,
      "dnsMonitoringInterval":5000
   },
   "threads":0,
   "nettyThreads":0,
   "codec":{
      "class":"org.redisson.codec.JsonJacksonCodec"
   },
   "transportMode":"NIO"
}

重启Tomcat后再次刷新浏览器界面测试。同时打开Redis客户端,看到SessionID在Redis也有存储。

Tomcat会话保持_Memcached_22

Tomcat会话保持_Memcached_23