第 8-2 章 Linux Tomcat 服务实践

作者: Brinnatt 分类: ARM64 Linux 进阶架构 发布时间: 2022-01-21 14:50

tomcat 一般只提供动态资源处理功能,而静态资源的请求则交给独立的 apache/httpd 或 nginx 来处理。但 tomcat 与外界通信的唯一组件是连接器 Connector,因此动态请求要转发给 tomcat 时,需要和 Connector 通信。Connector 与外界通信的协议有两种:http/ajp。

8.1、Tomcat 连接器协议类型

tomcat 的 Connector 组件支持两种协议类型的连接:http、ajp。

其中 http 又分为 http/1.1 和 http/2,但因为 Servlet 的阻塞特性,使得每个 http/2 的请求都需要单独的容器线程负责处理,因此目前使用 http/2 的性能还很差。而 AJP 又有 ajp12、ajp13 和 ajp14,其中 ajp12 的功能太简陋,ajp14 又处于试验期,因此目前都适用 ajp13,或者称为 ajp 1.3。

基于 IO 模型,Connector 又分为 NIO/NIO2/APR 三种类型。

设置连接器协议的方式如下:

<!--  定义使用Http协议的连接器,其中"HTTP/1.1"表示自动选择NIO/NIO2/APR  -->
<connector port="8080" protocol="HTTP/1.1">
<connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol">
<connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol">
<connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol">

<!--  定义使用AJP协议的连接器,其中"AJP/1.3"表示自动选择NIO/NIO2/APR  -->
<Connector port="8009" protocol="AJP/1.3"/>
<Connector port="8009" protocol="org.apache.coyote.ajp.AjpNioProtocol"/>
<Connector port="8009" protocol="org.apache.coyote.ajp.AjpNio2Protocol"/>
<Connector port="8009" protocol="org.apache.coyote.ajp.AjpAprProtocol"/>

8.2、Tomcat 与 httpd/nginx 结合的方式

Tomcat 连接器与外界通信的两种协议中,ajp 只能和 apache 基金会开发的部分项目通信,例如 httpd。要与非 apache 基金会开发的程序通信,必须使用 http 协议。因此,tomcat+nginx 时,tomcat 连接器的协议类型只能是 http。

对于 tomcat+httpd,tomcat 端的连接器既可以使用 http,也可以使用 ajp 协议。但在 httpd 端,也支持多种通信模块,最常用的是 mod_proxy 和 mod_jk。

tomcat+httpd 时,几个需要注意的点:

  1. mod_jk 一般只和 tomcat 的 ajp 协议配合来通信。而 mod_proxy 则不要求 tomcat 端的协议类型是 http 还是 ajp。
  2. 配置时,使用 mod_jk 比使用 mod_proxy 要复杂的多。
  3. 使用 mod_jk 可以配置成只处理动态请求,而不处理静态请求。但 mod_proxy 则只能将所有请求都转发给 tomcat。因此,在性能上 mod_jk 比 mod_proxy 好一些。不过由于前端可以使用反向代理工具,因此这种情况下的 mod_jk 和 mod_proxy,性能无差别。
  4. 因此,如果满足业务需求,建议使用 mod_proxy,它配置起来比 mod_jk 要简便的多,且可定制的功能更多。

下图是 httpd/nginx+tomcat 在动静分离时通常使用的架构模型:

tomcat serving mode

左边的模型中,nginx/httpd 需要处理静态请求,并将动态请求转发给 tomcat,同时实现负载均衡。

右边的模型中,添加一层反向代理层,无论是静态请求还是动态请求都负载到各自的服务器组。

后文的实验都采用左边的架构模型来完成。

8.3、Tomcat + nginx

测试环境:

角色(主机名) IP 地址 操作系统
nginx(静态+反代) 192.168.122.45 CentOS Linux release 7.9.2009 (AltArch)
tomcat A 192.168.122.48 CentOS Linux release 7.9.2009 (AltArch)
tomcat B 192.168.122.49 CentOS Linux release 7.9.2009 (AltArch)

nginx 主机配置如下:可以先将 /etc/nginx/nginx.conf 里面的 server 指令都删除掉,避免影响实验。

[root@nginx ~]# cat /etc/nginx/conf.d/tomcat.conf 
upstream TomcatServers {
    server 192.168.122.48:8080 weight=1 max_fails=2 fail_timeout=2;
    server 192.168.122.49:8080 weight=2 max_fails=2 fail_timeout=2;
}

server {
    listen       80;
    server_name  default;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    location ~* \.(jsp|jspx|do)$ {
        proxy_pass http://TomcatServers;
    }

    error_page 404 /404.html;
    location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }
}
[root@nginx ~]# systemctl start nginx

tomcat A 和 tomcat B 配置参见 安装 tomcat

启动 nginx 和 tomcat A、tomcat B。然后在浏览器中分别访问静态资源和动态资源。

http://192.168.122.45
http://192.168.122.45/index.jsp

其中第二个访问的是动态资源,页面结果如下:

nginx to tomcat

发现这个欢迎页面缺失了很多内容。其实这些缺失的内容都是定义在 index.jsp 中的静态资源,例如某些图片。

  • 之所以会缺失,是因为客户端发送请求给 nginx 后,nginx 将请求转发给 tomcat,tomcat 翻译 index.jsp 为 java 源文件,然后执行该 servlet。
  • 执行 servlet 时,将所需响应数据都回应给 nginx,包括 index.jsp 中定义的图片链接标签。
    • 当客户端收到这一次的响应数据后,还会继续去请求图片,但是这是静态请求,nginx 会自己处理而不会转发给 tomcat,但 nginx 本身不知道图片在何处(tomcat 才知道)。
    • 因此对于图片部分,nginx 将返回 404 错误,使得客户端显示的页面缺失了一部分。
  • 在生产环境下,不需要担心这样的二次静态请求缺失问题,因为会将图片等静态数据存放在某个位置,并配置好 nginx 如何找到这些静态数据。
    • 例如,上面的页面中缺失了 tomcat.{png,css,gif} 等静态文件,将它们从 tomcat 服务器的 $CATALINA_HOME/webapps/ROOT/ 目录下拷贝到 nginx 服务器的 /usr/share/nginx/html 目录(上面配置文件的 root 指令指定的位置)下,并赋予读取权限。再去访问,就能正确显示图片。

8.4、Tomcat + httpd(mod_jk)

测试环境如下:

角色(主机名) IP 地址 操作系统
httpd(mod_jk)
静态+反代
192.168.122.46 CentOS Linux release 7.9.2009 (AltArch)
tomcat A 192.168.122.48 CentOS Linux release 7.9.2009 (AltArch)
tomcat B 192.168.122.49 CentOS Linux release 7.9.2009 (AltArch)

使用 mod_jk 模块和 tomcat 连接时,tomcat 的连接器一般都使用 ajp 协议类型。

mod_jk 不是 apache httpd 的原生模块,而是类似于第三方模块,因此需要额外编译 mod_jk 模块到 httpd 中,就像将 php 模块添加到 httpd 中一样。

8.4.1、编译 mod_jk 模块

当前最新稳定版的 mod_jk 是 1.2.48 版本。

mod_jk 下载地址:http://tomcat.apache.org/download-connectors.cgi

mod_jk 官方手册:http://tomcat.apache.org/connectors-doc/

httpd 要扩展模块需要借助 apxs,它是 httpd 开发包 httpd-devel 中的工具,所以先要安装 httpd-devel。如果是编译安装的 httpd,则 devel 包已经装好,如果是 yum 安装,则需要额外安装 httpd-devel 包。

此处为了方便,httpd 使用 yum 安装。所以编译 mod_jk 的方式如下:

[root@httpd ~]# yum install httpd httpd-devel
[root@httpd ~]# yum groups install "Development Tools" -y
[root@httpd ~]# tar xf tomcat-connectors-1.2.48-src.tar.gz 
[root@httpd ~]# cd tomcat-connectors-1.2.48-src/native/
[root@httpd native]# ./configure --with-apxs=/usr/bin/apxs --prefix=/usr/local/tomcat/mod_jk
[root@httpd native]# make && make install

8.4.2、配置 httpd 与 tomcat 的 ajp 连接

此处暂先配置 httpd 与其中一个 tomcat(192.168.122.48)连接。后文在说明负载均衡时再引入另一个 tomcat。

先提供一个额外的 httpd 配置文件:

[root@httpd ~]# cat /etc/httpd/conf.d/mod_jk.conf
######### "JkMount /* TomcatA" will send all request to TomcatA   ########

LoadModule          jk_module                                   modules/mod_jk.so
JkWorkersFile       /etc/httpd/conf.d/workers.properties
JkLogFile           logs/mod_jk.log
JkLogLevel          debug

JkMount             /*.jsp                                      TomcatA
JkMount             /status/*                                   statA
JkUnMount           /images/*                                   TomcatA
JkUnMount           /css/*.*                                    TomcatA
JkUnMount           /css_js/*                                   TomcatA
JkUnMount           /*.html                                     TomcatA
JkUnMount           /*.js                                       TomcatA

mod_jk 的配置文件官方手册:http://tomcat.apache.org/connectors-doc/reference/apache.html。以下是几个常用的指令说明

  • LoadModule:用于装载 mod_jk 相关模块,除此之外还需要在 httpd 的配置文件中设置其它一些指令来配置其工作属性。
  • JkWorkersFile:用于指定保存了 worker 相关工作属性定义的配置文件。
  • JkLogFile:用于指定 mod_jk 模块的日志文件。
  • JkLogLevel:用于指定日志级别(info,error,debug),此外还可以使用 JkRequestLogFormat 自定义日志信息格式。
  • JkMount:用于控制 URL 与 Tomcat workers 的对应关系。可以理解为转发请求的意思,例如 "/status/*" 表示 url 地址后加上 /status/ 可转发至 statA 这个 worker 上。
    • 注意,JkMount 匹配的 URL 是相对的。如果 JkMount 指令放在 Location 指令中,如 <Location /app>,则 JkMount 将从 /app 的后面开始匹配。

JkMount 和 JkUnMount 是很重要的指令,mod_jk 性能之所以比 mod_proxy 好,就是因为通过这两个指令可以实现动静分离,使得只将动态请求转发给 tomcat。

  • 其中 JkMount 指定要转发给 tomcat 处理的请求,JkUnMount 指定明确不转发给 tomcat 而是在本地处理的请求。

  • 虽然不指定 JkUnMount 时,也表示不转发给 tomcat,但如果有重叠时,则应该指定 JkUnMount。例如下面的例子,除了 /myapp/ 下的 js 文件,其他都转发给 tomcat1 处理。

JkMount     /myapp/*        tomcat1
JkUnMount   /myapp/*.js     tomcat1

对于 apache 来说,每一个后端 Tomcat 实例中的 engine 都可以视作一个 worker,而每一个 worker 的地址、Connector 的端口等信息都需要在 apache 端指定以便可以识别并使用这些 worker。

配置这些信息的文件通常为 "workers.properties",其具体路径是使用前面介绍过的 JkWorkersFile 指定的。在 apache 启动时,mod_jk 会扫描此文件获取每一个 worker 配置信息。如这里使用 /etc/httpd/conf.d/workers.properties

workers.properties 文件一般由两类指令组成:一是 mod_jk 可以连接的各 worker 名称列表,二是每一个 worker 的属性配置信息。详细的配置方法见官方手册:http://tomcat.apache.org/connectors-doc/reference/workers.html

下面是和上述 /etc/httpd/conf.d/mod_jk.conf 中配置相对应的 /etc/httpd/conf.d/workers.properties。

[root@httpd ~]# cat /etc/httpd/conf.d/workers.properties 
worker.list=TomcatA,statA
worker.TomcatA.type=ajp13
worker.TomcatA.host=192.168.122.48
worker.TomcatA.port=8009
worker.TomcatA.lbfactor=1
worker.statA.type = status
[root@httpd ~]#
  • 关于 worker 的配置,它们分别遵循如下使用语法:
worker.list = <a comma separated list of worker_name>
worker.<worker_name>.<property>=<property value>
  • 其中 worker.list 指令可以重复指定多次。worker_name 是 Tomcat 中 engine 组件中 jvmRoute 属性的值(jvmRoute 可以不指定,此时 worker_name 仅用于标识 worker)。

  • 根据工作机制的不同,worker 有多种不同的类型,每个 worker 都需要指定其类型,即设定 woker..type 项。常见的类型如下:其中 ajp13 是默认值。

    • ajp13:此类型是 web server 和 tomcat 首选的类型。此外,还有 ajp12 和 ajp14,但它们一个废弃一个处于测试阶段。
    • lb:lb 用于负载均衡场景中的 worker;此 worker 并不真正负责处理用户请求,而是将用户请求调度给其它类型为 ajp13 的 worker。
    • status:用户显示负载均衡中各 worker 工作状态的特殊 worker,它不处理任何请求,也不关联到任何实际工作的 tomcat 实例。
  • worker 其它常见的属性有:

    • host:worker 所在的主机,更具体的是 tomcat 上 connector 组件设置的 ajp 监听地址;
    • port:worker 的 AJP1.3 连接器监听的端口;
    • connection_pool_minsize:最少要保存在连接池中的连接的个数;默认为 pool_size/2;
    • connection_pool_timeout:连接池中连接的超时时长;
    • mount:由当前 worker 提供的 context 路径,如果有多个则使用空格格开;可考虑在 httpd 端使用 JkMount 替代。
    • retries:错误发生时的重试次数;
    • socket_timeout:mod_jk 等待 worker 响应的时长,默认为 0,即无限等待;
    • socket_keepalive:是否启用 keep alive 的功能,1 表示启用,0 表示禁用;
    • lbfactor:worker 的权重,可以在负载均衡的应用场景中为 worker 定义此属性;
  • 负载均衡模式中专用的属性还有:

    • balance_workers:用于负载均衡模式中的各 worker 的名称列表,需要注意的是,出现在此处的 worker 名称一定不能在任何 worker.list 属性列表中定义过,并且 worker.list 属性中定义的 worker 名字必须包含负载均衡 worker。
    • method:可以设定为 R、T 或 B;默认为 R,即根据请求的个数进行调度(wrr);T 表示根据已经发送给 worker 的实际流量大小进行调度;B 表示根据实际负载情况进行调度(leastconn)。
    • sticky_session:将某请求调度至某 worker 后,此地址后续所有请求都将直接调度至此 worker,实现将用户 session 与某 worker 绑定。默认为值为 true,即启用此功能。如果后端的各 worker 之间支持 session 复制,则可设为 false。

由于 status 是状态监控页面,所以应该保证其安全性,可以在 httpd 的配置文件中加入以下控制列表:

# 注意,必须加上尾随斜线,因为在mod_jk.conf中已经明确了"/status/*"
# For http 2.2
<Location /status/>
    Order deny,allow
    Deny from all
    Allow from 192.168.122.0/24
</Location>

# For http 2.4
<Location /status/>
    Require ip 192.168.122
</Location>

配置 TomcatA 这个主机,开启 AJP13 连接协议:

[root@tomcat_a ~]# grep -iE "Connector.*AJP" /usr/local/tomcat/conf/server.xml
    <Connector port="8009" address="192.168.122.48" protocol="AJP/1.3" redirectPort="8443" secretRequired="false"/>
[root@tomcat_a ~]#
  • 默认 8009 端口监听在 127.0.0.1 地址上,所以要指定 address 参数;另外 secretRequired 是个坑,Tomcat 8.5.51+ 默认是开启的,开启的原因是关于 tomcat 漏洞 CVE-2020-1938、CNVD-2020-1048。我们这里是实验环境,手动设置为 false,关于 secret 安全配置可自行查阅资料。

至此,一个基于 mod_jk 模块与后端名为 TomcatA 的 worker 通信的配置已经完成,重启 httpd 服务即可生效。

测试在浏览器中输入:

http://192.168.122.46
http://192.168.122.46/index.jsp
http://192.168.122.46/status/

已测试验证,都可以获取预知结果。

8.4.3、mod_jk 负载均衡 tomcat

使用 mod_jk 实现 tomcat 的负载均衡有一个好处,tomcat 上可以禁用 http 协议(将监听此协议的 Connector 配置删除即可),防止外界直接通过 http 请求 tomcat。

配置 apache,使其支持负载均衡,修改 /etc/httpd/conf.d/mod_jk.conf 为如下内容:

[root@httpd ~]# cat /etc/httpd/conf.d/mod_jk.conf
LoadModule  jk_module  modules/mod_jk.so
JkWorkersFile  /etc/httpd/conf.d/workers.properties
JkLogFile  logs/mod_jk.log
JkLogLevel  trace
######### "JkMount /* TomcatA" will send all request to TomcatA   ########
JkMount   /*.jsp        TomcatLB
JkMount   /status/*     statA
JkUnMount /images/*     TomcatA
JkUnMount /css/*.*      TomcatA
JkUnMount /css_js/*     TomcatA
JkUnMount /*.html       TomcatA
JkUnMount /*.js         TomcatA
[root@httpd ~]#

编辑 /etc/httpd/conf.d/workers.properties,修改为如下内容:为测试负载效果,不启用 stick_session。

[root@httpd ~]# cat /etc/httpd/conf.d/workers.properties
worker.list=TomcatLB,statA
worker.statA.type=status
worker.TomcatLB.type=lb
worker.TomcatLB.sticky_session=false
worker.TomcatLB.balance_workers=TomcatA,TomcatB
worker.TomcatA.type=ajp13
worker.TomcatA.host=192.168.122.48
worker.TomcatA.port=8009
worker.TomcatA.lbfactor=5
worker.TomcatB.type=ajp13
worker.TomcatB.host=192.168.122.49
worker.TomcatB.port=8009
worker.TomcatB.lbfactor=10
[root@httpd ~]#

在 mod_jk 负载均衡中,后端 tomcat 的 engine 组件需要添加 jvmRoute 参数,该参数会为当前 server 实例设置全局惟一标识符,因此每一个实例的 jvmRoute 的值均不能相同,且 jvmRoute 的值必须等于 balance_workers 的成员值。对于上面的配置,Engine 应该如下设置:此处还修改了 name,但这并非必须。

<!--  在tomcatA上设置  -->
[root@tomcat_a ~]# grep -iE "Connector.*AJP|engin.*jvmRoute" /usr/local/tomcat/conf/server.xml
    <Connector protocol="AJP/1.3" address="192.168.122.48" port="8009" redirectPort="8443" secretRequired="false" />
    <Engine name="Standalone" defaultHost="localhost" jvmRoute="TomcatA">
[root@tomcat_a ~]#

<!--  在tomcatB上设置  -->
[root@tomcat_b ~]# grep -iE "Connector.*AJP|engin.*jvmRoute" /usr/local/tomcat/conf/server.xml
    <Connector protocol="AJP/1.3" address="192.168.122.49" port="8009" redirectPort="8443" secretRequired="false" />
    <Engine name="Standalone" defaultHost="localhost" jvmRoute="TomcatB">
[root@tomcat_b ~]#

为了演示效果,在 TomcatA 部署一个应用程序 armAPP,并添加 index.jsp,内容如下:

[root@tomcat_a ~]# mkdir -p /usr/local/tomcat/webapps/armAPP/WEB-INF/{classes,lib}
[root@tomcat_a ~]# cat /usr/local/tomcat/webapps/armAPP/index.jsp
<%@ page language="java" %>
<html>
  <head><title>TomcatA</title></head>
  <body>
    <h1><font color="red">TomcatA </font></h1>
    <table align="centre" border="1">
      <tr>
        <td>Session ID</td>
    <% session.setAttribute("abc","abc"); %>
        <td><%= session.getId() %></td>
      </tr>
      <tr>
        <td>Created on</td>
        <td><%= session.getCreationTime() %></td>
     </tr>
    </table>
  </body>
</html>
[root@tomcat_a ~]#

在 TomcatB 同样也部署一个应用程序 armAPP,如下:

[root@tomcat_b ~]# mkdir -p /usr/local/tomcat/webapps/armAPP/WEB-INF/{classes,lib}
[root@tomcat_b ~]# cat /usr/local/tomcat/webapps/armAPP/index.jsp
<%@ page language="java" %>
<html>
  <head><title>TomcatB</title></head>
  <body>
    <h1><font color="blue">TomcatB </font></h1>
    <table align="centre" border="1">
      <tr>
        <td>Session ID</td>
    <% session.setAttribute("abc","abc"); %>
        <td><%= session.getId() %></td>
      </tr>
      <tr>
        <td>Created on</td>
        <td><%= session.getCreationTime() %></td>
     </tr>
    </table>
  </body>
</html>
[root@tomcat_b ~]#

重启 httpd、tomcatA、tomcatB 对应的服务程序。在浏览器中输入 192.168.122.46/armAPP/index.jsp 测试负载均衡是否生效。

tomcat lb

测试时,轮调两次 tomcatB 后轮调一次 tomcatA。而且可以发现每次轮询时 Session ID 每次都是变化的,因为没有开启 sticky_session,所以 session 没有进行绑定。

要绑定会话,将 worker.properties 中的 sticky_session 设置为 true 即可。

8.5、Tomcat+httpd(mod_proxy)

测试环境如下:

角色(主机名) IP 地址 操作系统
httpd(mod_proxy)
静态+反代
192.168.122.46 CentOS Linux release 7.9.2009 (AltArch)
tomcat A 192.168.122.48 CentOS Linux release 7.9.2009 (AltArch)
tomcat B 192.168.122.49 CentOS Linux release 7.9.2009 (AltArch)

当 httpd 端采用 mod_proxy 和 tomcat 连接时,可以采用 ajp 或 http 协议进行连接。

要使用 mod_proxy 与 Tomcat 连接,需要 apache 已经装载 mod_proxy、mod_proxy_http、mod_proxy_ajp 和 proxy_balancer_module(实现 Tomcat 负载均衡时用到)等模块。使用 rpm 包安装的 httpd 一般默认已经启用它们,如果是编译 httpd,则在编译选项中加上以下对应几项:

--enable-proxy --enable-proxy-http --enable-proxy-ajp --enable-proxy-balancer

如果是已经编译好的 Httpd,则可以使用 apxs 工具,向 httpd 中添加这几个新模块。参见 httpd 添加新模块

确保 proxy 相关的模块已经加载了:

[root@httpd ~]# httpd -M |grep proxy
 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_scgi_module (shared)
 proxy_wstunnel_module (shared)
[root@httpd ~]#

8.5.1、配置 httpd 代理到 tomcat

基于 ajp 连接协议和 tomcat 连接时,向 httpd 添加以下配置文件。如果要基于 http 协议连接 tomcat,将上面配置文件的 ajp 协议改为 http 协议,并修改端口即可。

[root@httpd ~]# cat /etc/httpd/conf.d/ajp.conf
<Location /status>
  SetHandler balancer-manager
  Proxypass !                   # 表示此Location的URL不进行反向代理
  Require ip 192.168.122
</Location>

ProxyVia Off
ProxyRequests Off
ProxyPreserveHost Off
  ProxyPassMatch    "^/(.*\.jsp)$"  "ajp://192.168.122.48:8009/$1"
  ProxyPassReverse  "^/(.*\.jsp)$"  "ajp://192.168.122.48:8009/$1"

<Proxy *>
  Require all granted
</Proxy>
[root@httpd ~]#
  • 关于如上 apache 配置的几个指令,解释如下。httpd 反向代理的详细内容,可参见 mod_proxy
    • ProxyVia {On|Off|Full|Block}:用于控制在 http 首部是否使用 "Via:",主要用于在多级代理中控制代理请求的流向。默认为 Off,即不启用此功能;On 表示每个请求和响应报文均添加 "Via:";Full 表示每个 "Via:" 行都会添加当前 apache 服务器的版本号信息;Block 表示每个代理请求报文中的 "Via:" 都会被移除。
    • ProxyRequests {On|Off}:是否开启 apache 正向代理的功能;如果为 apache 设置了 ProxyPass 即反向代理,则必须将 ProxyRequests 设置为 Off。
    • ProxyPreserveHost {On|Off}:如果启用此功能,代理会将用户请求报文中的 "Host:" 行发送给后端的服务器,而不再使用 ProxyPass 指定的服务器 IP 地址。如果后端一个 IP 上可能会有多个虚拟主机,则需要开启此项明确转发给哪台虚拟主机,否则就无需打开此功能。
    • ProxyPassReverse:在反向代理环境中必须使用此指令避免重定向报文绕过 proxy 服务器,属性设置为 ProxyPass 一样基本上就可以。
    • ProxyPass [path] !|[url [key=value key=value ...]]:将后端服务器某 URL 与当前服务器的某虚拟路径关联起来作为提供服务的路径,path 为当前服务器上的某虚拟路径,url 为后端服务器上某 URL 路径。使用此指令时必须将 ProxyRequests 的值设置为 Off。需要注意的是,如果 path 以 "/" 结尾,则对应的 url 也必须以 "/" 结尾,反之亦然。
    • ProxyPassMatch [regex] !|url [key=value [key=value ...]]:正则格式的 ProxyPass。

重启 httpd,输入 http://192.168.122.46/armAPP/index.jsp 测试,已验证成功。

注意:重启前将前面 mod_jk 实验的配置文件删除掉,另外,这个实验只是简单地反向代理到 TomcatA,继续看下一小节实现负载均衡。

8.5.2、mod_proxy 负载均衡 tomcat

关于httpd反向代理的负载均衡配置方式,参见 mod_proxy

继续上一小节的实验,将 /etc/httpd/conf.d/ajp.conf 修改如下:

[root@httpd ~]# cat /etc/httpd/conf.d/ajp.conf
<proxy balancer://TomcatLB>
BalancerMember ajp://192.168.122.48:8009 loadfactor=5
BalancerMember ajp://192.168.122.49:8009 loadfactor=10
</proxy>

ProxyVia Off
ProxyRequests Off
ProxyPreserveHost Off
ProxyPassMatch   "^/(.*\.jsp)$" balancer://TomcatLB/$1 
ProxyPassReverse "^/(.*\.jsp)$" balancer://TomcatLB/$1

<Proxy *>
  Require all granted
</Proxy>

<Location /status>
  SetHandler balancer-manager
  Proxypass ! 
  Require ip 192.168.122
</Location>
[root@httpd ~]#

注意:TomcatA 和 TomcatB 的配置没有动,还是 8.4.3 小节的配置。

重启 httpd 服务,并在浏览器中输入 192.168.122.46/armAPP/index.jsp 测试,测试时会轮调两次 tomcatB 再轮调一次 tomcatA。

如果要实现 session 粘滞(绑定),则修改 /etc/httpd/conf.d/ajp.conf 配置文件如下:

[root@httpd ~]# cat /etc/httpd/conf.d/ajp.conf
<proxy balancer://TomcatLB>
BalancerMember ajp://192.168.122.48:8009 loadfactor=5  route=TomcatA
BalancerMember ajp://192.168.122.49:8009 loadfactor=10 route=TomcatB
ProxySet  lbmethod=byrequests
</proxy>

ProxyVia Off
ProxyRequests Off
ProxyPreserveHost Off
ProxyPassMatch   "^/(.*\.jsp)$" balancer://TomcatLB/$1 stickysession=JSESSIONID
ProxyPassReverse "^/(.*\.jsp)$" balancer://TomcatLB/$1 stickysession=JSESSIONID

<Proxy *>
  Require all granted
</Proxy>

<Location /status>
  SetHandler balancer-manager
  Proxypass ! 
  Require ip 192.168.122
</Location>
[root@httpd ~]#

注意:TomcatA 和 TomcatB 的配置没有动,还是 8.4.3 小节的配置。

重启 httpd 服务,然后测试结果,再测试时同一客户端将总是得到同一个结果,不会出现负载均衡。

标签云