基于新版的Apache-2.4.46+和Tomcat-9.0.45+配置一例新的Web应用时,使用Mod_jk进行连接时,使用与之前版本相同的配置文件,各自运行起来后,Apache的JSP文件请求触发到Mod_jk并进一步地前传给Tomcat处理时,开始报错,报错信息是connection failed to backend service之类。

大致是Apache无法通过mod_jk连接到Tomcat的服务。而单独测试Apache的运行和Tomcat的运行,比如单独请求非JSP文件,或者在Tomcat的8080端口请求相应的JSP文件,均能够正常处理相应的请求。基于此,我们判断问题就出在mod_jk上,到底哪里出错了呢?

我们在 apache/conf/extra/httpd-jk.conf 中打开相应的详细日志记录。

\# Our JK log level (trace,debug,info,warn,error)
JkLogLevel trace

输出所有步骤的过程记录。日志记录很快反馈回来,是无法连接到 ::1:8009 这个服务。

问题似乎一下子显现出来了。由于配置了IPv4和IPv6双栈网络地址,在一些服务层面对 localhost 的解析,可能是 ipv4地址:127.0.0.1 或者 ipv6地址 ::1 。可能由于某种原因,localhost 这个hostname在Apache的mod_jk中解析出是 ipv6地址,而Tomcat的程序中则解析出 ipv4地址。

相当于是mod_jk中的worker配置中: apache/conf/extra/workers.properties :

worker.balancer.balance_workers=node1
worker.node1.reference=worker.template
worker.node1.host=localhost
\#worker.node1.host=127.0.0.1
worker.node1.port=8009

这里启动后去连接 ::1:8009 服务, 而在 Tomcat中服务可能启动在 127.0.0.1:8009上,于是两边就这么因为ip地址的v4或者v6而错过了。问题若是如此,似乎也好解决:1)修改系统的hosts文件,修改消除主机名 localhost的歧义,只用在传统的127.0.0.1上,而针对 ::1 地址,另外命名为 localhost-ipv6;或者2)在Apache和Tomcat的配置文件中,不再使用主机名,都使用明确而具体的IP地址。 经过一番折腾,我们消除了 localhost的歧义,只指向 127.0.0.1, 同时在 Tomcat/conf/server.xml 中:

<Connector protocol=”AJP/1.3″

port=”8009″

address=”127.0.0.1″
redirectPort=”8443″/>

也做了具体的IPv4地址的指定,这样按预期应该是能够连通的。
果然,经过这么一番操作,mod_jk不再报错说无法连接 ::1:8009 或者 127.0.0.1:8009的错误,但依然无法进行连接! 新的错误结果依然是 connection failed to backend service…. in error state or wrong port….

与此前所不同的是,这次明确显示出了 socket connected,连接已经被创建,不再是网络层的问题。这次的错误,增加了 timeout during cping/cpong …. ,根据这些新的报错信息,继续依靠搜索引擎的帮助,挖掘相关信息。
果然,已经有同学遇到类似问题,原来是由于 新版的Tomcat默认启用了新的配置,但未能在日志信息中给出具体而明确的指示。

( -R/v2SS ) There was a change in Tomcat last year (from version 8.5.51 and version 9.0.31), which introduced a secretRequired attribute to the AJP connector with a default of true (cf. documentation). Hence you can either:

add a shared secret between the AJP connector and mod_jk

or add secretRequired="false" to the AJP connector.

直白地说,Tomcat-9.0.31+, 默认启用 secretRequired=true, 但在相应的样例配置默认设置中却没有提及。而且在错误日志中也没有提及是由于secretRequired的问题。要解决这个问题,就需要手工配置:1)增加一个共享的安全key在 AJP和mod_jk之间, 或者2)通过在AJP设置 secretRequired=false,停用这个功能。

奇怪的是这个AJP默认启用了secretRequired=true, 而 mod_jk 则是默认不启用,设置 secretRequired=false,两边自然就无法进行通信。遗憾 这样的错配,在软件层面发生了,而在错误信息里也指代不明,应该在后续予以修正。


wadelau
32 声望4 粉丝

计算技术专家.