文章 78
评论 0
浏览 8365
5-session 共享服务器

5-session 共享服务器

5 session 共享服务器

5.1 msm 介绍

msm(memcached session manager)提供将Tomcat的session保持到memcached或redis的程序,可以实现高可用。

项目早期托管在google code,目前在Github

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

clipboard.png

支持Tomcat的 6.x、7.x、8.x、9.x

  • Tomcat的Session管理类,Tomcat版本不同
    • memcached-session-manager-2.3.2.jar
    • memcached-session-manager-tc8-2.3.2.jar
  • Session数据的序列化、反序列化类
    • 官方推荐kyro
    • 在webapp中WEB-INF/lib/下
  • 驱动类
    • memcached(spymemcached.jar)
    • Redis(jedis.jar)

5.2 安装

参考链接: https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

将spymemcached.jar、memcached-session-manage、kyro相关的jar文件都放到Tomcat的lib目录中去,这个目录是 $CATALINA_HOME/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

5.3 sticky 模式

5.3.1 sticky 模式工作原理

sticky 模式即前端tomcat和后端memcached有关联(粘性)关系

参考文档:https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

Tomcat-1(t1)主要将其会话存储在另一台计算机上运行的memcached-2(m2)中(m2是t1的常规节
点)。 仅当m2不可用时,t1才会将其会话存储在memcached-1中(m1,m1是t1的failoverNode)。 使
用此配置,当计算机1(服务于t1和m1)崩溃时,会话不会丢失。 以下非常好的ASCII艺术显示了此设置。
<t1>  <t2>
 . \ / .
  . X .
 . / \ .
<m1>  <m2>

t1和m1部署可以在一台主机上,t2和m2部署也可以在同一台。

当新用户发请求到Tomcat1时, Tomcat1生成session返回给用户的同时,也会同时发给memcached2备份。即Tomcat1 session为主session,memcached2 session为备用session,使用memcached相当于备份了一份Session

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

5.3.2 配置过程

5.3.2.1 下载相关jar包

下载相关jar包,参考下面官方说明的下载链接

https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

tomcat和memcached相关包
clipboard.png

序列化相关下载

clipboard.png

5.3.2.2 修改tomcat配置

修改 $CATALINA_HOME/conf/context.xml

特别注意,t1配置中为failoverNodes="n1", t2配置为failoverNodes="n2

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

配置说明

memcachedNodes="n1:host1.yourdomain.com:11211,n2:host2.yourdomain.com:11211"

memcached的节点: n1、n2只是别名,可以重新命名。
failoverNodes 为故障转移节点,n1是备用节点,n2是主存储节点。另一台Tomcat将n1改为n2,其主节
点是n1,备用节点是n2。

如果配置成功,可以在logs/catalina.out中看到下面的内容

12-APR-2020 16:24:08.975 INFO [t1.magedu.com-startStop-1]
de.javakaffee.web.msm.MemcachedSessionService.startInternal --------
- finished initialization:
- sticky: true
- operation timeout: 1000
- node ids: [n2]
- failover node ids: [n1]
- storage key prefix: null
- locking mode: null (expiration: 5s)

5.3.2.3 准备测试msm的python脚本

t1、t2、n1、n2依次启动成功,分别使用http://t1.magedu.org:8080/http://t2.magedu.org:8080/观察。

开启负载均衡调度器,通过http://proxy.magedu.com来访问看看效果

可以看到浏览器端被调度到不同Tomcat上,但是都获得了同样的SessionID。

停止t2、n2看看效果,恢复看看效果。

范例:访问tomcat,查看memcached中SessionID信息

#!/bin/python3
import memcache
mc = memcache.Client(['10.0.0.101:11211'], debug=True)
stats = mc.get_stats()[0]
print(stats)
for k,v in stats[1].items():
    print(k, v)
    print('-' * 30)
# 查看全部key
    print(mc.get_stats('items')) # stats items 返回 items:5:number 1
    print('-' * 30)
    print(mc.get_stats('cachedump 5 0')) # stats cachedump 5 0 # 5和上面的items返回的值有关;0表示全部

5.3.3 实战案例 1 : tomcat和memcached集成在一台主机

clipboard.png

环境准备:

  • 时间同步,确保NTP或Chrony服务正常运行。
  • 防火墙规则
  • 禁用SELinux
  • 三台主机

5.3.3.1 配置nginx充当proxy

upstream tomcat-server {
             #ip_hash;
             #hash $cookie_JSESSIONID;
             server t1.zhangzhuo.org:8080;
             server t2.zhangzhuo.org:8080;
        }
 location / {
           proxy_pass http://tomcat-server;
        }
[17:31:51 root@proxy ~]#cat /etc/hosts
192.168.10.81 proxy.zhangzhuo.org proxy
192.168.10.82 t1.zhangzhuo.org
192.168.10.83 t2.zhangzhuo.org

5.3.3.2 配置memcached

[17:22:21 root@t1 tomcat]#cat /etc/sysconfig/memcached 
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
#注释下面行
#OPTIONS="-l 127.0.0.1,::1"
[17:32:33 root@t1 tomcat]#systemctl enable --now memcached.service

5.3.3.3 配置 tomcat

配置 tomcat1

[17:34:39 root@t1 tomcat]#vim conf/server.xml
 <Host name="t1.zhangzhuo.org"  appBase="/data/webapps"
            unpackWARs="true" autoDeploy="true">

[17:34:39 root@t1 tomcat]#vim conf/context.xml
###倒数第一行前,即</Context>行的前面,加下面内容
 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
    memcachedNodes="n1:192.168.10.82:11211,n2:192.168.10.83:11211"
    failoverNodes="n1"
    requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
   
    transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"    />


#将相关包传到lib/目录下
asm-5.2.jar
kryo-3.0.3.jar
kryo-serializers-0.45.jar
memcached-session-manager-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
minlog-1.3.1.jar
msm-kryo-serializer-2.3.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
spymemcached-2.12.3.jar

[17:58:10 root@t1 ~]#ll -t /usr/local/tomcat/lib/ | tail -11
-rw-r--r-- 1 tomcat tomcat   53259 Aug 22  2020 asm-5.2.jar
-rw-r--r-- 1 tomcat tomcat  126366 Aug 22  2020 kryo-serializers-0.45.jar
-rw-r--r-- 1 tomcat tomcat   38372 Aug 22  2020 msm-kryo-serializer-2.3.2.jar
-rw-r--r-- 1 tomcat tomcat  285211 Aug 22  2020 kryo-3.0.3.jar
-rw-r--r-- 1 tomcat tomcat    5923 Aug 22  2020 minlog-1.3.1.jar
-rw-r--r-- 1 tomcat tomcat   55684 Aug 22  2020 objenesis-2.6.jar
-rw-r--r-- 1 tomcat tomcat   72265 Aug 22  2020 reflectasm-1.11.9.jar
-rw-r--r-- 1 tomcat tomcat  586620 Aug 22  2020 jedis-3.0.0.jar
-rw-r--r-- 1 tomcat tomcat  167294 Aug 22  2020 memcached-session-manager-2.3.2.jar
-rw-r--r-- 1 tomcat tomcat   10826 Aug 22  2020 memcached-session-manager-tc8-2.3.2.jar
-rw-r--r-- 1 tomcat tomcat  473774 Aug 22  2020 spymemcached-2.12.3.jar

[17:37:03 root@t1 tomcat]#systemctl restart tomcat.service

配置 tomcat2

#t2参考上面t1做配置
 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
    memcachedNodes="n1:192.168.10.82:11211,n2:192.168.10.83:11211"
    failoverNodes="n2"                                                              
    requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
    transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
#将相关包传到lib/目录下

查看tomcat日志

[18:01:44 root@t2 tomcat]#cat logs/catalina.out
-  finished initialization:
- sticky: true
- operation timeout: 1000
- node ids: [n1]
- failover node ids: [n2]
- storage key prefix: null
- locking mode: null (expiration: 5s)
[18:02:05 root@t1 ~]#cat /usr/local/tomcat/logs/catalina.out 
-  finished initialization:
- sticky: true
- operation timeout: 1000
- node ids: [n2]
- failover node ids: [n1]
- storage key prefix: null
- locking mode: null (expiration: 5s)

5.3.3.4 python测试脚本

在t1 上安装部署python3环境,访问memcached

[18:05:57 root@t1 ~]#yum install python3 python3-memcached
#准备python测试脚本
#!/usr/bin/python3
import memcache # pip install python-memcached
mc = memcache.Client(['192.168.10.82:11211','192.168.10.83: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)

5.4 non-sticky 模式

5.4.1 non-sticky 模式工作原理

non-sticky 模式即前端tomcat和后端memcached无关联(无粘性)关系

从msm 1.4.0之后版本开始支持non-sticky模式。

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

后端两个memcached服务器对一个session来说是一个是主,一个是备,但对所有session信息来说每个memcached即是主同时也是备

如果n1下线,n2则转正。n1再次上线,n2依然是主Session存储节点

5.4.2 memcached配置

放到 $CATALINA_HOME/conf/context.xml 中

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

5.4.3 redis 配置

clipboard.png

支持将session存放在Redis中,但当前对Redis的支持不允许连接到多个Redis节点,可以通过Redis的集群服务实现防止redis的单点失败

参考文档 :

https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki

https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration#example-for-non-sticky-sessions--kryo--redis

clipboard.png

下载 jedis.jar,放到 $CATALINA_HOME/lib/ ,对应本次安装就是/usr/local/tomcat/lib。

[15:07:49 root@tomcat1 ~]#yum install -y redis
[15:08:30 root@tomcat1 ~]#vim /etc/redis.conf
bind 0.0.0.0
[15:10:17 root@tomcat1 ~]#systemctl enable --now redis

放到 $CATALINA_HOME/conf/context.xml 中

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

浏览器访问,使用redis相关工具可以观察到redis中的信息

clipboard.png

5.4.4 实战案例: memcached 实现non-sticky模式

5.4.4.1 修改tomcat配置

#在前面实验基础上修改,memcached配置不变,只需要修改tomcat配置
[15:15:17 root@tomcat1 tomcat]#vim conf/context.xml
 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
    memcachedNodes="n1:192.168.10.88:11211,n2:192.168.10.89:11211"
    sticky="false"
    sessionBackupAsync="false"
    lockingMode="uriPattern:/path1|/path2"
    requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
    transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
[15:14:57 root@tomcat1 tomcat]#systemctl restart tomcat.service

#查看日志
-  finished initialization:
- sticky: false
- operation timeout: 1000
- node ids: [n1, n2]
- failover node ids: []
- storage key prefix: null
- locking mode: uriPattern:/path1|/path2 (expiration: 5s)

#t2和t1相同操作

#运行脚本查看key
[15:18:13 root@tomcat1 ~]#python3 py_memcached.py 
------------------------------
('192.168.10.88:11211 (1)', {'426C05715FA18C99CA2C7F4EC476D12A-n1.tomcat2': '[97 b; 1616141731 s]'})
('192.168.10.89:11211 (1)', {'bak:426C05715FA18C99CA2C7F4EC476D12A-n1.tomcat2': '[97 b; 1616141731 s]'})
#再次运行脚本后可以看到,t1为memcached的主节点,t2为备份节点

5.4.5 实战案例: redis 实现 non-sticky 模式的msm

clipboard.png

5.4.5.1 上传redis库到tomcat服务器

[15:16:43 root@tomcat2 tomcat]#ll lib/jedis-3.0.0.jar
-rw-r--r-- 1 tomcat tomcat 586620 Aug 22  2020 lib/jedis-3.0.0.jar

5.4.5.2 安装并配置 Redis 服务

[15:07:49 root@tomcat1 ~]#yum install -y redis
[15:08:30 root@tomcat1 ~]#vim /etc/redis.conf
bind 0.0.0.0
[15:10:17 root@tomcat1 ~]#systemctl enable --now redis

5.4.5.3 修改tomcat 配置指定redis服务器地址

[15:32:47 root@tomcat1 tomcat]#vim conf/context.xml
 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
    memcachedNodes="redis://192.168.10.88:6379"  #和non-sticky的memcached相比,只修改此行
    sticky="false"                                                                  
    sessionBackupAsync="false"
    lockingMode="uriPattern:/path1|/path2"
    requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
    transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>


#查看日志
[15:36:06 root@tomcat1 tomcat]#cat logs/catalina.out
  finished initialization:
- sticky: false
- operation timeout: 1000
- node ids: []
- failover node ids: []
- storage key prefix: null
- locking mode: uriPattern:/path1|/path2 (expiration: 5s)
#t2和t1配置相同

5.4.5.4 测试访问

浏览器刷新访问多次,主机轮询,但SessionID不变

clipboard.png

使用redis工具连接redis 查看SessionID

[15:39:01 root@tomcat1 tomcat]#redis-cli
127.0.0.1:6379> KEYS *

1) "A531E5656BB9D23FA10F9433A7D0F517.tomcat2"
2) "validity:A531E5656BB9D23FA10F9433A7D0F517.tomcat2"
   127.0.0.1:6379> KEYS *
3) "A531E5656BB9D23FA10F9433A7D0F517.tomcat2"
4) "validity:C8EF4EA10928F7D77B58FEF5F597FD1C.tomcat1"
5) "C8EF4EA10928F7D77B58FEF5F597FD1C.tomcat1"
6) "validity:A531E5656BB9D23FA10F9433A7D0F517.tomcat2"

5.5 Session 问题方案总结

通过多组实验,使用不同技术实现了session持久机制

  • session绑定,基于IP或session cookie的。其部署简单,尤其基于session黏性的方式,粒度小,对负载均衡影响小。但一旦后端服务器有故障,其上的session丢失。
  • session复制集群,基于tomcat实现多个服务器内共享同步所有session。此方法可以保证任意一台后端服务器故障,其余各服务器上还都存有全部session,对业务无影响。但是它基于多播实现心跳,TCP单播实现复制,当设备节点过多,这种复制机制不是很好的解决方案。且并发连接多的时候,单机上的所有session占据的内存空间非常巨大,甚至耗尽内存。
  • session服务器,将所有的session存储到一个共享的内存空间中,使用多个冗余节点保存session,这样做到session存储服务器的高可用,且占据业务服务器内存较小。是一种比较好的解决session持久的解决方案。

以上的方法都有其适用性。生产环境中,应根据实际需要合理选择。

不过以上这些方法都是在内存中实现了session的保持,可以使用数据库或者文件系统,把session数据存储起来,持久化。这样服务器重启后,也可以重新恢复session数据。不过session数据是有时效性的,是否需要这样做,视情况而定。


标题:5-session 共享服务器
作者:Carey
地址:HTTPS://zhangzhuo.ltd/articles/2021/03/20/1616231331374.html

生而为人

取消