企业级web应用服务器--Tomcat(四)
一、结合反向代理实现tomcat部署
1、常见部署方式介绍
standalone模式,Tomcat单独运行,直接接受用户的请求,不推荐。
反向代理,单机运行,提供了一个Nginx作为反向代理,可以做到静态由nginx提供响应,动态jsp代理给Tomcat
LNMT:Linux + Nginx + MySQL + Tomcat
LAMT:Linux + Apache(Httpd)+ MySQL + Tomcat
前置一台Nginx,给多台Tomcat实例做反向代理和负载均衡调度,Tomcat上部署的纯动态页面更适合
LNMT:Linux + Nginx + MySQL + Tomcat
多级代理
LNNMT:Linux + Nginx + Nginx + MySQL + Tomcat
2、利用 nginx 反向代理实现全部转发置指定同一个虚拟主机
1)利用nginx指令proxy_pass 可以向后端服务器转发请求报文,并且在转发时会保留客户端的请求报文中的host首部
#从yum源安装nginx
#yum install nginx -y
#vim /etc/nginx/nginx.conf
#全部反向代理测试
location / {
# proxy_pass http://127.0.0.1:8080; # 不管什么请求,都会访问后面的localhost虚拟主机
proxy_pass http://node1.magedu.com:8080; # 此项将用户访问全部请求转发到node1的虚拟主机上
#proxy_pass http://node2.magedu.com:8080; #此项将用户访问全部请求转发到node2的虚拟主机上
#以上两项都需要修改nginx服务器的/etc/hosts,实现node1.magedu.com和node2.magedu.com到IP的解析
}
#nginx -t
#systemctl restart nginx
#说明: proxy_pass http://FQDN/ 中的FQDN 决定转发至后端哪个虚拟主机,而与用户请求的URL无关
#如果转到后端的哪个服务器由用户请求决定,可以向后端服务转发请求的主机头实现,示例:
proxy_set_header Host $http_host;
2)案例
环境说明:
一台主机,实现nginx和tomcat
tomcat上有两个虚拟主机node1和node2
#在同一下主机上建立两个tomcat虚拟主机,node1.syk.top和node2.syk.top
#修改/etc/hosts文件,实现名称解析
[root@centos8 ~]#vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
centos8.localdomain
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.100 node1.syk.top node2.syk.top
#安装nginx
[root@centos8 ~]#yum -y install nginx
#修改nginx.conf配置文件
[root@centos8 ~]#vim /etc/nginx/nginx.conf
......
#修改location / 此行,添加以下内容
location / {
#proxy_pass http://127.0.0.1:8080;
proxy_pass http://node1.syk.top:8080;
}
......
[root@centos8 ~]#systemctl enable --now nginx
#先别访问node1,node2和IP都可以看到一样的node1的虚拟主机页面
[root@centos8 ~]#curl http://node1.syk.top/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jsp例子</title>
</head>
<body>
后面的内容是服务器端动态生成字符串,最后拼接在一起
node1.syk.top
</body>
</html>
[root@centos8 ~]#curl http://node2.syk.top/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jsp例子</title>
</head>
<body>
后面的内容是服务器端动态生成字符串,最后拼接在一起
node2.syk.top
</body>
</html>
[root@centos8 ~]#curl http://127.0.0.1/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jsp例子</title>
</head>
<body>
后面的内容是服务器端动态生成字符串,最后拼接在一起
node1.syk.top
</body>
</html>
[root@centos8 ~]#curl http://10.0.0.100/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jsp例子</title>
</head>
<body>
后面的内容是服务器端动态生成字符串,最后拼接在一起
node1.syk.top
</body>
</html>
[root@centos8 ~]#systemctl restart nginx
#再次修改nginx.conf配置文件
[root@centos8 ~]#vim /etc/nginx/nginx.conf
......
#修改location / 行,添加以下内容
location / {
#proxy_pass http://127.0.0.1:8080;
proxy_pass http://node2.syk.top:8080;
}
......
#先别访问node1,node2和IP都可以看到一样的node2的虚拟主机页面
[root@centos8 ~]#curl http://node1.syk.top/
[root@centos8 ~]#curl http://node2.syk.top/
[root@centos8 ~]#curl http://127.0.0.1/
[root@centos8 ~]#curl http://10.0.0.100/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jsp例子</title>
</head>
<body>
后面的内容是服务器端动态生成字符串,最后拼接在一起
node2.syk.top
</body>
</html>
3、利用nginx实现动静分离代理
1)配置说明
可以利用nginx实现动静分离代理
vim nginx.conf
root /usr/share/nginx/html;
#下面行可不加
#location / {
# root /data/webapps/ROOT;
# index index.html;
#}
# ~* 不区分大小写
location ~* \.jsp$ {
proxy_pass http://node1.magedu.com:8080; #注意: 8080后不要加/,需要nginx修改
/etc/hosts
}
以上设置,可以将jsp的请求反向代理到tomcat,而其它文件仍由nginx处理,从而实现所谓动静分离。但由于jsp文件中实际上是由静态资源和动态组成,所以无法彻底实现动静分离。实际上Tomcat不太适合做动静分离,用它来管理程序的图片不好做动静分离部署
2)案例
#准备三个不同的资源文件
[root@centos8 ~]#echo /usr/local/tomcat/webapps/ROOT/test.html >
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#echo /usr/local/tomcat/webapps/ROOT/test.jsp >
/usr/local/tomcat/webapps/ROOT/test.jsp
[root@centos8 ~]#echo /usr/share/nginx/html/test.html >
/usr/share/nginx/html/test.html
[root@centos8 ~]#vim /etc/nginx/nginx.conf
......
root /usr/share/nginx/html;
#location / {
#
#}
location ~* \.jsp$ {
proxy_pass http://127.0.0.1:8080;
}
......
[root@centos8 ~]#systemctl restart nginx
#访问test.html,观察结果都一样访问的是nginx自身的资源
[root@centos8 ~]#curl http://node1.syk.top/test.html
[root@centos8 ~]#curl http://node2.syk.top/test.html
[root@centos8 ~]#curl http://127.0.0.1/test.html
[root@centos8 ~]#curl http://10.0.0.8/test.html
/usr/share/nginx/html/test.html
#访问test.jsp,观察结果都一样访问的是tomcat的默认主机资源
[root@centos8 ~]#curl http://node1.syk.top/test.jsp
[root@centos8 ~]#curl http://node2.syk.top/test.jsp
[root@centos8 ~]#curl http://127.0.0.1/test.jsp
[root@centos8 ~]#curl http://10.0.0.8/test.jsp
/usr/local/tomcat/webapps/ROOT/test.jsp
4、利用httpd实现基于http协议的反向代理至后端Tomcat服务器
1)配置说明
httpd也提供了反向代理功能,所以可以实现对tomcat的反向代理功能
功能模块:查看代理相关模块
[root@centos8 ~]#httpd -M|grep proxy
AH00558: httpd: Could not reliably determine the server's fully qualified domain
name, using centos8.localdomain. Set the 'ServerName' directive globally to
suppress this message
proxy_module (shared)
proxy_ajp_module (shared) #ajp
proxy_balancer_module (shared)
proxy_connect_module (shared)
proxy_express_module (shared)
proxy_fcgi_module (shared)
proxy_fdpass_module (shared)
proxy_ftp_module (shared)
proxy_http_module (shared) #http
proxy_hcheck_module (shared)
proxy_scgi_module (shared)
proxy_uwsgi_module (shared)
proxy_wstunnel_module (shared)
proxy_http2_module (shared)
proxy_http_module模块代理配置
vim /etc/httpd/conf.d/http-tomcat.conf
<VirtualHost *:80>
ServerName node1.syk.top
ProxyRequests Off
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
ProxyPreserveHost On
ProxyVia On
</VirtualHost>
ProxyRequests:Off 关闭正向代理功能,即启动反向代理
ProxyPass:反向代理指令,指向后端服务器
ProxyPassReverse:当反向代理时,返回给客户端的报文需将之重写个别后端主机的response头,如:Location,Content-Location,URI
ProxyPreserveHost:On时让反向代理保留原请求的Host首部转发给后端服务器,off 时则删除host首部后再转发至后面端服务器, 这将导致只能转发到后端的默认虚拟主机
ProxyVia:On开启。反向代理的响应报文中提供一个response的via首部,默认值off
2)案例
#基于httpd实现反向代理后端的tomcat
#对不同的虚拟主机生成页面文件
[root@centos8 ~]#echo /usr/local/tomcat/webapps/ROOT/test.html >
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#echo /data/node1/ROOT/test.html > /data/node1/ROOT/test.html
[root@centos8 ~]#echo /data/node2/ROOT/test.html > /data/node2/ROOT/test.html
#提前准备好tomcat的两个虚拟主机的配置
[root@centos8 ~]#tail /usr/local/tomcat/conf/server.xml
</Host>
<Host name="node1.syk.top" appBase="/data/node1/" unpackWARs="true"
autoDeploy="true">
</Host>
<Host name="node2.syk.top" appBase="/data/node2/" unpackWARs="true"
autoDeploy="true">
</Host>
</Engine>
</Service>
</Server>
#修改httpd配置
[root@centos8 ~]#yum -y install httpd
[root@centos8 ~]#vim /etc/httpd/conf.d/tomcat.conf
[root@centos8 ~]#cat /etc/httpd/conf.d/tomcat.conf
<VirtualHost *:80>
ServerName node1.syk.top
ProxyRequests Off
ProxyVia On
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
[root@centos8 ~]#systemctl restart httpd
#用下面不同URL访问,可以看不同结果
[root@centos8 ~]#curl http://node1.syk.top/test.html
/data/node1/ROOT/test.html
[root@centos8 ~]#curl http://node2.syk.top/test.html
/data/node2/ROOT/test.html
[root@centos8 ~]#curl http://127.0.0.1/test.html
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#curl http://10.0.0.8/test.html
/usr/local/tomcat/webapps/ROOT/test.html
#修改配置
[root@centos8 ~]#vim /etc/httpd/conf.d/tomcat.conf
#只修改下面一行
ProxyPreserveHost Off
[root@centos8 ~]#systemctl restart httpd
#再次用用下面不同URL访问,可以看相同结果
[root@centos8 ~]#curl http://node1.syk.top/test.html
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#curl http://node2.syk.top/test.html
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#curl http://10.0.0.8/test.html
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#curl http://127.0.0.1/test.html
/usr/local/tomcat/webapps/ROOT/test.html
5、利用 httpd 实现基于AJP协议的反向代理至后端Tomcat服务器
AJP(Apache JServ Protocol)是定向包协议,是一个二进制的TCP传输协议,相比HTTP这种纯文本的协议来说,效率和性能更高,也做了很多优化。但是浏览器并不能直接支持AJP13协议,只支持HTTP协议。所以实际情况是,通过Apache的proxy_ajp模块进行反向代理,暴露成http协议给客户端访问。
1)启用和禁用 AJP
注意: Tomcat/8.5.51之后版本基于安全需求默认禁用AJP协议
案例: Tomcat/8.5.51之后版启用支持AJP协议
[root@centos8 tomcat]#vim conf/server.xml
#取消前面的注释,并修改下面行,修改address和secretRequired
<Connector protocol="AJP/1.3" address="0.0.0.0" port="8009"
redirectPort="8443" secretRequired="" />
[root@centos8 tomcat]#systemctl restart tomcat
[root@centos8 tomcat]#ss -ntl
State Recv-Q Send-Q Local Address:Port
Peer Address:Port
LISTEN 0 128 0.0.0.0:22
0.0.0.0:*
LISTEN 0 100 127.0.0.1:25
0.0.0.0:*
LISTEN 0 128 [::]:22
[::]:*
LISTEN 0 100 [::1]:25
[::]:*
LISTEN 0 1 [::ffff:127.0.0.1]:8005
*:*
LISTEN 0 100 [::ffff:127.0.0.1]:8009
*:*
LISTEN 0 100 *:8080
*:*
LISTEN 0 128 *:80
*:*
注意: secretRequired="" 必须加上,否则出现以下错误提示
[root@centos8 tomcat]#cat logs/catalina.log
Caused by: java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "". This combination is not valid.
除httpd外,其它支持AJP代理的服务器非常少,比如Nginx就不支持AJP,所以目前一般都禁用AJP协议端口
案例:禁用AJP协议
#Tomcat/8.5.50版本之前默认支持AJP协议
[root@centos8 ~]#ss -ntl
State Recv-Q Send-Q Local Address:Port
Peer Address:Port
LISTEN 0 128 0.0.0.0:22
0.0.0.0:*
LISTEN 0 100 *:8080
*:*
LISTEN 0 128 *:80
*:*
LISTEN 0 128 [::]:22
[::]:*
LISTEN 0 1 [::ffff:127.0.0.1]:8005
*:*
LISTEN 0 100 *:8009
*:*
#配置tomcat配置文件,删除下面一行
[root@centos8 ~]#vim /usr/local/tomcat/conf/server.xml
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
[root@centos8 ~]#systemctl restart tomcat
[root@centos8 ~]#ss -ntl
State Recv-Q Send-Q Local Address:Port
Peer Address:Port
LISTEN 0 128 0.0.0.0:22
0.0.0.0:*
LISTEN 0 100 *:8080
*:*
LISTEN 0 128 *:80
*:*
LISTEN 0 128 [::]:22
[::]:*
LISTEN 0 1 [::ffff:127.0.0.1]:8005
*:*
2)httpd 实现 AJP 反向代理
相对来讲,AJP协议基于二进制比使用HTTP协议的连接器效率高些。
proxy_ajp_module模块代理配置
<VirtualHost *:80>
ServerName node1.syk.top
ProxyRequests Off
ProxyVia On
ProxyPreserveHost On
ProxyPass / ajp://127.0.0.1:8009/
</VirtualHost>
查看Server Status可以看到确实使用的是ajp连接了。
案例 :启用httpd的AJP反向代理功能
[root@centos8 ~]#vim /etc/httpd/conf.d/tomcat.conf
[root@centos8 ~]#cat /etc/httpd/conf.d/tomcat.conf
<VirtualHost *:80>
ServerName node1.syk.top
ProxyRequests Off
ProxyVia On #此项对AJP无效
ProxyPreserveHost On #此项对AJP无效
ProxyPass / ajp://127.0.0.1:8009/
</VirtualHost>
[root@centos8 ~]#systemctl restart httpd
#再次用用下面不同URL访问,可以看以下结果
[root@centos8 ~]#curl http://node1.syk.top/test.html
/data/node1/ROOT/test.html
[root@centos8 ~]#curl http://node2.syk.top/test.html
/data/node2/ROOT/test.html
[root@centos8 ~]#curl http://10.0.0.8/test.html
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#curl http://127.0.0.1/test.html
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#vim /etc/httpd/conf.d/tomcat.conf
#只修改下面一行,关闭向后端转发请求的host首部
ProxyPreserveHost Off
#再次用用下面不同URL访问,可以看到和上面一样的结果,说明AJP协议和Http不同,自动转发所有首部信
息
[root@centos8 ~]#curl http://node1.syk.top/test.html
/data/node1/ROOT/test.html
[root@centos8 ~]#curl http://node2.syk.top/test.html
/data/node2/ROOT/test.html
[root@centos8 ~]#curl http://10.0.0.8/test.html
/usr/local/tomcat/webapps/ROOT/test.html
[root@centos8 ~]#curl http://127.0.0.1/test.html
/usr/local/tomcat/webapps/ROOT/test.html
#可以通过status页面看到下面AJP的信息
#用iptables禁用AJP的访问
[root@centos8 ~]#iptables -A INPUT -p tcp --dport 8009 -j REJECT
[root@centos8 ~]#curl http://node1.syk.top/test.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>503 Service Unavailable</title>
</head><body>
<h1>Service Unavailable</h1>
<p>The server is temporarily unable to service your
request due to maintenance downtime or capacity
problems. Please try again later.</p>
</body></html>
6、实现 tomcat 负载均衡
动态服务器的问题,往往就是并发能力太弱,往往需要多台动态服务器一起提供服务。如何把并发的压力分摊,这就需要调度,采用一定的调度策略,将请求分发给不同的服务器,这就是Load Balance负载均衡。当单机Tomcat,演化出多机多级部署的时候,一个问题便凸显出来,这就是Session。而这个问题的由来,都是由于HTTP协议在设计之初没有想到未来的发展。
1)HTTP的无状态,有连接和短连接
无状态:指的是服务器端无法知道2次请求之间的联系,即使是前后2次请求来自同一个浏览器,也没有任何数据能够判断出是同一个浏览器的请求。后来可以通过cookie、session机制来判断。
浏览器端第一次HTTP请求服务器端时,在服务器端使用session这种技术,就可以在服务器端产生一个随机值即SessionID发给浏览器端,浏览器端收到后会保持这个SessionID在Cookie当中,这个Cookie值一般不能持久存储,浏览器关闭就消失。浏览器在每一次提交HTTP请求的时候会把这个SessionID传给服务器端,服务器端就可以通过比对知道是谁了;Session通常会保存在服务器端内存中,如果没有持久化,则易丢失;Session会定时过期。过期后浏览器如果再访问,服务端发现没有此ID,将给浏览器端重新发新的SessionID;更换浏览器也将重新获得新的SessionID
有连接:是因为它基于TCP协议,是面向连接的,需要3次握手、4次断开。
短连接:Http 1.1之前,都是一个请求一个连接,而Tcp的连接创建销毁成本高,对服务器有很大的影响。所以,自Http 1.1开始,支持keep-alive,默认也开启,一个连接打开后,会保持一段时
间(可设置),浏览器再访问该服务器就使用这个Tcp连接,减轻了服务器压力,提高了效率。
服务器端如果故障,即使Session被持久化了,但是服务没有恢复前都不能使用这些SessionID。如果使用HAProxy或者Nginx等做负载均衡器,调度到了不同的Tomcat上,那么也会出现找不到SessionID的情况。
2)会话保持方式
(1)session sticky会话黏性
nginx:source ip, cookie
HAProxy:source ip, cookie
优点:简单易配置
缺点:如果目标服务器故障后,如果没有做sessoin持久化,就会丢失session,此方式生产很少使用
(2)Session 复制集群
Tomcat自己的提供的多播集群,通过多播将任何一台的session同步到其它节点。
缺点:Tomcat的同步节点不宜过多,互相即时通信同步session需要太多带宽;每一台都拥有全部session,内存损耗太多。
(3)Session Server
session 共享服务器,使用memcached、redis做共享的Session服务器,此为推荐方式。
3)负载均衡规划和准备
#只需在10.0.0.100的nginx主机上实现域名解析
vim /etc/hosts
#添加以下三行
10.0.0.100 proxy.syk.top proxy
10.0.0.101 t1.syk.top t1
10.0.0.102 t2.syk.top t2
(1)负载均衡tomcat主机准备
修改tomcat的虚拟机主机为自定义的主机名,并设为默认的虚拟主机
t1虚拟主机配置conf/server.xml
<Engine name="Catalina" defaultHost="t1.syk.top">
<Host name="t1.syk.top" appBase="/data/webapps" autoDeploy="true" >
</Host>
</Engine>
t2虚拟主机配置conf/server.xm
<Engine name="Catalina" defaultHost="t2.syk.top">
<Host name="t2.syk.top" appBase="/data/webapps" autoDeploy="true" >
</Host>
</Engine>
(2)准备负载均衡规划测试用的jsp文件
#在t1和 t2节点创建相同的文件/data/webapps/ROOT/index.jsp
#项目路径配置
mkdir -pv /data/webapps/ROOT
#编写测试jsp文件,内容在下面
vim /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tomcat test</title>
</head>
<body>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>
#设置权限
chown -R tomcat.tomcat /data/webapps/
4)Nginx 实现后端 tomcat 的负载均衡调度
(1)Nginx 实现后端 tomcat 的负载均衡
nginx 配置如下 :
vim /etc/nginx/nginx.conf
#在http块中加以下内容
#注意名称不要用下划线
upstream tomcat-server {
#ip_hash; # 先禁用看看轮询,之后开启开黏性
#hash $cookie_JSESSIONID; # 先禁用看看轮询,之后开启开黏性
server t1.syk.top:8080;
server t2.syk.top:8080;
}
server {
location ~* \.(jsp|do)$ {
proxy_pass http://tomcat-server;
}
}
测试 http://proxy.magedu.com/index.jsp,可以看到轮询调度效果,每次刷新后端主机和SessionID都会变化
[root@proxy ~]#curl http://proxy.syk.top/index.jsp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tomcat test</title>
</head>
<body>
<h1> tomcat website </h1>
<div>On tomcat-server</div>
<div>10.0.0.101:8080</div>
<div>SessionID = <span
style="color:blue">2E4BFA5135497EA3628F1EBDAE62493E</span></div>
Thu Jul 09 17:58:06 CST 2020
</body>
</html>
[root@proxy ~]#curl http://proxy.syk.top/index.jsp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tomcat test</title>
</head>
<body>
<h1> tomcat website </h1>
<div>On tomcat-server</div>
<div>10.0.0.102:8080</div>
<div>SessionID = <span
style="color:blue">C5CC437BC05EE5A8620822CB07E71B7C</span></div>
Thu Jul 09 17:58:07 CST 2020
</body>
</html>
(2)实现 session 黏性
在upstream中使用ip_hash指令,使用客户端IP地址Hash。
[root@proxy ~]#vim /etc/nginx/nginx.conf
#只添加ip_hash;这一行
upstream tomcat-server {
ip_hash; #启动源地址hash
#hash $cookie_JSESSIONID #启动基于cookie的hash
server t1.syk.top:8080;
server t2.syk.top:8080;
}
配置完reload nginx服务。curl 测试一下看看效果。
#用curl访问每次都调度到10.0.0.102主机上,但因为curl每次请求不会自动携带之前获取的cookie,所
有SessionID每次都在变化
[root@proxy ~]#curl http://proxy.syk.top/index.jsp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tomcat test</title>
</head>
<body>
<h1> tomcat website </h1>
<div>On tomcat-server</div>
<div>10.0.0.102:8080</div>
<div>SessionID = <span
style="color:blue">C471641C26865B08B2FDA970BE7C71A6</span></div>
Thu Jul 09 18:02:48 CST 2020
</body>
</html>
[root@proxy ~]#curl http://proxy.syk.top/index.jsp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tomcat test</title>
</head>
<body>
<h1> tomcat website </h1>
<div>On tomcat-server</div>
<div>10.0.0.102:8080</div>
<div>SessionID = <span
style="color:blue">3F61232DFD791A94D60D0D2E9561309A</span></div>
Thu Jul 09 18:02:52 CST 2020
</body>
</html>
#通过图形浏览器看到主机不变,sessionID不变
关闭Session对应的Tomcat服务,再重启启动它,看看Session的变化。
[root@t2 ~]#systemctl restart tomcat
通过浏览器看到主机不变,但sessionID和上一次变化,但后续刷新不再变化
5)Httpd 实现后端tomcat的负载均衡调度
(1)和nginx一样, httpd 也支持负载均衡调度功能
httpd 的负载均衡配置说明 :使用 httpd -M 可以看到 proxy_balancer_module,用它来实现负载均衡。
负载均衡配置说明
#配置代理到balancer
ProxyPass [path] !|url [key=value [key=value ...]]
#Balancer成员
BalancerMember [balancerurl] url [key=value [key=value ...]]
#设置Balancer或参数
ProxySet url key=value [key=value ...]
ProxyPass 和 BalancerMember 指令参数
Balancer 参数
ProxySet指令也可以使用上面的参数。
(2)启用 httpd 的负载均衡
在 tomcat 的配置中Engine使用jvmRoute属性,通过此项可得知SessionID是在哪个tomcat生成
#t1的conf/server.xml配置如下:
<Engine name="Catalina" defaultHost="t1.syk.top" jvmRoute="Tomcat1">
<Host name="t1.syk.top" appBase="/data/webapps" autoDeploy="true">
</Host>
#t2的conf/server.xml配置如下:
<Engine name="Catalina" defaultHost="t2.syk.top" jvmRoute="Tomcat2">
<Host name="t2.syk.top" appBase="/data/webapps" autoDeploy="true">
</Host>
这样设置后 SessionID 就变成了以下形式:SessionID = 9C949FA4AFCBE9337F5F0669548BD4DF.Tomcat1
httpd配置如下 :
[root@proxy ~]#vim /etc/httpd/conf.d/tomcat.conf
[root@proxy ~]#cat /etc/httpd/conf.d/tomcat.conf
<Proxy balancer://tomcat-server>
BalancerMember http://t1.syk.top:8080 loadfactor=1
BalancerMember http://t2.syk.top:8080 loadfactor=2
</Proxy>
<VirtualHost *:80>
ServerName proxy.syk.top
ProxyRequests Off
ProxyVia On
ProxyPreserveHost On #off时不向后端转发原请求host首部,而转发采用BalancerMember指
向名称为首部
ProxyPass / balancer://tomcat-server/
ProxyPassReverse / balancer://tomcat-server/
</VirtualHost>
#开启httpd负载均衡的状态页
<Location /balancer-manager>
SetHandler balancer-manager
ProxyPass !
Require all granted
</Location>
#loadfactor设置为1:2,便于观察。观察调度的结果是轮询的。
#查看状态页
(3)实现 session 黏性
官方文档:http://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html
案例:
[root@proxy ~]#vim /etc/httpd/conf.d/tomcat.conf
#添加此行,在cookie 添加 ROUTEID的定义
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/"
env=BALANCER_ROUTE_CHANGED
<Proxy balancer://tomcat-server>
BalancerMember http://t1.syk.top:8080 loadfactor=1 route=T1 #修改行,指定后
端服务器对应的ROUTEID
BalancerMember http://t2.syk.top:8080 loadfactor=1 route=T2 #修改行
ProxySet stickysession=ROUTEID #添加此行,指定用cookie中的ROUTEID值做为调度条件
</Proxy>
<VirtualHost *:80>
ServerName proxy.syk.top
ProxyRequests Off
ProxyVia On
ProxyPreserveHost On
ProxyPass / balancer://tomcat-server/
ProxyPassReverse / balancer://tomcat-server/
</VirtualHost>
#开启httpd负载均衡的状态页
<Location /balancer-manager>
SetHandler balancer-manager
ProxyPass !
Require all granted
</Location>
用浏览器访问发现Session不变了,一直找的同一个Tomcat服务器
#观察结果
[root@proxy ~]#curl http://proxy.syk.top/index.jsp #轮询
[root@proxy ~]#curl -b "ROUTEID=.T1" http://proxy.syk.top/index.jsp #固定调度到t1
[root@proxy ~]#curl -b "ROUTEID=.T2" http://proxy.syk.top/index.jsp
[root@centos7 ~]#curl http://proxy.syk.top/index.jsp -I HTTP/1.1 200
Date: Wed, 15 Jul 2020 00:55:05 GMT
Server: Apache/2.4.37 (centos)
Content-Type: text/html;charset=ISO-8859-1
Transfer-Encoding: chunked
Set-Cookie: JSESSIONID=214D58236E1BD3095814B86A65C46C8A.Tomcat1; Path=/;
HttpOnly
Via: 1.1 proxy.syk.top
Set-Cookie: ROUTEID=.T1; path=/
[root@centos7 ~]#curl -b "JSESSIONID=214D58236E1BD3095814B86A65C46C8A.Tomcat1;ROUTEID=.T1" http://proxy.syk.top/index.jsp
关闭tomcat2的tomcat服务,再查看,转向另一台tomcat服务器
[root@t2 ~]#systemctl stop tomcat
重新启动 tomcat2 的tomcat服务,再查看保持不变
[root@t2 ~]#systemctl start tomcat
查看状态页
案例:
[root@client ~]#curl -I www.magedu.org
HTTP/1.1 200
Date: Sun, 10 Jan 2021 09:58:49 GMT
Server: Apache/2.4.37 (centos)
Content-Type: text/html;charset=ISO-8859-1
Transfer-Encoding: chunked
Set-Cookie: JSESSIONID=9E1A624ABD2A0ABBD256EFB14B12D555.Tomcat2; Path=/;
HttpOnly
Via: 1.1 proxy.magedu.org
Set-Cookie: ROUTEID=.T2; path=/
[root@client ~]#curl -b "ROUTEID=.T1" www.magedu.org
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tomcat test</title>
</head>
<body>
<h1>t1.magedu.org</h1>
<div>On www.magedu.org</div>
<div>10.0.0.101:8080</div>
<div>SessionID = <span
style="color:blue">A13BFA537739734CFDC12D59EA56710A.Tomcat1</span></div>
Sun Jan 10 18:01:33 CST 2021
</body>
</html>
(4)实现 AJP 协议的负载均衡
在上面基础上修改httpd的配置文件
#在t1和t2的tomcat-8.5.51以上版本的需启用AJP
[root@centos8 tomcat]#vim conf/server.xml
#取消前面的注释,并修改下面行
<Connector protocol="AJP/1.3" address="0.0.0.0" port="8009"
redirectPort="8443" secretRequired="" />
[root@proxy ~]#cat /etc/httpd/conf.d/tomcat.conf
#Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/"
env=BALANCER_ROUTE_CHANGED #注释此行
<Proxy balancer://tomcat-server>
BalancerMember ajp://t1.magedu.org:8009 loadfactor=1 route=T1 #修改此行
BalancerMember ajp://t2.magedu.org:8009 loadfactor=1 route=T2 #修改此行
#ProxySet stickysession=ROUTEID #先注释此行
</Proxy>
<VirtualHost *:80>
ServerName proxy.magedu.org
ProxyRequests Off
ProxyVia On
ProxyPreserveHost On
ProxyPass / balancer://tomcat-server/
ProxyPassReverse / balancer://tomcat-server/
</VirtualHost>
<Location /balancer-manager>
SetHandler balancer-manager
ProxyPass !
Require all granted
</Location>
#ProxySet stickysession=ROUTEID先禁用,可以看到不断轮询的切换效果
#开启ProxySet后,发现Session不变了,一直找的同一个Tomcat服务器。
[root@proxy ~]#vim /etc/httpd/conf.d/tomcat.conf
<Proxy balancer://tomcat-server>
BalancerMember ajp://t1.magedu.org:8009 loadfactor=1 route=T1
BalancerMember ajp://t2.magedu.org:8009 loadfactor=2 route=T2
ProxySet stickysession=ROUTEID #取消此行注释,只修改此行
</Proxy>
[root@proxy ~]#systemctl restart httpd
#多次刷新页面,不再变化
虽然,上面的做法实现客户端在一段时间内找同一台Tomcat,从而避免切换后导致的Session丢失。但是如果Tomcat节点挂掉,那么Session依旧丢失。
[root@t1 ~]#systemctl stop tomcat
再恢复t1,观察到仍不会变化
[root@t1 ~]#systemctl start tomcat
结论:
假设有A、B两个节点,都将Session持久化。如果Tomcat A节点下线期间用户切换到了Tomcat B上,就获得了Tomcat B的Session,原有Sesssion将丢失,就算将持久化Session的Tomcat A节点再次上线了,也没用了。因此需要实现Session的高可用性来解决上述问题。