文章 78
评论 0
浏览 8357
2-结合反向代理部署tomcat

2-结合反向代理部署tomcat

2 结合反向代理实现tomcat部署

2.1 常见部署方式介绍

clipboard.png

  • 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.2 利用 nginx 反向代理实现全部转发置指定同一个虚拟主机

2.2.1 配置说明

clipboard.png

利用nginx反向代理功能,实现 4.1 图(2)的代理功能,将用户请求全部转发至指定的同一个tomcat主机

利用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.zhangzhuo.org:8080;   #此项将用户访问全部请求转发到node1的虚拟主机上
            proxy_pass http://node2.zhangzhuo.org:8080;   #此项将用户访问全部请求转发到node2的虚拟主机上
 #以上两项都需要修改nginx服务器的/etc/hosts,实现node1.magedu.com和node2.magedu.com到IP的解析 
          }   
[15:59:41 root@nginx ~]#nginx -t
[15:59:41 root@nginx ~]#systemctl enable --now nginx.service 
#说明: proxy_pass http://FQDN/ 中的FQDN 决定转发至后端哪个虚拟主机,而与用户请求的URL无关
#如果转到后端的哪个服务器由用户请求决定,可以向后端服务转发请求的主机头实现,示例:
proxy_set_header Host $http_host;

2.3 利用nginx实现动静分离代理

2.3.1 配置说明

可以利用nginx实现动静分离

[16:11:26 root@nginx ~]#vim /etc/nginx/nginx.conf
#下面行可不加
#        location / {
            #proxy_pass http://192.168.10.81:8080;
            #proxy_set_header Host $http_host:8080;
            proxy_pass http://node1.zhangzhuo.org:8080;
            #proxy_pass http://node2.zhangzhuo.org:8080;
#        }
# ~* 不区分大小写
        location ~* \.jsp$ {
        proxy_pass http://node1.zhangzhuo.org:8080;        #注意: 8080后不要加/,需要nginx修改                          
        }

以上设置,可以将jsp的请求反向代理到tomcat,而其它文件仍由nginx处理,从而实现所谓动静分离。但由于jsp文件中实际上是由静态资源和动态组成,所以无法彻底实现动静分离。实际上Tomcat不太适合做动静分离,用它来管理程序的图片不好做动静分离部署

2.4 利用httpd实现基于http协议的反向代理至后端Tomcat服务器

httpd也提供了反向代理功能,所以可以实现对tomcat的反向代理功能

范例:查看代理相关模块

[09:49:32 root@tomcat ~]#httpd -M | grep proxy
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using tomcat.zhangzhuo.org. Set the 'ServerName' directive globally to suppress this message
proxy_module (shared)
proxy_ajp_module (shared)
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)
proxy_hcheck_module (shared)
proxy_scgi_module (shared)
proxy_uwsgi_module (shared)
proxy_wstunnel_module (shared)
proxy_http2_module (shared)

proxy_http_module模块代理配置

<VirtualHost *:80>
    ServerName         node1.zhangzhuo.org
    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

说明: 关于ProxyPreserveHost

#分别访问下面不同链接
http://httpd服务IP/
http://node1.magedu.org/
http://node1.magedu.org/index.jsp
#以上3个URL看到了不同的页面,说明ProxyPreserveHost On起了作用
#设置ProxyPreserveHost Off再看效果,说明什么?

2.4.2 实战案例

#对不同的虚拟主机生成页面文件
#修改httpd配置
[09:58:32 root@tomcat ~]#vim /etc/httpd/conf.d/http-tomcat.conf
<VirtualHost *:80>
    ServerName         node1.zhangzhuo.org
    ProxyRequests      Off 
    ProxyPass        / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/
    ProxyPreserveHost On
    ProxyVia          On  
</VirtualHost>    
[09:59:55 root@tomcat ~]#systemctl enable --now httpd.service
#用下面不同URL访问,可以看不同结果
 [10:01:51 root@tomcat ~]#curl node1.zhangzhuo.org
/data/tomcat1/ROOT/index.html
[10:01:55 root@tomcat ~]#curl node2.zhangzhuo.org
/data/tomcat2/ROOT/index.html
[10:01:58 root@tomcat ~]#curl 192.168.10.83
/usr/local/tomcat/webapps/ROOT/index.html

#修改配置
[10:02:05 root@tomcat ~]#vim /etc/httpd/conf.d/http-tomcat.conf
#只修改下面一行
ProxyPreserveHost Off
[10:02:54 root@tomcat ~]#systemctl reload httpd.service
#再次用用下面不同URL访问,可以看相同结果
[10:03:18 root@tomcat ~]#curl 192.168.10.83
/usr/local/tomcat/webapps/ROOT/index.html
[10:03:34 root@tomcat ~]#curl node1.zhangzhuo.org
/usr/local/tomcat/webapps/ROOT/index.html
[10:03:39 root@tomcat ~]#curl node2.zhangzhuo.org
/usr/local/tomcat/webapps/ROOT/index.html

2.5 利用 httpd 实现基于AJP协议的反向代理至后端Tomcat服务器

clipboard.png

2.5.1 AJP 协议说明

AJP(Apache JServ Protocol)是定向包协议,是一个二进制的TCP传输协议,相比HTTP这种纯文本的协议来说,效率和性能更高,也做了很多优化。但是浏览器并不能直接支持AJP13协议,只支持HTTP协议。所以实际情况是,通过Apache的proxy_ajp模块进行反向代理,暴露成http协议给客户端访问

2.5.2 启用和禁用 AJP

注意: Tomcat/8.5.51之后版本基于安全需求默认禁用AJP协议

范例: Tomcat/8.5.51之后版启用支持AJP协议

[10:03:43 root@tomcat ~]#vim /usr/local/tomcat/conf/server.xml 
#取消前面的注释,并修改下面行,修改address和secretRequired 
   <Connector protocol="AJP/1.3" address="0.0.0.0" port="8009" redirectPort="8443" secretRequired="" />
 [10:07:02 root@tomcat ~]#systemctl restart tomcat.service 
[10:13:19 root@tomcat ~]#ss -ntl | grep 8009
LISTEN    0         100                      *:8009                   *:*

注意: 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协议
#配置tomcat配置文件,删除下面一行
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

2.5.3 httpd 实现 AJP 反向代理

2.5.3.1 配置说明

相对来讲,AJP协议基于二进制比使用HTTP协议的连接器效率高些。

proxy_ajp_module模块代理配置

<VirtualHost *:80>
    ServerName         node1.zhangzhuo.org
    ProxyRequests      Off 
    ProxyPreserveHost On
    ProxyVia          On  
    ProxyPass         / ajp://127.0.0.1:8009/                                       
</VirtualHost>

查看Server Status可以看到确实使用的是ajp连接了。
clipboard.png

2.6 实现tomcat负载均衡

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

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

2.6.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.6.2 会话保持方式

2.6.2.1 session sticky会话黏性

Session绑定

  • nginx:source ip, cookie
  • HAProxy:source ip, cookie

优点:简单易配置

缺点:如果目标服务器故障后,如果没有做sessoin持久化,就会丢失session,此方式生产很少使用

2.6.2.2 session 复制集群

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

缺点

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

2.6.2.3 session server

session 共享服务器,使用memcached、redis做共享的Session服务器,此为推荐方式

2.6.3 负载均衡规划和准备

2.6.3.1 负载均衡主机和网络地址规划

clipboard.png

clipboard.png

#只需在192.168.10.81的nginx主机上实现域名解析
vim /etc/hosts
#添加以下三行
192.168.10.81 proxy.zhangzhuo.org proxy
192.168.10.82 t1.zhangzhuo.org
192.168.10.83 t2.zhangzhuo.org

2.6.3.2 负载均衡tomcat主机准备

修改tomcat的虚拟机主机为自定义的主机名,并设为默认的虚拟主机

t1虚拟主机配置conf/server.xml

<Engine name="Catalina" defaultHost="t1.zhangzhuo.org">
<Host name="t1.zhangzhuo.org"  appBase="/data/webapps" unpackWARs="true" autoDeploy="true">

t2虚拟主机配置conf/server.xml

<Engine name="Catalina" defaultHost="t2.zhangzhuo.org">
<Host name="t2.zhangzhuo.org"  appBase="/data/webapps" unpackWARs="true" autoDeploy="true">

2.6.3.3 准备负载均衡规划测试用的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: /data/*

2.6.4 Nginx 实现后端 tomcat 的负载均衡调度

2.6.4.1 Nginx 实现后端 tomcat 的负载均衡

nginx 配置如下

yum install -y nginx

vim /etc/nginx/nginx.conf
#在http块中加以下内容
#注意名称不要用下划线
        upstream tomcat-server {                                                    
             #ip_hash
             #hash $cookie_JSESSIONID;
             server t1.zhangzhuo.org:8080;
             server t2.zhangzhuo.org:8080;
        }   
#修该server中的location
        server {
             location ~* \.(jsp|do)$ {
                  proxy_pass http://tomcat-server;
             }   
        }

测试http://proxy.magedu.com/index.jsp,可以看到轮询调度效果,每次刷新后端主机和SessionID都会变化
clipboard.png
clipboard.png

[11:02:35 root@proxy ~]#curl proxy.zhangzhuo.org/index.jsp

<!DOCTYPE html>
<html lang="en">
<head>
 ? <meta charset="UTF-8">
 ? <title>tomcat test</title>
</head>
<body>
<div>On tomcat-server</div>
<div>192.168.10.83:8080</div>
<div>SessionID = <span style="color:blue">94BF0E8A4DC91C895E49A96DC45B487E</span></div>
Thu Mar 18 11:02:36 CST 2021
</body>
</html>
[11:02:36 root@proxy ~]#curl proxy.zhangzhuo.org/index.jsp

<!DOCTYPE html>
<html lang="en">
<head>
 ? <meta charset="UTF-8">
 ? <title>tomcat test</title>
</head>
<body>
<div>On tomcat-server</div>
<div>192.168.10.82:8080</div>
<div>SessionID = <span style="color:blue">1DBAED2F3AF861F315881B3165E01035</span></div>
Thu Mar 18 11:02:39 CST 2021
</body>
</html>

2.6.4.2 实现 session 黏性

在upstream中使用ip_hash指令,使用客户端IP地址Hash

[11:05:41 root@proxy ~]#vim /etc/nginx/nginx.conf
#只添加ip_hash;这一行
upstream tomcat-server {
ip_hash;
#hash $cookie_JSESSIONID;
server t1.zhangzhuo.org:8080;
server t2.zhangzhuo.org:8080;
}

配置完reload nginx服务。curl 测试一下看看效果。

#用curl访问每次都调度到10.0.0.102主机上,但因为curl每次请求不会自动携带之前获取的cookie,所有SessionID每次都在变化
[11:09:25 root@proxy ~]#curl proxy.zhangzhuo.org

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>tomcat test</title>
</head>
<body>
<div>On tomcat-server</div>
<div>192.168.10.83:8080</div>
<div>SessionID = <span style="color:blue">0F95C31449951998BB9A83332022F40D</span></div>
Thu Mar 18 11:10:19 CST 2021
</body>
</html>
[11:10:19 root@proxy ~]#curl proxy.zhangzhuo.org

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>tomcat test</title>
</head>
<body>
<div>On tomcat-server</div>
<div>192.168.10.83:8080</div>
<div>SessionID = <span style="color:blue">B0FD485A9EA362C1FAA9A6904BFD3390</span></div>
Thu Mar 18 11:10:21 CST 2021
</body>
</html>

通过图形浏览器看到主机不变,sessionID不变
clipboard.png

关闭Session对应的Tomcat服务,再重启启动它,看看Session的变化。

通过浏览器看到主机不变,但sessionID和上一次变化,但后续刷新不再变化

2.6.5 Httpd 实现后端tomcat的负载均衡调度

和nginx一样, httpd 也支持负载均衡调度功能

2.6.5.1 httpd 的负载均衡配置说明

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

官方帮助: http://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html

负载均衡配置说明

#配置代理到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 指令参数
clipboard.png
Balancer 参数

clipboard.png

ProxySet指令也可以使用上面的参数。

2.6.5.2 启用 httpd 的负载均衡

在 tomcat 的配置中Engine使用jvmRoute属性,通过此项可得知SessionID是在哪个tomcat生成

#t1的conf/server.xml配置如下:
<Engine name="Catalina" defaultHost="t1.zhangzhuo.org" jvmRoute="tomcat1">
#t2的conf/server.xml配置如下:
<Engine name="Catalina" defaultHost="t2.zhangzhuo.org" jvmRoute="tomcat2">

这样设置后 SessionID 就变成了以下形式:

SessionID = 9C949FA4AFCBE9337F5F0669548BD4DF.Tomcat1

httpd配置如下

yum install httpd
vim /etc/httpd/conf.d/tomcat.conf
<Proxy balancer://tomcat-server>
    BalancerMember http://t1.zhangzhuo.org:8080 loadfactor=1
    BalancerMember http://t2.zhangzhuo.org:8080 loadfactor=2
</Proxy>

<VirtualHost *:80>
    ServerName    proxy.zhangzhuo.org
    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,便于观察。观察调度的结果是轮询的。

查看状态页

clipboard.png

2.6.5.3 实现 session 黏性

官方文档:http://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html

%{BALANCER_WORKER_ROUTE}e   The route of the worker chosen.

范例:

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.zhangzhuo.org:8080 loadfactor=1 route=T1  #修改行,指定后端服务器对应的ROUTEID
    BalancerMember http://t2.zhangzhuo.org:8080 loadfactor=2 route=T2  #修改行
    ProxySet stickysession=ROUTEID    #添加此行,指定用cookie中的ROUTEID值做为调度条件
</Proxy>

用浏览器访问发现Session不变了,一直找的同一个Tomcat服务器

2.6.5.4 实现 AJP 协议的负载均衡

在上面基础上修改httpd的配置文件

#在t1和t2的tomcat-8.5.51以上版本的需启用AJP
<Connector protocol="AJP/1.3" address="0.0.0.0" port="8009" redirectPort="8443" secretRequired="" />
vim /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.zhangzhuo.org:8009 loadfactor=1 route=T1 #修改此行
    BalancerMember ajp://t2.zhangzhuo.org:8009 loadfactor=1 route=T2 #修改此行
    #ProxySet stickysession=ROUTEID           #先注释此行                                       
</Proxy>

<VirtualHost *:80>
    ServerName    proxy.zhangzhuo.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服务器。

<Proxy balancer://tomcat-server>
    BalancerMember ajp://t1.zhangzhuo.org:8009 loadfactor=1 route=T1
    BalancerMember ajp://t2.zhangzhuo.org:8009 loadfactor=1 route=T2
    ProxySet stickysession=ROUTEID  #取消此行注释,只修改此行
</Proxy>
systemctl restart httpd

多次刷新页面,不再变化

结论:

假设有A、B两个节点,都将Session持久化。如果Tomcat A节点下线期间用户切换到了Tomcat B上,就获得了Tomcat B的Session,原有Sesssion将丢失,就算将持久化Session的Tomcat A节点再次上线了,也没用了。因此需要实现Session的高可用性来解决上述问题。


标题:2-结合反向代理部署tomcat
作者:Carey
地址:HTTPS://zhangzhuo.ltd/articles/2021/03/20/1616229163790.html

生而为人

取消