实战案例
环境准备:
- 时间同步,确保NTP或Chrony服务正常运行。
- 防火墙规则
- 禁用SELinux
- 五台主机
IP | 主机名 | 服务 | |
---|---|---|---|
10.0.0.100 | proxy | 调度器 | Nginx、HTTPD |
10.0.0.101 | t1 | tomcat1 | JDK8、Tomcat8 |
10.0.0.102 | t2 | tomcat2 | JDK8、Tomcat8 |
10.0.0.103 | m1 | memcached1 | memcached |
10.0.0.104 | m2 | memcached2 | memcached |
- 准备proxy主机的配置,利用nginx作为反向代理
[root@proxy ~]#cat /etc/nginx/nginx.conf
http {
......
upstream tomcat-server {
#ip_hash;
server t1.magedu.org:8080;
server t2.magedu.org:8080;
}
server {
......
location / {
}
location ~* /.(jsp|do)$ {
proxy_pass http://tomcat-server;
}
[root@proxy ~]#cat /etc/hosts
10.0.0.100 proxy.magedu.org proxy
10.0.0.101 t1.magedu.org t1
10.0.0.102 t2.magedu.org t2
- 在10.0.0.101和102上准备tomcat,并安装和配置memcached的客户
[root@t1 tomcat]#vim conf/server.xml
<Engine name="Catalina" defaultHost="t1.magedu.org" jvmRoute="Tomcat1">
......
<Host name="t1.magedu.org" appBase="/data/webapps" autoDeploy="true" >
</Host>
</Engine>
</Service>
</Server>
[root@t1 tomcat]#vim conf/context.xml
<Context>
......
<Manager pathname="" />
-->
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:10.0.0.103:11211,n2:10.0.0.104:11211" failoverNodes="n1"
requestUriIgnorePattern=".*/.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
</Context>
#将相关包传到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
[root@t1 tomcat]#ls lib/ -t |tail
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
[root@t1 tomcat]#cat /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>lbjsptest</title>
</head>
<body>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>
#t2参考上面t1做配置
- 在m1和m2上分别配置memcached
#m1的配置
[root@m1 ~]#dnf -y install memcached
[root@m1 ~]#vim /etc/sysconfig/memcached
[root@m1 ~]#cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
#OPTIONS="-l 127.0.0.1,::1"
OPTIONS=""
[root@m1 ~]#systemctl start memcached.service
#安装python3环境
[root@m1 ~]#dnf -y install python3
[root@m1 ~]#pip3 install python-memcached
[root@m1 ~]#cat showmemcached.py
import memcache # pip install python-memcached
mc = memcache.Client(['10.0.0.103: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表示全部
#m2的配置
[root@m2 ~]#dnf -y install memcached
[root@m2 ~]#vim /etc/sysconfig/memcached
[root@m2 ~]#cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
#OPTIONS="-l 127.0.0.1,::1"
OPTIONS=""
[root@m2 ~]#systemctl start memcached.service
#安装python3环境
[root@m2 ~]#dnf -y install python3
[root@m2 ~]#pip3 install python-memcached
[root@m2 ~]#cat showmemcached.py
import memcache # pip install python-memcached
mc = memcache.Client(['10.0.0.104: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表示全部
- 查看结果,刷新浏览器可以看到SessionID前面部分不变
#上面结果表示SessionID 保存到了m2的memcached主机上,可以执行python脚本验证
[root@m1 ~]#python3 showmemcached.py
------------------------------
[('10.0.0.103:11211 (1)', {'items:5:number': '1', 'items:5:number_hot': '0', 'items:5:number_warm': '0', 'items:5:number_cold': '1', 'items:5:age_hot': '0', 'items:5:age_warm': '0', 'items:5:age': '14', 'items:5:evicted': '0', 'items:5:evicted_nonzero': '0', 'items:5:evicted_time': '0', 'items:5:outofmemory': '0', 'items:5:tailrepairs': '0', 'items:5:reclaimed': '0', 'items:5:expired_unfetched': '0', 'items:5:evicted_unfetched': '0', 'items:5:evicted_active': '0', 'items:5:crawler_reclaimed': '0', 'items:5:crawler_items_checked': '0', 'items:5:lrutail_reflocked': '0', 'items:5:moves_to_cold': '1', 'items:5:moves_to_warm': '0', 'items:5:moves_within_lru': '0', 'items:5:direct_reclaims': '0', 'items:5:hits_to_hot': '0', 'items:5:hits_to_warm': '0', 'items:5:hits_to_cold': '0', 'items:5:hits_to_temp': '0'})]
------------------------------
[('10.0.0.103:11211 (1)', {'59A4BE74A69C70F56FA5A01D5191F6D3-n1.Tomcat2': '[97 b; 1581605764 s]'})]
[root@m2 ~]#python3 showmemcached.py
------------------------------
[('10.0.0.104:11211 (1)', {})]
------------------------------
[('10.0.0.104:11211 (1)', {})]
停止t2和m2的服务,再观察结果
[root@t2 ~]#systemctl stop tomcat
[root@m2 ~]#systemctl stop memcached.service
non-sticky模式
原理
从msm 1.4.0之后开始支持non-sticky模式。
Tomcat session为中转Session,n1为主session,n2为备session。产生的新的Session会发送给主、备memcached,并清除本地Session。
n1下线,n2转正。n1再次上线,n2依然是主Session存储节点。
memcached配置(问题)
放到 $CATALINA_HOME/conf/context.xml
中
<Context>
...
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:10.0.0.101:11211,n2:10.0.0.102: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>
redis配置
下载jedis.jar,放到$CATALINA_HOME/lib/
,对应本次安装就是/usr/local/tomcat/lib。
# yum install redis
# vim /etc/redis.conf
bind 0.0.0.0
# systemctl start redis
放到 $CATALINA_HOME/conf/context.xml
中
<Context>
...
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="redis://10.0.0.101: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>
浏览器访问,使用redis相关工具可以观察到redis中的信息
总结
通过多组实验,使用不同技术实现了session持久机制
- session绑定,基于IP或session cookie的。其部署简单,尤其基于session黏性的方式,粒度小,对负载均衡影响小。但一旦后端服务器有故障,其上的session丢失。
- session复制集群,基于tomcat实现多个服务器内共享同步所有session。此方法可以保证任意一台后端服务器故障,其余各服务器上还都存有全部session,对业务无影响。但是它基于多播实现心跳,TCP单播实现复制,当设备节点过多,这种复制机制不是很好的解决方案。且并发连接多的时候,单机上的所有session占据的内存空间非常巨大,甚至耗尽内存。
- session服务器,将所有的session存储到一个共享的内存空间中,使用多个冗余节点保存session,这样做到session存储服务器的高可用,且占据业务服务器内存较小。是一种比较好的解决session持久的解决方案。
以上的方法都有其适用性。生产环境中,应根据实际需要合理选择。
不过以上这些方法都是在内存中实现了session的保持,可以使用数据库或者文件系统,把session数据存储起来,持久化。这样服务器重启后,也可以重新恢复session数据。不过session数据是有时效性的,是否需要这样做,视情况而定。
本文链接:http://www.yunweipai.com/35198.html
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/52752.html