使用Apache mod_proxy和Tomcat时出现Bad Gateway 502错误

56
我们正在Tomcat 6和Apache mod_proxy 2.2.3上运行Web应用程序。看到很多502错误,如下所示:
坏的网关!代理服务器从上游服务器收到无效响应。
代理服务器无法处理请求GET /the/page.do。
原因:从远程服务器读取错误。
如果您认为这是服务器错误,请联系网络管理员。
错误502
Tomcat有大量线程,因此它不受线程限制。我们通过JMeter向应用程序推送2400个用户。所有盒子都坐在我们防火墙内的快速未加载网络上,因此不应该有任何网络问题。
有没有人有任何建议需要查看或尝试的东西?我们接下来要使用tcpdump。
更新于10/21/08:仍然没有解决这个问题。在负载下只看到很少的这些情况。以下答案还没有提供任何神奇的答案...但愿能有所帮助。

1
我在运行应用程序时遇到了这个问题已经有一段时间了。 - Uday A. Navapara
10个回答

47

仅补充一些具体的设置,我有一个类似的设置(使用Apache 2.0.63反向代理到Tomcat 5.0.27)。

对于某些URL,Tomcat服务器可能需要大约20分钟才能返回页面。

最终我修改了Apache配置文件中以下设置,以防止它在代理操作中超时(并设置了大量溢出因素,以防Tomcat需要更长时间才能返回页面):

Timeout 5400
ProxyTimeout 5400

背景

ProxyTimeout 单独使用不够。查看 Timeout 文档,我猜测(不确定)是因为当 Apache 等待来自 Tomcat 的响应时,Apache 和浏览器(或其他 HTTP 客户端)之间没有流量 - 因此 Apache 关闭与浏览器的连接。

我发现,如果我将 Timeout 设置保留在其默认值(300 秒),那么如果代理请求到 Tomcat 需要超过 300 秒才能获得响应,则浏览器会显示一个“502 代理错误”页面。我相信这个消息是由 Apache 生成的,知道它正在充当反向代理,然后关闭与浏览器的连接(这是我目前的理解 - 可能有缺陷)。

代理错误页面上显示:

代理错误

代理服务器从上游服务器接收到无效的响应。代理服务器无法处理请求 GET。

原因:从远程服务器读取错误

... 这表明 ProxyTimeout 设置的时间太短,而进一步调查显示 Apache 的 Timeout 设置(Apache 和客户端之间的超时)也会影响此问题。


超时设置的语法是什么?TimeOut 5400或者Timeout 5400?(小写字母o与大写字母O之间的区别) - TechnoCrat
配置指令不区分大小写(但参数可能区分大小写):http://httpd.apache.org/docs/2.4/configuring.html - sherb
你好,我是一个新手,不知道在哪里以及如何设置上述属性,请详细解释一下。我应该在哪里找到这个配置文件,并在哪个配置文件中编写此属性? - Uday A. Navapara
在我的情况下,浏览器的控制台显示......502(代理错误)......我在httpd.conf文件中的<virtualHost>中添加了Timeout 5400 ProxyTimeout 5400,并且成功了!谢谢! - JRichardsz
在大多数情况下,不需要添加“ProxyTimeout”指令,因为它会将“Timeout”指令的值作为默认值。请参阅http://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxytimeout。 - themenace

15

好的,我来回答这个问题。我们最终确定负载均衡器中出现502和503错误是由于Tomcat线程超时导致的。在短期内,我们增加了超时时间。在长期内,我们修复了导致超时的应用程序问题。为什么Tomcat超时会被负载均衡器视为502和503错误仍然有点神秘。


你有没有想法,为什么负载均衡器在Tomcat超时时会抛出错误网关? - Tobias
在Janning的回答中引用的文档(https://dev59.com/I3VC5IYBdhLWcg3w1E7w#1287662)中解释说,后端WAS关闭连接和mod_proxy_http检查连接之间存在竞争条件。如果一个新客户端连接而没有设置`proxy-initial-not-pooled`,它可能会被发送到这个失效的线程。 - MattBianco

12

您可以使用proxy-initial-not-pooled。

请参阅http://httpd.apache.org/docs/2.2/mod/mod_proxy_http.html

如果设置了此变量,则在客户端连接为初始连接时,不会重用任何池化连接。这避免了由于后端服务器在代理进行连接检查并且代理发送的数据未到达后端之前关闭池化连接而导致的“proxy:error reading status line from remote server”错误消息所引起的竞争条件。必须记住,设置此变量会降低性能,特别是对于HTTP/1.0客户端。

我们也遇到了这个问题。我们通过添加以下内容来解决它:

SetEnv proxy-nokeepalive 1
SetEnv proxy-initial-not-pooled 1

并且关闭所有服务器上的keepAlive

在大多数情况下,mod_proxy_http都很好,但我们正在承受重载,并且仍然遇到一些超时问题,我们不理解。

但请查看上述指令是否符合您的需求。


这对我有用。我有不一致的保持活动设置,我通过SetEnv proxy-nokeepalive 1和SetEnv force-proxy-request-1.0 1进行了更正。 - Ben Thurley

4

Apache配置文件示例:

#Default value is 2 minutes
**Timeout 600**
ProxyRequests off
ProxyPass /app balancer://MyApp stickysession=JSESSIONID lbmethod=bytraffic nofailover=On
ProxyPassReverse /app balancer://MyApp
ProxyTimeout 600
<Proxy balancer://MyApp>
    BalancerMember http://node1:8080/ route=node1 retry=1 max=25 timeout=600
    .........
</Proxy>

4

我知道这并不能回答这个问题,但我来到这里是因为我在nodeJS服务器上遇到了同样的错误。我卡了很长时间,直到我找到了解决方案。我的解决方案只是在proxyreserve apache的结尾添加反斜杠或/

我的旧代码是:

ProxyPass / http://192.168.1.1:3001
ProxyPassReverse / http://192.168.1.1:3001

正确的代码是:

ProxyPass / http://192.168.1.1:3001/
ProxyPassReverse / http://192.168.1.1:3001/

感谢分享,帮助我解决了类似的问题。 - Joshua Achoka
对我也有效。现在让我更加困惑了,这是语法问题还是超时问题?[1]:ProxyPass / http://192.168.1.1:3001/ [1]:ProxyPassReverse / http://192.168.1.1:3001/ - yas

3
我猜你正在使用mod_proxy_http(或代理平衡器)。
请查看你的Tomcat日志(localhost.log或catalina.log),我怀疑你会看到一个异常在你的Web堆栈中冒出并关闭与Tomcat工作进程连接的套接字。

请在日志中找到任何问题并进行更新。同时,请检查Apache错误日志,以便了解是谁关闭了套接字(Apache还是Tomcat)。默认情况下,Apache代理响应的超时时间为300秒。 - Dave Cheney

3
您可以通过在ProxyPass指令中指定代理超时时间来避免全局超时或虚拟主机的问题,具体操作如下:
ProxyPass /svc http://example.com/svc timeout=600
ProxyPassReverse /svc http://example.com/svc timeout=600

注意 timeout=600 秒。

然而,当你有负载均衡器时,这并不总是起作用。在这种情况下,您必须在两个地方添加超时时间(在Apache 2.2.31中测试过)。

负载均衡器示例:

<Proxy "balancer://mycluster">
     BalancerMember "http://member1:8080/svc" timeout=600
     BalancerMember "http://member2:8080/svc" timeout=600
</Proxy> 

ProxyPass /svc "balancer://mycluster" timeout=600
ProxyPassReverse /svc "balancer://mycluster" timeout=600

一个小提示:在Chrome是客户端时,ProxyPass上的timeout=600是不需要的(我不知道为什么),但是如果没有此超时设置,Internet Explorer(11)会中止并显示“服务器重置连接”错误消息。
我的理论是: ProxyPass 超时设置用于客户端(浏览器)和Apache之间的连接。 BalancerMember 超时设置用于Apache和后端之间的连接。
对于那些使用Tomcat或其他后端服务器的用户,您可能还需要注意HTTP Connector超时设置。

2

你可以通过timeout和proxyTimeout参数设置为600秒来解决这个问题。在经过一段时间的奋斗后,这对我起了作用。


1

很可能您应该在Apache配置文件中增加Timeout参数(默认值为120秒)


0

如果您想使用Apache负载均衡器处理Web应用程序的超时问题,首先必须了解timeout的不同含义。我试图在此概括我在这里找到的讨论:http://apache-http-server.18135.x6.nabble.com/mod-proxy-When-does-a-backend-be-considered-as-failed-td5031316.html

看起来只有当与后端的传输层连接失败时,mod_proxy才会将后端视为失败。除非使用failonstatus/failontimeout。...

因此,设置failontimeout是必要的,以便Apache将Web应用程序(例如由Tomcat提供)的超时视为失败(并连续切换到热备份服务器)。对于正确的配置,请注意以下错误配置:

ProxyPass / balancer://localbalance/ failontimeout=on timeout=10 failonstatus=50

这是一种错误的配置,因为:

您在此处定义了一个balancer,因此timeout参数与balancer(如另外两个)相关联。 但是对于balancertimeout参数不是连接超时(例如与BalancerMember一起使用的超时),而是等待空闲工作程序/成员的最长时间(例如当所有工作程序都忙或处于错误状态时,默认情况下不等待)。

因此,正确的配置方式如下:

  1. BalanceMember级别设置timeout
 <Proxy balancer://mycluster>
     BalancerMember http://member1:8080/svc timeout=6 
 ... more BalanceMembers here
</Proxy>
  1. 在负载均衡器上设置failontimeout
ProxyPass /svc balancer://mycluster failontimeout=on

重启Apache。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接