Tomcat实验2之负载均衡和session

Tomcat实验二

(1)Tomcat常见部署方式:

Tomcat实验2之负载均衡和session_第1张图片


(2)Tomcat要实现负载均衡,必然涉及session问题:
session问题的分析:https://blog.csdn.net/wdirdo/article/details/103190013


(1)tomcat解决session问题

(1)session sticky会话黏性

a.Session绑定

  • nginx:source ip
  • HAProxy:cookie

b.优点:简单易配置

c.缺点:如果目标服务器故障后,如果没有做sessoin持久化,就会丢失session


(2)session复制集群

a.Tomcat自己的提供的多播集群,通过多播将任何一台的session同步到其它节点

b.session复制集群的缺点

  • Tomcat的同步节点不宜过多,互相即时通信同步session需要太多带宽
  • 每一台都拥有全部session,内存占用太多

(3)session server

a.session共享服务器,使用memcached、redis做共享的Session服务器。




(2)nginx实现负载均衡

(1)nginx实现负载均衡说明

此实现先不管session问题,先实现Tomcat可以通过nginx调度


(2)实验拓扑图:

Tomcat实验2之负载均衡和session_第2张图片


(3)nginx配置: 192.168.38.27

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

(4)tomcat配置:192.168.38.17(node1.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()%> #当前时间

(5)tomcat配置:192.168.38.37(node2.zcpzcp.com)

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()%>

(6)Windows的解析文件配置:C:\Windows\System32\drivers\etc\hosts

192.168.38.17 node1.zcpzcp.com
192.168.38.37 node2.zcpzcp.com
192.168.38.27 www.zcpzcp.com

(7)测试:http://www.zcpzcp.com/index.jsp

a.浏览器第一次访问:
Tomcat实验2之负载均衡和session_第3张图片

b.ctrl+r 刷新访问:
Tomcat实验2之负载均衡和session_第4张图片

c.ctrl+r 刷新访问:
Tomcat实验2之负载均衡和session_第5张图片

总结:由于负载均衡,浏览器每次被调度至不同的服务器,但是sessionID浏览器只能保存一份(相同域名),因此sessionID一直改变,无法实现浏览器与web server的会话保持。




(3)session绑定的方式解决session问题

(1)基于session绑定:nginx上实现基于源地址hash

upstream tomcat {
    ip_hash; # 先禁用看看轮询,之后开启开黏性
    server node1.zcpzcp.com:8080;
    server node2.zcpzcp.com:8080;
}

==>预计看到的现象:当浏览器访问:http://www.zcpzcp.com/index.jsp,将一直被调度至web server中其他一台Tomcat上。


(2)测试:基于源地址hash

a.ctrl+r 刷新访问:
Tomcat实验2之负载均衡和session_第6张图片

a.ctrl+r 刷新访问:
Tomcat实验2之负载均衡和session_第7张图片

==>现象:仅有时间改变,sessionID和web server的tomcat均未发生改变


(3)总结:基于源地址hash

①使用基于源地址解决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问题

(1)tomcat session集群

tomcat session集群即后端服务器如果有多个tomcat时,多个tomcat之间将对session进行数据同步,则每一个tomcat节点都有整个tomcat整个集群的session信息。因此浏览器无论被调度至哪一个tomcat节点,tomcat均能识别sessionID,进而完成会话状态保持。


(2)实现tomcat集群的配置

官方文档: https://tomcat.apache.org/tomcat-8.5-doc/cluster-howto.html

  • 建议直接去官网粘贴源码,只需将NioReceiver中的address地址修改为当前主机用于tomcat集群通信的IP


  

  
	
	

  
  	
	
	
	
  

  
  

  
  

  • 这段代码可以放置的位置:
    ①engine(对所以虚拟主机生效)即所有虚拟主机都可以启用Session复制
    ②host(对当前虚拟主机生效)即该虚拟主机可以启用Session复制

(3)修改配置文件:192.168.38.17


在默认的添加了jvmRoute="Tomcat17"  ==>为了后续实验观察现象


②在host虚拟主机可以启用Session复制

...
==>添加tomcat集群的配置
...


(4)修改配置文件:192.168.38.37


在默认的添加了jvmRoute="Tomcat37"  ==>为了后续实验观察现象


②在host虚拟主机可以启用Session复制

...
==>添加tomcat集群的配置
...


(5)Make sure your web.xml has the element

注意:仅在虚拟主机开启session复制是不够的!如下是tomcat官方提供的实现:
Tomcat实验2之负载均衡和session_第8张图片
注意:集群实验中各集群节点一定要保证时间一致,时间不一致,集群的实现肯定有问题。

[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文件并添加


(6)session同步测试:

①打开浏览器访问此域名:http://www.zcpzcp.com/index.jsp
Tomcat实验2之负载均衡和session_第9张图片

②ctrl+r刷新:
Tomcat实验2之负载均衡和session_第10张图片

==>sessionID未改变,无论调度至192.168.38.17还是192.168.38.37


(7)总结:tomcat session集群的方式解决session问题

①每个tomcat节点都需保存整个节点的session信息,tomcat集群中主机数目小,session信息少还可以使用此方法实现,若session信息较多,那么对于tomcat内存的要求。

②随着tomcat节点数目的增加,内部通信的代价也将逐渐增加。

③session同步解决session问题两个问题:后端动态服务器的内存和内部通信,适用于小场景,session较少,动态服务器集群数量较少。




(5)session共享

(1)msm

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。

(2)tomcat与缓存服务:

官网说明: https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

Tomcat实验2之负载均衡和session_第11张图片

  • 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)

(3)tomcat需要安装的包:

tomcat将session发送给缓存服务:
Tomcat实验2之负载均衡和session_第12张图片

支持序列化的jar包:
Tomcat实验2之负载均衡和session_第13张图片
Tomcat实验2之负载均衡和session_第14张图片

将spymemcached.jar、memcached-session-manage、kyro相关的jar文件都放到Tomcat的lib目录中去,这个目录是 $CATALINA_HOME/lib/ ,对应本次安装就是/usr/local/tomcat/lib




sticky模式

(1)sticky原理:

①官网画的拓扑图
Tomcat实验2之负载均衡和session_第15张图片

②按照官网画的图重新绘制的拓扑图
Tomcat实验2之负载均衡和session_第16张图片

③原理阐述:
   当请求结束时Tomcat的session会送给memcached备份。即Tomcat session为主session,memcached session为备session,使用memcached相当于备份了一份Session。查询Session时Tomcat会优先使用自己内存的Session,Tomcat通过jvmRoute发现不是自己的Session,便从memcached中找到该Session,更新本机Session,请求完成后更新memcached。

④示例:

  • tomcat1中有个session1 那么session1保存的位置:tomcat1 和 memcache2
    如果memcache2 节点故障,那么session1 的信息才会被迫存放至 memcache1。

⑤总结:

  • sticky模式最关键的是:使用tomcat自己的内存作为存储session的主,然后交叉以对方的memcache缓存作为’备份的主’(备份的主简单为数据优先备份存放的位置)。

sticky的实现

注:此处tomcat操作相同,省略一个节点的tomcat操作。

①安装memcache

[root@centos7-17 tomcat]# yum install -y memcached
[root@centos7-17 tomcat]# systemctl start memcached.service

②tomcat配置

  • node1配置中为failoverNodes=“n17”, node2配置为failoverNodes=“n37”
  • failoverNodes故障转移节点,n17是备用节点,n37是主存储节点。另一台Tomcat将n17改为n37,其主节点是n17,备用节点是n37
  • memcached的节点们;n17、n37只是别名,可以重新命名。
conf/context.xml 中


    ...
    
  

③配置tomcat配置文件截图:
Tomcat实验2之负载均衡和session_第17张图片

④配置成功的显示日志:
Tomcat实验2之负载均衡和session_第18张图片


sticky的测试:

①浏览器访问:http://www.zcpzcp.com/index.jsp
Tomcat实验2之负载均衡和session_第19张图片
==>调度至192.168.38.17主机,那么session信息应该保存在192.168.38.37主机

②查看memcache的数据:
Tomcat实验2之负载均衡和session_第20张图片

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模式

(1)non-sticky模式原理

①拓扑图:
Tomcat实验2之负载均衡和session_第21张图片

②原理:

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

  • Tomcat session为中转Session,如果n1为主session,n2为备session。产生的新的Session会发送给主、备memcached,并清除本地Session。

  • 其中memcache主节点下线,则备用节点转正,主节点上线,将成为目前的备用节点。


(2)non-sticky的tomcat配置:


...




主要变化是这三行:
    sticky="false"
    sessionBackupAsync="false"
    lockingMode="uriPattern:/path1|/path2"
  • 修改配置后重启memcache 和 tomcat服务,重启memcache主要是将上次实现的数据清空

(3)non-sticky测试:

①浏览器重新访问:http://www.zcpzcp.com/index.jsp
Tomcat实验2之负载均衡和session_第22张图片

②查看memcache中保存的session信息
Tomcat实验2之负载均衡和session_第23张图片

③当17主机的memcache服务停止,浏览器继续访问和memcache的信息保存:
Tomcat实验2之负载均衡和session_第24张图片
Tomcat实验2之负载均衡和session_第25张图片
==>sessionID仍然没有改变,但是memcache存储的session只能放置37主机。




最后附上:查看memcache内存信息的python程序:

  • 注:pip install python-memcached
  • 运行时需要安装python-memcached,作为memcache客户端连接memcache
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表示全部



你可能感兴趣的:(memcache,Tomcat)