前言
在做负载均衡集群的时候,如果后端是应用服务器,我们就有一个不得不考虑的一个问题:会话绑定。为了追踪会话,我们常见的有三种方式:
(1)session sticky
:会话粘性,常见有2种方式:
-
source_ip
:采用源地址绑定方式 -
nginx:ip_hash,ip地址哈希
-
haproxy:source
-
lvs:sh,源地址哈希
-
cookie
:基于cookie绑定 -
nginx:hash
-
haproxy:cookie
(2)session cluster
:session集群
(3)session server
:session服务器,结合memcache或redis。
下面以Tomcat为例,来分别演示一下。
Tomcat Session Cluster结合httpd作为反代有如下三种实现方式:
Tomcat Cluster (1) httpd + tomcat cluster httpd: mod_proxy, mod_proxy_http, mod_proxy_balancer tomcat cluster:http connector (2) httpd + tomcat cluster httpd: mod_proxy, mod_proxy_ajp, mod_proxy_balancer tomcat cluster:ajp connector (3) httpd + tomcat cluster httpd: mod_jk tomcat cluster:ajp connector
实验步骤
在node3和node4上安装部署tomcat
[root@node3 ~]# yum install java-1.8.0-openjdk-devel tomcat-lib.noarch tomcat-admin-webapps.noarch tomcat-webapps.noarch -y
创建测试页面
:
[root@node4 ~]# mkdir -pv /usr/share/tomcat/webapps/test/{WEB-INF,lib,classes} mkdir: created directory ‘/usr/share/tomcat/webapps/test’ mkdir: created directory ‘/usr/share/tomcat/webapps/test/WEB-INF’ mkdir: created directory ‘/usr/share/tomcat/webapps/test/lib’ mkdir: created directory ‘/usr/share/tomcat/webapps/test/classes’ [root@node4 ~]#
为了演示效果,node3上测试页面内容如下:
<%@ page language="java" %> <html> <head><title>Tomcat:Node3</title></head> <body> <h1><font color="red">Tomcat:Node3</font></h1> <table align="centre" border="1"> <tr> <td>Session ID</td> <% session.setAttribute("magedu.com","magedu.com"); %> <td><%= session.getId() %></td> </tr> <tr> <td>Created on</td> <td><%= session.getCreationTime() %></td> </tr> </table> </body> </html>
为了演示效果,node4上测试页面内容如下:
<%@ page language="java" %> <html> <head><title>Tomcat:Node4</title></head> <body> <h1><font color="blue">Tomcat:Node4</font></h1> <table align="centre" border="1"> <tr> <td>Session ID</td> <% session.setAttribute("magedu.com","magedu.com"); %> <td><%= session.getId() %></td> </tr> <tr> <td>Created on</td> <td><%= session.getCreationTime() %></td> </tr> </table> </body> </html>
启动tomcat,访问测试:
1)用nginx反代:session sticky(ip_hash)的实现
在node2上安装nginx,配置:
在/etc/nginx/nginx.conf中的http上下文中定义服务器组
upstream tcsrvs { server 172.16.47.103:8080; server 172.16.47.104:8080; }
在/etc/nginx/conf.d/default.conf中使用代理
location / { root /usr/share/nginx/html; proxy_pass http://tcsrvs/; index index.html index.htm; }
启动nginx,浏览器访问node2的ip:
可以看到,负载均衡功能已经实现了,但是Session ID一直在变,session绑定问题还没决解决。
要想基于session sticky
绑定,我们可以做ip_hash
,在upstream
段中加入ip_hash
,再来访问:
可以看到,session id一直保持不变,会话绑定的问题解决了,但是用户也被绑定到一台主机上了。
2)用httpd反代:session sticky(cookie)
停掉nginx,在node2上安装httpd:yum install httpd -y
配置httpd,让其负载均衡node3和node4,要用到mod Proxy balancer模块,要确保该模块存在,可以使用httpd -M,查看
<proxy balancer://tcsrvs> BalancerMember http://172.16.47.103:8080 BalancerMember http://172.16.47.104:8080 ProxySet lbmethod=byrequests </Proxy> <VirtualHost *:80> ServerName lb.magedu.com ProxyVia On ProxyRequests Off ProxyPreserveHost On <Proxy *> Require all granted </Proxy> ProxyPass / balancer://tcsrvs/ ProxyPassReverse / balancer://tcsrvs/ <Location /> Require all granted </Location> </VirtualHost>
启动httpd,访问node2,可以看到,同nginx一样,实现了负载均衡,但是session问题没解决
要实现会话的绑定,修改配置如下:
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED <proxy balancer://tcsrvs> BalancerMember http://172.16.47.103:8080 route=Tomcatnode3 loadfactor=1 BalancerMember http://172.16.47.104:8080 route=Tomcatnode4 loadfactor=2 ProxySet lbmethod=byrequests ProxySet stickysession=ROUTEID </Proxy> <VirtualHost *:80> ServerName lb.magedu.com ProxyVia On ProxyRequests Off ProxyPreserveHost On <Proxy *> Require all granted </Proxy> ProxyPass / balancer://tcsrvs/ ProxyPassReverse / balancer://tcsrvs/ <Location /> Require all granted </Location> </VirtualHost>
可以看到会话被绑定了。如果要是用ajp的话,只需要把http改为ajp就可以,但是要确保ajp模块被加载。
另外,proxy balancer有一个web管理界面,类似于tomcat的gui界面,如果要启用的话,需要加入以下配置:
<Location /balancer-manager> SetHandler balancer-manager ProxyPass ! Require all granted </Location>
使用session sticky会有很多问题,它是通过把会话与主机绑定来实现会话保持的,但如果某一台主机挂了,该主机上用户的session也就丢失了,所以我们可以采用session cluster来保存用户会话。
3)session cluster
正常情况下,session信息是保存在用户所访问的服务器上的,服务器挂了,用户的session也就丢失了,但是我们可以通过session cluster的方式来实现将用户的session信息保存在后端的所有服务器上,这样,无论用户的请求被调度至哪一台服务器,session都不会丢失。
四种常见的session manager
-
StandardManager
: -
PersistentManager
: 可以将session信息保存在持久存储中 -
DeltaManager
: 将session信息通过多播的形式共享到其他节点 -
BackupManager
: 将session信息共享到特定的一个节点上
我们使用DeltaManager方式来配置:
以下配置可以放在host中,也可以放在engine中,生效范围不同
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6"> <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" mapSendOptions="6"/> <!-- <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.47.4" port="45564" frequency="500" dropTime="3000"/> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="172.16.47.104" port="5000" selectorTimeout="100" 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.MessageDispatch15Interceptor"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/> </Channel> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/> <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> 注意:<Engine name="Catalina" defaultHost="localhost" jvmRoute="Tomcatnode4" >,这个jvmRoute必须得配置
然后执行如下操作,注意,node3,4上都要执行。
[root@node4 /usr/share/tomcat/webapps]# cp /etc/tomcat/web.xml test/WEB-INF/ vim test/WEB-INF/web.xml ,加入如下配置。 <distributable/>
重启tomcat,通过日志tail -f /var/log/tomcat/catalina.2017-02-09.log ,可以看到cluster的工作过程,这里就不截图了
利用上面nginx的配置,不过要去掉ip_hash,我们启动nginx,然后浏览器访问:
可以看到被调度到不同主机上了,但是Session ID一直没有变,这样,我们就实现了session cluster的功能。
总结
这篇文章实现了tomcat session 保持的各种方法,但是实际上这些方式用的并不多,试想当后端tomcat服务器很多的情况下,它们要一直多播通信,在用户高并发的情况下,很可能会造成网络拥堵。所以在实际生产环境中的解决方法是做session server,我们下篇文章再演示。
原创文章,作者:Lurker,如若转载,请注明出处:http://www.178linux.com/68266