Tomcat实验二 |
(1)Tomcat常见部署方式:
(2)Tomcat要实现负载均衡,必然涉及session问题:
session问题的分析:https://blog.csdn.net/wdirdo/article/details/103190013
(1)tomcat解决session问题 |
(1)session sticky会话黏性
a.Session绑定
b.优点:简单易配置
c.缺点:如果目标服务器故障后,如果没有做sessoin持久化,就会丢失session
(2)session复制集群
a.Tomcat自己的提供的多播集群,通过多播将任何一台的session同步到其它节点
b.session复制集群的缺点
(3)session server
a.session共享服务器,使用memcached、redis做共享的Session服务器。
(2)nginx实现负载均衡 |
此实现先不管session问题,先实现Tomcat可以通过nginx调度
upstream tomcat {
#ip_hash; # 先禁用看看轮询,之后开启开黏性
server node1.zcpzcp.com:8080;
server node2.zcpzcp.com:8080;
}
location / {
root /data/nginx;
index index.html;
location ~* \.(jsp|do)$ {
proxy_pass http://tomcat;
#proxy_pass http://node1.zcpzcp.com:8080;
}
}
[root@centos7-27 ~]# cat /etc/hosts
192.168.38.17 node1.zcpzcp.com
192.168.38.37 node2.zcpzcp.com
a.tomcat虚拟主机配置:
# #默认的缺省虚拟主机为localhost
#将缺省主页修改为node1.zcpzcp.com虚拟主机
....
b.idnex.jsp文件:
[root@centos7-17 tomcat]# cat /data/webapp/ROOT/index.jsp
<%@ page import="java.util.*" %>
lbjsptest
On <%=request.getServerName() %> #取servername
<%=request.getLocalAddr() + ":" + request.getLocalPort() %> #取本地IP和port
SessionID = <%=session.getId() %>#显示SessionID
<%=new Date()%> #当前时间
a.tomcat虚拟主机配置:
# #默认的缺省虚拟主机为localhost
#将缺省主页修改为node1.zcpzcp.com虚拟主机
....
b.idnex.jsp文件:
[root@centos7-37 tomcat]# cat /data/webapp/ROOT/index.jsp
<%@ page import="java.util.*" %>
lbjsptest
On <%=request.getServerName() %>
<%=request.getLocalAddr() + ":" + request.getLocalPort() %>
SessionID = <%=session.getId() %>
<%=new Date()%>
192.168.38.17 node1.zcpzcp.com
192.168.38.37 node2.zcpzcp.com
192.168.38.27 www.zcpzcp.com
总结:由于负载均衡,浏览器每次被调度至不同的服务器,但是sessionID浏览器只能保存一份(相同域名),因此sessionID一直改变,无法实现浏览器与web server的会话保持。
(3)session绑定的方式解决session问题 |
upstream tomcat {
ip_hash; # 先禁用看看轮询,之后开启开黏性
server node1.zcpzcp.com:8080;
server node2.zcpzcp.com:8080;
}
==>预计看到的现象:当浏览器访问:http://www.zcpzcp.com/index.jsp,将一直被调度至web server中其他一台Tomcat上。
==>现象:仅有时间改变,sessionID和web server的tomcat均未发生改变
①使用基于源地址解决session问题,是一种不好的处理方式,因为web server做负载均衡的目的就是实现将访问的并发分摊至后端各个服务器,但是基于源地址hash,调度始终指向后端某台服务器。
②现在局域网上网基本都是通过SNAT实现的,因此整个局域网上网映射的公网IP相同,基于源地址hash则认为整个局域网的人都属于同一用户。
③其实session绑定中基于cookie做hash仅仅是将用户根据浏览器的不同调度至后端服务器,即将同一局域网和同一主机的不同浏览器分辨出为不同用户,依旧解决不了后端服务器故障的问题。
④session绑定没能从根本上解决问题,即浏览器中的sessionID必须去有sessionID这台后端服务器才能有用,如果带着此sessionID被调度至别的后端服务器,后端服务器找不到此sessionID时,将重发sessionID,等带着此sessionID去访问后端服务器别的主机时,别的主机也找不到此sessionID,本质上解决问题:需要所有的后端服务器均能识别浏览器本次访问时所携带的sessionID。
注1:web server的tomcat代表后端动态服务器,即后端动态服务器使用tomcat举例。
注2:session绑定的方式实现虽然简单,但是实际上却不会使用session绑定的方式处理会话状态保持的问题。
(4)后端服务器session同步解决session问题 |
tomcat session集群即后端服务器如果有多个tomcat时,多个tomcat之间将对session进行数据同步,则每一个tomcat节点都有整个tomcat整个集群的session信息。因此浏览器无论被调度至哪一个tomcat节点,tomcat均能识别sessionID,进而完成会话状态保持。
官方文档: https://tomcat.apache.org/tomcat-8.5-doc/cluster-howto.html
①
在默认的添加了jvmRoute="Tomcat17" ==>为了后续实验观察现象
②在host虚拟主机可以启用Session复制
...
==>添加tomcat集群的配置
...
①
在默认的添加了jvmRoute="Tomcat37" ==>为了后续实验观察现象
②在host虚拟主机可以启用Session复制
...
==>添加tomcat集群的配置
...
注意:仅在虚拟主机开启session复制是不够的!如下是tomcat官方提供的实现:
注意:集群实验中各集群节点一定要保证时间一致,时间不一致,集群的实现肯定有问题。
[root@centos7-37 tomcat]#mkdir /data/webapp/ROOT/WEB-INF
[root@centos7-37 tomcat]#cp conf/web.xml /data/webapp/ROOT/WEB-INF/
[root@centos7-37 tomcat]#vim /data/webapp/ROOT/WEB-INF/web.xml
#在/data/webapp/ROOT/WEB-INF/web.xml最后添加
192.168.38.17(tomcat另一节点)做以上相同操作,也需要/data/webapp/ROOT/WEB-INF/web.xml文件并添加
①打开浏览器访问此域名:http://www.zcpzcp.com/index.jsp
==>sessionID未改变,无论调度至192.168.38.17还是192.168.38.37
①每个tomcat节点都需保存整个节点的session信息,tomcat集群中主机数目小,session信息少还可以使用此方法实现,若session信息较多,那么对于tomcat内存的要求。
②随着tomcat节点数目的增加,内部通信的代价也将逐渐增加。
③session同步解决session问题两个问题:后端动态服务器的内存和内部通信,适用于小场景,session较少,动态服务器集群数量较少。
(5)session共享 |
msm(memcached session manager)提供将Tomcat的session保持到memcached或redis的程序,可以实现高可用。
目前项目托管在Github, https://github.com/magro/memcached-session-manager
支持Tomcat的6.x、7.x、8.x、9.x。
官网说明: 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。
sticky模式 |
③原理阐述:
当请求结束时Tomcat的session会送给memcached备份。即Tomcat session为主session,memcached session为备session,使用memcached相当于备份了一份Session。查询Session时Tomcat会优先使用自己内存的Session,Tomcat通过jvmRoute发现不是自己的Session,便从memcached中找到该Session,更新本机Session,请求完成后更新memcached。
④示例:
⑤总结:
注:此处tomcat操作相同,省略一个节点的tomcat操作。
①安装memcache
[root@centos7-17 tomcat]# yum install -y memcached
[root@centos7-17 tomcat]# systemctl start memcached.service
②tomcat配置
conf/context.xml 中
...
①浏览器访问:http://www.zcpzcp.com/index.jsp
==>调度至192.168.38.17主机,那么session信息应该保存在192.168.38.37主机
memcache的数据:
[('192.168.38.17:11211 (1)', {'1DF770481060C28E523C7E0312C3F09C-n17.Tomcat37': '[99 b; 1574424758 s]'})
('192.168.38.37:11211 (1)', {'1DF770481060C28E523C7E0312C3F09C-n37.Tomcat17': '[99 b; 1574424311 s]'})]
==>sessionID无论在17或者37主机均为:1DF770481060C28E523C7E0312C3F09C
non-sticky模式 |
②原理:
从msm 1.4.0之后开始支持non-sticky模式。
Tomcat session为中转Session,如果n1为主session,n2为备session。产生的新的Session会发送给主、备memcached,并清除本地Session。
其中memcache主节点下线,则备用节点转正,主节点上线,将成为目前的备用节点。
...
主要变化是这三行:
sticky="false"
sessionBackupAsync="false"
lockingMode="uriPattern:/path1|/path2"
①浏览器重新访问:http://www.zcpzcp.com/index.jsp
③当17主机的memcache服务停止,浏览器继续访问和memcache的信息保存:
==>sessionID仍然没有改变,但是memcache存储的session只能放置37主机。
最后附上:查看memcache内存信息的python程序:
import memcache # pip install python-memcached
mc = memcache.Client(['192.168.142.152:11211','192.168.142.153: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表示全部