Tomcat 负载均衡 小节3

169 阅读5分钟

@[TOC](Tomcat 负载均衡 小节3)

负载均衡

动态服务器的问题,往往就是并发能力太弱,往往需要多台动态服务器一起提供服务。如何把并发的压力分摊,这就需要调度,采用一定的调度策略,将请求分发给不同的服务器,这就是Load Balance负载均衡。

当单机的Tomcat,演化出多机多级部署的时候,一个问题便凸显出来,这就是Session。而这个问题的由来,都是由于HTTP协议在设计之初没有想到未来的发展。

HTTP的无状态,有连接和短连接

  • 无状态:指的是服务器端无法知道2次请求之间的联系,即使是前后2次请求来自同一个浏览器,也没有任何数据能够判断出是同一个浏览器的请求。后来可以通过cookie、session机制来判断。
    • 浏览器端第一次HTTP请求服务器端时,在服务器端使用session这种技术,就可以在服务器端产生一个随机值即SessionlD发给浏览器端,浏览器端收到后会保持这个SessionID在Cookie当中,这个Cookie值一般不能持久存储,浏览器关闭就消失。浏览器在每一次提交HTTP请求的时候会把这个SessionlD传给服务器端,服务器端就可以通过比对知道是谁了
    • Session通常会保存在服务器端内存中,如果没有持久化,则易丢失
    • Session会定时过期。过期后浏览器如果再访问,服务端发现没有此ID,将给浏览器端重新发新的SessionID
    • 更换浏览器也将重新获得新的SessionlD
  • 有连接:是因为它基于TCP协议,是面向连接的,需要3次握手、4次断开。
  • 短连接:Http 1.1之前,都是一个请求一个连接,而Tcp的连接创建销毁成本高,对服务器有很大的影响。所以,自Http 1.1开始,支持keep-alive,默认也开启,一个连接打开后,会保持一段时间(可设置),浏览器再访问该服务器就使用这个Tcp连接,减轻了服务器压力,提高了效率。

服务器端如果故障,即使Session被持久化了,但是服务没有恢复前都不能使用这些SessionlD.

如果使用HAProxy或者Nginx等做负载均衡器,调度到了不同的Tomcat上,那么也会出现找不到SessionlD的情况。

会话保持

  1. session sticky会话黏性

Session绑定

  • nginx:source ip
  • HAProxy:cookip

优点:简单易配置

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

  1. session复制集群 Tomcat自己的提供的多播集群,通过多播将任意一台的session同步到其他节点。

缺点:

  • Tomcat的同步节点不宜过多,互相即时通信同步session需要太多带宽
  • 每一台都拥有全部session,内存损耗太多
  1. session server session共享服务器,使用memcached、redis做共享的Session服务器。

规划

IP主机名服务
37.13t0调度器Nginx或Httpd
37.14t1tomcat1JDK8、Tomcat8
37.15t2tomcat2JDK8、Tomcat8
#每台主机的域名解析
~]# vim /etc/hosts
192.168.37.13 t0.123.com t0
192.168.37.14 t1.123.com t1
192.168.37.15 t2.123.com t2

软件包:apache-tomcatindex.jsp

#解压缩到指定目录'/usr/local/'
]# tar xf apache-tomcat-8.5.42.tar.gz -C /usr/local/
]# cd /usr/local/
#项目路径配置
]# mkdir -pv /data/webapps/ROOT
#测试jsp文件
]# cp ~/index.jsp /data/webapps/ROOT/
#软链接
]# ln -sv apache-tomcat-8.5.42 tomcat

t1

server.xml修改后模板

local]# cd tomcat/
tomcat]# vim conf/server.xml
...
      <!-- 修改 -->
    <Engine name="Catalina" defaultHost="t1.123.com">

      <!-- 添加 -->      
      <Host name="t1.123.com" appBase="/data/webapps" autoDeploy="true">
      </Host>
      <!-- 下面结尾处 -->       
    </Engine>
...

t2

local]# cd tomcat/
tomcat]# vim conf/server.xml
...
      <!-- 修改 -->
    <Engine name="Catalina" defaultHost="t2.123.com">

      <!-- 添加 -->      
      <Host name="t2.123.com" appBase="/data/webapps" autoDeploy="true">
      </Host>
      <!-- 下面结尾处 -->       
    </Engine>
...

Nginx调度

nginx.conf修改模板可参考

]# vim /etc/nginx/nginx.conf
...
    upstream tomcats{
        #ip_hash;  #先禁用看看轮询,之后再开启黏性
        server t1.123.com:8080;
        server t2.123.com:8080;
    }
#location在server中
        location / {
            #proxy_pass http://127.0.0.1:8080;
            #root /data/webapps/ROOT;
            #index index.html;    
        }
        location ~* \.(jsp|do)$ {
            #proxy_pass http://node1.123.com:8080;
            proxy_pass http://tomcats;
        }
...

#检查语法
]# nginx -t
#启动服务
]# systemctl start nginx

图片.png

出问题了.502

图片.png

t1

]# pwd
/usr/local/tomcat

]# bin/startup.sh 

图片.png

t2

也启动起来

]# pwd
/usr/local/tomcat

]# bin/startup.sh 

此时是轮询

图片.png

Nginx

在upstream中使用ip_hash指令,使用客户端lP地址Hash。这个hash值使用IP v4地址的前24位或全部的IPv6地址。

]# vim /etc/nginx/nginx.conf
...
    upstream tomcats {
        ip_hash;    <--
        server t1.123.com:8080;
        server t2.123.com:8080;
    }
...

]# systemctl reload nginx

配置完reload nginx服务。测试一下看看效果。关闭Session对应的Tomcat服务,再重启启动它,看看Session的变化。

此时不轮询

图片.png

Httpd调度

使用httpd -M可以看到proxy_balancer_module,用它来实现负载均衡。

方式依赖模块
http负载均衡mod_proxy mod_proxy_http mod_proxy_balancer
ajp负载均衡mod_proxy mod_proxy_ajp mod_proxy_balancer

Nginx

]# vim /etc/httpd/conf/httpd.conf 
...
#DocumentRoot "/var/www/html"   <--注释掉
...

t1

在tomcat的配置中Engine使用jvmRoute属性

]# pwd
/usr/local/tomcat

]# vim conf/server.xml
...
    <Engine name="Catalina" defaultHost="t1.123.com" jvmRoute="Tomcat1">
...

]# bin/shutdown.sh

t2

在tomcat的配置中Engine使用jvmRoute属性

]# pwd
/usr/local/tomcat

]# vim conf/server.xml
...
    <Engine name="Catalina" defaultHost="t2.123.com" jvmRoute="Tomcat2">
...

]# bin/shutdown.sh

Nginx

conf.d/httpd-tomcat.conf内容如下

]# vim /etc/httpd/conf.d/httpd-tomcat.conf 

<VirtualHost *:80>
    ServerName          node1.123.com
    ProxyRequests       Off
    ProxyVia            On
    ProxyPreserveHost   On
    ProxyPass          / balancer://lbtomcats/
    ProxyPassReverse   / balancer://lbtomcats/
</VirtualHost>

#loadfactor设置为1:2,便于观察。观察调度的结果是轮询的
<Proxy balancer://lbtomcats>
    BalancerMember http://t1.123.com:8080 loadfactor=1
    BalancerMember http://t2.123.com:8080 loadfactor=2
</Proxy>

]# httpd -t
]# systemctl reload httpd

t1和t2

]# bin/startup.sh

这样SessionID,就变成了这样SessionID= AD5874F130A0281F219BDDE57A58E28E.Tcomcat1

图片.png

使用session黏性

Nginx

修改conf.d/httpd-tomcat.conf

]# vim /etc/httpd/conf.d/httpd-tomcat.conf
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<VirtualHost *:80>
    ServerName          node1.123.com
    ProxyRequests       Off
    ProxyVia            On
    ProxyPreserveHost   On
    ProxyPass          / balancer://lbtomcats/
    ProxyPassReverse   / balancer://lbtomcats/
</VirtualHost>

<Proxy balancer://lbtomcats>
    BalancerMember http://t1.123.com:8080 loadfactor=1 route=Tomcat1
    BalancerMember http://t2.123.com:8080 loadfactor=2 route=Tomcat2
    ProxySet stickysession=ROUTEID
</Proxy>

]# systemctl reload httpd

发现Session不变了,一直找的同一个Tomcat服务器。

图片.png

ajp调度

Nginx

]# vim /etc/httpd/conf.d/httpd-tomcat.conf 
<VirtualHost *:80>
    ServerName          node1.123.com
    ProxyRequests       Off
    ProxyVia            On
    ProxyPreserveHost   On
    ProxyPass          / balancer://lbtomcats/
    ProxyPassReverse   / balancer://lbtomcats/
</VirtualHost>

<Proxy balancer://lbtomcats>
    BalancerMember ajp://t1.123.com:8009 loadfactor=1 route=Tomcat1
    BalancerMember ajp://t2.123.com:8009 loadfactor=2 route=Tomcat2
    #ProxySet stickysession=ROUTEID
</Proxy>

#重新加载httpd
]# systemctl reload httpd

ProxySet stickysession=ROUTEID 先禁用看看切换效果,开启后看看黏住效果。

图片.png

]# vim /etc/httpd/conf.d/httpd-tomcat.conf 
<VirtualHost *:80>
    ServerName          node1.123.com
    ProxyRequests       Off
    ProxyVia            On
    ProxyPreserveHost   On
    ProxyPass          / balancer://lbtomcats/
    ProxyPassReverse   / balancer://lbtomcats/
</VirtualHost>

<Proxy balancer://lbtomcats>
    BalancerMember ajp://t1.123.com:8009 loadfactor=1 route=Tomcat1
    BalancerMember ajp://t2.123.com:8009 loadfactor=2 route=Tomcat2
    ProxySet stickysession=ROUTEID
</Proxy>

#重新加载httpd
]# systemctl reload httpd

开启后,发现Session不变了,一直找的同一个Tomcat服务器。

图片.png

虽然,上面的做法实现客户端在一段时间内找同一台Tomcat,从而避免切换后导致的Session丢失。但是如果Tomcat节点挂掉,那么Session依旧丢失。

假设有A、B两个节点,都将Session持久化。如果Tomcat A服务下线期间用户切换到了Tomcat B上,就获得了Tomcat B的Session,就算持久化Session的Tomcat A上线了,也没用了。