超时操作指南

简介

设置通信超时对于改进通信过程非常重要。它们有助于检测问题并稳定分布式系统。JK 可以使用几种不同类型的超时,它们可以单独配置。出于历史原因,所有超时默认都是禁用的。本操作指南解释了它们的用法,并提供了如何找到适当值的提示。

所有超时都可以在 workers.properties 文件中配置。有关所有 worker 配置项的完整参考,请查阅 worker 参考。本页面假设您正在使用至少 JK 1.2.16 版本。对新版本的依赖将在必要时提及。

请勿将超时设置为极端值。过小的超时可能会适得其反。

后端长时间的垃圾回收暂停与某些超时不匹配。请尝试优化您的 Java 内存和 GC 设置。

JK 超时属性

CPing/CPong

CPing/CPong 是我们使用小型测试数据包来检查后端连接状态的概念。JK 可以在建立新的后端连接后(连接模式)以及在每个请求发送到后端之前(预处理模式)直接使用此类测试数据包。从 1.2.27 版本开始,当连接长时间空闲时(间隔模式)也可以使用它。可以配置 CPing 对 CPong 响应的最大等待时间(超时)以及间隔模式下的空闲时间。

后端将以最少的处理资源非常快速地响应测试数据包。肯定的响应表明后端可达且正在积极处理请求。它不检测是否有上下文已部署并正在工作。CPing/CPong 的好处是快速检测与后端的通信问题。缺点是延迟略有增加。

worker 属性 ping_mode 可以设置为字符组合,以确定在何种情况下使用测试数据包

  • C: 连接模式,超时 ping_timeoutconnect_timeout 覆盖
  • P: 预处理模式,超时 ping_timeoutprepost_timeout 覆盖
  • I: 间隔模式,超时 ping_timeout,空闲时间 connection_ping_interval
  • A: 所有模式

多个值必须不带任何分隔符连接。我们建议使用所有 CPing 测试。如果您的应用程序对延迟非常敏感,那么您应该只使用连接和间隔模式的组合。

通过 ping_mode 激活 CPing 探测是在 1.2.27 版本中添加的。对于旧版本,只有连接模式和预处理模式存在,并且必须通过显式设置 connect_timeoutprepost_timeout 来激活。

worker 属性 ping_timeout 设置所有模式下 CPong 的默认等待超时时间(毫秒)。默认值为“10000”毫秒。只有通过 ping_mode 激活 CPing/CPong 探测时,该值才会被使用。默认值应该足够,除非您遇到非常长的 Java 垃圾回收暂停。根据您的网络延迟和稳定性,良好的自定义值通常在 5000 到 15000 毫秒之间。您可以使用 connect_timeoutprepost_timeout 覆盖用于连接和预处理模式的超时。请记住:不要使用极小的值。

worker 属性 connect_timeout 设置连接建立期间 CPong 的等待超时时间(毫秒)。如果您想覆盖通过 ping_timeout 设置的通用超时,可以使用它。要使用连接模式 CPing,您需要通过 ping_mode 启用它。由于 JK 通常使用持久连接,因此打开新连接是一个罕见事件。因此,我们建议激活连接模式。根据您的网络延迟和稳定性,良好的值通常在 5000 到 15000 毫秒之间。请记住:不要使用极小的值。

worker 属性 prepost_timeout 设置请求转发前 CPong 的等待超时时间(毫秒)。如果您想覆盖通过 ping_timeout 设置的通用超时,可以使用它。要使用预处理模式 CPing,您需要通过 ping_mode 启用它。激活此类型的 CPing/CPong 会为每个请求增加少量延迟。通常这已经足够小,并且 CPing/CPong 的好处更为重要。因此,通常我们也建议使用 prepost_timeout。根据您的网络延迟和稳定性,良好的值通常在 5000 到 10000 毫秒之间。请记住:不要使用极小的值。

直到 1.2.27 版本,ping_modeping_timeout 都不存在,要启用连接或预处理模式 CPing,您必须分别将 connect_timeoutprepost_timeout 设置为某个合理的正值。

低级 TCP 超时

某些平台允许为 TCP 套接字上的所有操作设置超时。这适用于 Linux 和 Windows,其他平台(例如 Solaris)不支持此功能。如果您的平台支持 TCP 发送和接收超时,您可以使用 worker 属性 socket_timeout 来设置它们。您不能将这两个超时设置为不同的值。

即使您的平台不支持套接字超时,JK 也会接受此属性。在这种情况下,设置该属性将不起作用。默认值为“0”,超时被禁用。您可以将该属性设置为秒值(而不是毫秒)。然后 JK 会将后端连接的发送和接收超时设置为此值。该超时是低级的,它用于套接字上的每个读写操作。

使用此属性将使 JK 更快地响应某些类型的网络问题。不幸的是,套接字超时具有负面影响,因为对于大多数平台,一旦超时触发,就没有好的方法可以从中恢复。对于 JK 来说,无法判断此超时是因为真正的网络问题而触发,还是仅仅因为它没有及时收到来自后端的响应数据包。因此请记住:不要使用极小的值。

对于连接建立的一般情况,您可以使用 socket_connect_timeout。它接受毫秒值,并且在大多数平台上都有效,即使不支持 socket_timeout。我们建议使用 socket_connect_timeout,因为在某些网络故障情况下,由于 TCP 重传,连接建立期间的故障检测可能需要几分钟。根据您的网络质量,1000 到 5000 毫秒之间的超时应该没问题。请注意,socket_timeout 以秒为单位,而 socket_connect_timeout 以毫秒为单位。

连接池和空闲超时

JK 为每个 Web 服务器进程处理后端连接池中的连接。连接以持久模式使用。在请求成功完成后,我们保持连接打开并等待转发下一个请求。连接池能够根据希望并行转发请求的线程数量进行增长。

大多数应用程序的负载根据一天中的时间或月份中的日期而变化。连接池增长的其他原因可能是后端暂时变慢,导致前端(如 Web 服务器)的拥塞增加。许多后端为它们处理的每个传入连接使用一个专用线程。因此,通常人们希望在负载减少时连接池收缩。

JK 允许池中的连接在空闲一段时间后关闭。此最大空闲时间可以通过属性 connection_pool_timeout 配置,其单位为秒。默认值为“0”,这会禁用关闭空闲连接。

我们通常建议值在 10 分钟左右,因此将 connection_pool_timeout 设置为 600(秒)。如果您使用此属性,请同时在您的 Tomcat server.xml 配置文件中的 AJP Connector 元素中,将属性 keepAliveTimeout(如果已显式设置)或 connectionTimeout 设置为类似的值。注意keepAliveTimeoutconnectionTimeout 必须以毫秒为单位。因此,如果您将 JK connection_pool_timeout 设置为 600,您应该将 Tomcat keepAliveTimeoutconnectionTimeout 设置为 600000。

JK 连接不会在超时过后立即关闭。相反,有一个每 60 秒运行一次的自动内部维护任务,检查所有连接的空闲状态。60 秒的间隔可以通过全局属性 worker.maintain 进行调整。我们不建议更改此值,因为它有很多副作用。直到 1.2.26 版本,维护任务仅在处理请求时运行。因此,如果您的 Web 服务器进程长时间未收到任何请求,则无法关闭其池中的空闲连接。从 1.2.27 版本开始,当使用带有线程 APR 的 Apache HTTP Server 2.x 或 Microsoft IIS 时,您可以配置一个独立的看门狗线程。

最大连接池大小可以通过属性 connection_pool_size 配置。我们通常不建议将此属性与 Apache HTTP Server 结合使用。对于 Apache,我们自动检测每个进程的线程数,并将最大池大小设置为此值。对于 Microsoft IIS,我们使用默认值 250(1.2.20 版本之前:10)。我们强烈建议为 IIS 调整此值,使其与单个 Web 服务器进程应能够并行发送到后端的请求数量相匹配。您应该测量在高峰时段需要多少连接而不会出现性能问题,然后根据您的增长率等添加一定的百分比。最后,您应该检查您的 Web 服务器进程是否能够使用至少与您配置的池大小相同数量的线程。

JK 属性 connection_pool_minsize 定义了当连接池缩小时保留的空闲连接数。默认情况下,这是最大池大小的一半。

防火墙连接丢弃

空闲连接的一个特殊问题来自防火墙,防火墙通常部署在 Web 服务器层和后端之间。根据其配置,如果连接空闲时间过长,防火墙将从其状态表中静默丢弃连接。

从 JK 和 Web 服务器的角度来看,对方只是不响应任何流量。由于 TCP 是一个可靠的协议,它会检测到丢失的 TCP ACK 并尝试重新发送数据包相对较长时间,通常是几分钟。因此,您应该始终在 JK 端使用 connection_pool_timeout 和 connection_pool_minsize,并在 Tomcat 端使用 keepAliveTimeoutconnectionTimeout,以防止空闲连接断开。

此外,使用布尔属性 socket_keepalive,您可以设置一个标准的套接字选项,该选项会在每个连接空闲一段时间后自动发送 TCP keepalive 数据包。默认情况下,此值为 false。如果您怀疑防火墙导致空闲连接断开,则应将其设置为 true

不幸的是,这些数据包的默认间隔和算法是平台特定的。您可能需要检查您平台上的 TCP 调优选项,了解如何控制 TCP keepalive。通常默认间隔比防火墙对空闲连接的超时时间长得多。尽管如此,我们仍建议您与防火墙管理员和平台管理员沟通,以便他们就防火墙和平台 TCP 调优的良好配置值达成一致。

如果我们的任何建议都无济于事,并且您确实存在空闲连接断开的问题,那么在使用 JK 和 Apache HTTP Server 时,您可以禁用持久连接。为此,您需要在 Apache 配置中设置 "JkOptions +DisableReuse"。这会对性能产生多大影响取决于您的网络和防火墙的具体情况。

回复超时

JK 还可以对请求回复使用超时。此超时不测量响应的完整处理时间。相反,它控制连续响应数据包之间允许的时间量。

在大多数情况下,这正是人们实际想要的。例如,考虑长时间运行的下载。您将无法设置有效的全局回复超时,因为下载可能持续数分钟。然而,大多数应用程序在开始返回响应之前处理时间有限。对于这些应用程序,您可以设置显式回复超时。与回复超时不协调的应用程序是批处理类型应用程序、数据仓库和报告应用程序,它们预计会观察到长时间的处理。

如果 JK 因回复超时触发而中止等待响应,则无法停止后端上的处理。尽管您释放了 Web 服务器中的处理资源,但请求将继续在后端运行——一旦回复超时触发,就没有办法将结果发送回来。

JK 使用 worker 属性 reply_timeout 来设置回复超时。默认值为“0”(禁用超时),您可以将其设置为任何毫秒值。

结合 Apache HTTP Server,您还可以使用 Apache 环境变量设置更灵活的 reply_timeout。如果您将变量 JK_REPLY_TIMEOUT 设置为某个整数值,则将使用此值而不是 worker 配置中的值。这样,您可以根据 URI、查询字符串等,使用 mod_setenvif 和 mod_rewrite 更灵活地设置回复超时。如果环境变量 JK_REPLY_TIMEOUT 未设置或设置为负值,则将使用 worker 的默认回复超时。如果 JK_REPLY_TIMEOUT 包含值“0”,则将禁用该请求的回复超时。

结合负载均衡 worker,如果回复超时触发,JK 将禁用负载均衡器的一个成员 worker。该 worker 将不再被使用,直到在下一次自动维护任务中恢复。从 JK 1.2.24 开始,您可以使用 max_reply_timeouts 改进此行为。此属性将允许偶尔长时间运行的请求而不会禁用 worker。只有当这些请求发生得过于频繁时,负载均衡器才会禁用该 worker。

负载均衡器错误检测

本地和全局错误状态

负载均衡 worker 不仅具有负载均衡的能力。它还在发生错误时处理请求的粘性和故障转移。当负载均衡器检测到其某个成员出现错误时,它需要决定该错误是严重的,还是仅是临时错误,或者可能仅与正在处理的实际请求有关。临时错误称为本地错误,严重错误将称为全局错误。

如果负载均衡器决定将后端置于全局错误状态,则 Web 服务器将不再向其发送任何请求。如果未使用会话复制,这意味着位于相应后端上的所有用户会话都将不再可用。用户将被发送到另一个后端,并且必须再次登录。因此,全局错误状态对用户来说是不透明的。应用程序仍然可用,但用户可能会丢失一些工作。

在某些情况下,本地错误和全局错误之间的决定很容易。例如,如果向客户端(浏览器)发送响应时出错,那么后端损坏的可能性很小。所以这种情况是本地错误的典型例子。

然而,有些情况更难决定。如果负载均衡器无法与后端建立新连接,可能是因为临时过载(因此后端没有更多空闲线程),或者因为后端不再活跃。根据具体情况,正确的状态可能是本地错误或全局错误。

错误升级时间

直到 1.2.26 版本,大多数错误都被解释为全局错误。从 1.2.27 版本开始,许多以前被解释为全局的错误,在后端仍然繁忙时,都被切换为本地错误。繁忙意味着其他并发请求被发送到同一个后端(无论成功与否)。

在许多情况下,没有完美的办法来决定本地错误和全局错误。负载均衡器只是没有足够的信息。在 1.2.28 版本中,您现在可以调整负载均衡器从本地错误切换到全局错误的速度。如果负载均衡器的一个成员在本地错误状态下停留时间过长,负载均衡器将把它升级到全局错误状态。

本地错误状态下的容忍时间由负载均衡器属性 error_escalation_time(以秒为单位)控制。默认值是 recover_time 的一半,因此除非您更改了 recover_time,否则默认值为 30 秒。

使用较小的 error_escalation_time 值将使负载均衡器更快地响应严重错误,但也会增加在不太严重的情况下更频繁地丢失会话的风险。您可以将 error_escalation_time 降低到 0 秒,这意味着所有潜在严重的本地错误都会立即升级为全局错误。

请注意,如果没有良好的基本错误检测,整个升级过程将毫无用处。因此,在考虑调整 error_escalation_time 之前,您应该明确使用 socket_connect_timeout 并通过 ping_modeping_timeout 激活 CPing/CPong。