tomcat负载均衡与会话
tomcat负载均衡
nginx
1)在docker上创建两个tomcat容器
[root@ydong ~]# docker run --name tomcat -d --hostname ydong.com -v /data/ydong:/usr/local/ydong tomcat:9.0.37-jdk8-openjdk-slim-buster
[root@ydong ~]# docker run --name tomcat2 -d --hostname ydong.com -v /data/ydong2:/usr/local/ydong tomcat:9.0.37-jdk8-openjdk-slim-buster
2)为两个容器准备网页
[root@ydong data]# ls ydong/ROOT/
class index.jsp lib WEB-INF、
[root@ydong data]# ls ydong2/ROOT/
class index.jsp lib WEB-INF
# 两个是同样的目录,但是index.jsp不一样
3)将存储卷中的文件直接复制到webapps目录下
[root@ydong data]# docker exec -it tomcat /bin/bash
root@ydong:/usr/local/tomcat# cp -r ../ydong/ROOT webapps
[root@ydong data]# docker exec -it tomcat2 /bin/bash
root@ydong:/usr/local/tomcat# cp -r ../ydong/ROOT webapps
4)测试访问界面
5)利用nginx反代,nginx和docker在同一主机上
upstream tcservs {
server 172.17.0.2:8080;
server 172.17.0.3:8080;
}
location / {
proxy_pass http://tcservs;
}
#添加上以上规则,由于是测试,所以没设置权重和关闭了长连接以及它的proxy_cache相关选项
第一次访问
刷新访问
httpd
httpd反代用到了它的proxy modules。
示例:
vim /etc/httpd/conf.d/tomcat.conf
<proxy balancer://tcsrvs>
BalancerMember http://172.17.0.2:8080 loadfactor=1
# loadfactor 权重
BalancerMember http://172.17.0.3:8080 loadfactor=1
ProxySet lbmethod=byrequests
#lbmethod:访问方式,byrequests 加权轮询
</Proxy>
<VirtualHost *:80>
ServerName www.ydong.com
ProxyVia On
ProxyRequests Off
ProxyPreserveHost On
keepalive off
<Proxy *>
Require all granted
</Proxy>
ProxyPass / balancer://tcsrvs/
ProxyPassReverse / balancer://tcsrvs/
<Location />
Require all granted
</Location>
</VirtualHost>
会话保持
会话粘性
nginx
nginx的session sticky 有几种方式
- ip_hash
- hash key
nginx直接在nginx.conf里修改
简单示例:
upstream tcservs{
ip_hash;
server 172.17.0.2:8080;
server 172.17.0.3:8080;
}
location / {
proxy_pass http://tcservs;
}
根据源地址hash,只要是源地址访问的都发送同一个后端服务器上
一致性hash示例:
upstream tcservs{
hash $request_uri consistent;
server 172.17.0.2:8080;
server 172.17.0.3:8080;
}
location / {
proxy_pass http://tcservs;
}
绑定请求的uri,只要访问同一个uri,都发送到后端同一个服务器上。
httpd
httpd实现session sticky的话,需要借助cookie
示例:
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<proxy balancer://tcsrvs>
BalancerMember http://172.17.0.2:8080 route=TomcatA loadfactor=1
BalancerMember http://172.17.0.3:8080 route=TomcatB loadfactor=1
ProxySet lbmethod=byrequests
ProxySet stickysession=ROUTEID
</Proxy>
<VirtualHost *:80>
ServerName www.ydong.com
ProxyVia On
ProxyRequests Off
ProxyPreserveHost On
keepalive off
<Proxy *>
Require all granted
</Proxy>
ProxyPass / balancer://tcsrvs/
ProxyPassReverse / balancer://tcsrvs/
<Location />
Require all granted
</Location>
</VirtualHost>
第一次访问
第二次访问
在保持会话的时候,tomcat的server.xml文件需要添加一项JVMRoute选项。这个选项功能主要是
jvm_route的原理(from 作者 Weibin Yao):
- 一开始请求过来,没有带session信息,jvm_route就根据round robin的方法,发到一台tomcat上面。
- tomcat添加上session 信息,并返回给客户。
- 用户再此请求,jvm_route看到session中有后端服务器的名称,它就把请求转到对应的服务器上。
暂时jvm_route模块还不支持默认fair的模式。jvm_route的工作模式和fair是冲突的。对于某个特定用户,当一直为他服务的tomcat宕机后,默认情况下它会重试max_fails的次数,如果还是失败,就重新启用round
robin的方式,而这种情况下就会导致用户的session丢失。总的说来,jvm_route是通过session_cookie这种方式来实现session粘性,将特定会话附属到特定tomcat上,从而解决session不同步问题,但无法解决宕机后会话转移问题。
转自:http://blog.163.com/momoliu88@126/blog/static/139208463201231104120587/
从httpd可以看出,请求报文头部带有TomcatB,后端服务器看到TomcatB的时候,tomcat中的cluster会根据对应的JVMRoute来进行响应。
tomcat session replication cluster
tomcat具有会话复制的功能、在tomcat的集群内,每个节点的会话都会同步到集群中每个节点的服务器内。这个功能是由tomcat中DeltaManager(集群增量会话管理器)实现的。
示例
以下的需要写在server.xml上的engine或者host中。 engine表示所有主机,host表示指定主机。
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<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.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="192.168.192.131" #此处是绑定地址,最高绑定在服务的ip地址上
port="4000"
autoBind="100"
selectorTimeout="5000"
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.MessageDispatchInterceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<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>
上述完成之后,还需要在web.xml中添加<distributable/>
元素。 而且web.xml复制到WEB-INF下。
前面反代和上边没有区别,nginx和httpd,HAproxy都可以。
测试
可以看到,内容不同,但是会话一直存在