超时操作指南

简介

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

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

不要将超时设置为极端值。非常小的超时可能会适得其反。

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

JK 超时属性

CPing/CPong

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

后端会使用最少的必要处理资源非常快速地回答测试数据包。一个肯定的回答告诉我们,后端可以访问并且正在积极处理请求。它不会检测到是否已部署并正在运行某个上下文。CPing/CPong 的好处是快速检测到与后端通信的问题。缺点是延迟略有增加。

工作程序属性 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 来激活。

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

工作程序属性 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_timeout 分别设置为 prepost_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 保活数据包,从而设置标准套接字选项。默认情况下,此选项设置为 false。如果您怀疑防火墙会中断空闲连接,则应将其设置为 true

遗憾的是,这些数据包的默认间隔和算法是特定于平台的。您可能需要检查平台的 TCP 调优选项,了解如何控制 TCP 保活。通常,默认间隔远长于防火墙对空闲连接的超时时间。不过,我们建议您与防火墙管理员和平台管理员沟通,让他们就防火墙和平台 TCP 调优的良好配置值达成一致。

如果我们的建议都没有帮助,并且您肯定遇到了空闲连接中断的问题,则可以在将 JK 与 Apache HTTP Server 一起使用时禁用持久连接的使用。为此,您可以在 Apache 配置中设置“JkOptions +DisableReuse”。这将产生的性能影响程度取决于您的网络和防火墙的详细信息。

回复超时

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

在大多数情况下,这正是人们真正想要的东西。例如,考虑长时间下载。你将无法设置一个有效的全局响应超时,因为下载可能持续很多分钟。然而,大多数应用程序在开始返回响应之前都有有限的处理时间。对于那些应用程序,你可以设置一个明确的响应超时。与响应超时不协调的应用程序是批处理类型应用程序、数据仓库和报告应用程序,这些应用程序预计会观察到较长的处理时间。

如果 JK 中止等待响应,因为响应超时触发,则没有办法停止后端的处理。虽然你释放了 Web 服务器中的处理资源,但请求仍将继续在后端运行 - 一旦响应超时触发,就无法再发回结果。

JK 使用工作程序属性 reply_timeout 设置响应超时。默认值为“0”(禁用超时),你可以将其设置为任何毫秒值。

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

结合使用负载平衡工作程序,如果响应超时触发,JK 将禁用负载平衡器的成员工作程序。然后,该工作程序将不再被使用,直到它在下一个自动维护任务期间恢复。从 JK 1.2.24 开始,你可以使用 max_reply_timeouts 改进此行为。此属性将允许偶尔长时间运行请求,而不会禁用工作程序。只有当这些请求经常发生时,工作程序才会被负载平衡器禁用。

负载平衡器错误检测

本地和全局错误状态

负载平衡器工作程序不仅具有平衡负载的能力。它还处理请求的粘滞性和故障转移(在发生错误时)。当负载平衡器在其一个成员上检测到错误时,它需要决定该错误是严重的,还是只是临时错误,或者可能仅与正在处理的实际请求相关。临时错误称为本地错误,严重错误将称为全局错误。

如果负载均衡器决定将后端置于全局错误状态,则 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。