负载均衡指南

简介

负载均衡器是一个不直接与 Tomcat 通信的 worker。相反,它负责管理多个“真实”worker,这些 worker 被称为负载均衡器的成员或子 worker。

此管理包括

  • 在 Web 服务器中实例化 worker。
  • 使用 worker 的负载均衡因子,执行加权负载均衡(根据目标的定义强度分配负载)。
  • 将属于同一会话的请求保持在同一个 Tomcat 上执行(会话粘滞)。
  • 识别失败的 Tomcat worker,暂停对其的请求,转而故障转移到由负载均衡器管理的其他 worker。
  • 通过状态 worker 接口提供负载均衡器本身和所有成员的状态和负载指标。
  • 允许通过状态 worker 接口动态重新配置负载均衡。

由同一个负载均衡器 worker 管理的 worker 会被负载均衡(基于其配置的均衡因子和当前请求或会话负载),并通过向同一负载均衡器的其他成员提供故障转移来确保不会因故障而中断。因此,单个 Tomcat 进程的死亡不会“杀死”整个站点。

即使只使用单个成员 worker(无法进行负载均衡的情况下),负载均衡器提供的一些功能也很有趣。

基本负载均衡器属性

通过将 worker 的 type 设置为 lb 来将其配置为负载均衡器。

下表指定了用于配置负载均衡器 worker 的一些属性

  • balance_workers 是负载均衡器成员 worker 名称的逗号分隔列表。这些 worker 通常是 ajp13 类型。成员 worker 不需要自行出现在 worker.list 属性中,将其负载均衡器添加到其中即可。
  • sticky_session 指定是否应将会话 ID 请求路由回创建该会话的同一 Tomcat 实例。当 Tomcat 使用可以跨多个 Tomcat 实例共享会话数据的会话管理器时,或者如果您的应用程序是无状态的,您可以将 sticky_session 设置为 false。默认情况下,sticky_session 设置为 true
  • lbfactor 可以添加到每个成员 worker,以配置成员的单独权重。更高的 lbfactor 将导致更多的请求被均衡到该 worker。因子必须是整数,负载将按给定因子的比例分布。更高的因子导致更多的请求。
# The load balancer worker balance1 will distribute
# load to the members worker1 and worker2
worker.balance1.type=lb
worker.balance1.balance_workers=worker1, worker2
worker.worker1.type=ajp13
worker.worker1.host=myhost1
worker.worker1.port=8009
worker.worker2.type=ajp13
worker.worker1.host=myhost2
worker.worker1.port=8009
会话粘滞不是通过使用会话跟踪表实现的。相反,每个 Tomcat 实例都获得一个单独的名称,并将其名称添加到会话 ID 的末尾。当负载均衡器看到会话 ID 时,它会找到 Tomcat 实例的名称,并通过正确的成员 worker 发送请求。为此,您必须将 Tomcat 实例的名称设置为每个 Tomcat 的 server.xml 中 Engine 元素的 jvmRoute 属性的值。Tomcat 的名称需要与相应的负载均衡器成员的名称相同。在上面的示例中,主机 "myhost1" 上的 Tomcat 需要 jvmRoute="worker1",主机 "myhost2" 上的 Tomcat 需要 jvmRoute="worker2"

有关所有负载均衡器配置属性的完整参考,请查阅 worker 参考

高级负载均衡器 Worker 属性

负载均衡器支持复杂的拓扑和故障转移配置。使用成员属性 distance 可以对成员进行分组。负载均衡器总是会将请求发送到距离最低的成员。只有当所有这些成员都出现故障时,它才会均衡到下一个更高配置距离的成员。这允许在不同数据中心位置的 Tomcat 实例之间定义优先级。

在处理共享会话时,无论是通过会话复制还是持久化会话管理器(例如通过数据库),通常会将 Tomcat 集群划分为复制组。如果某个成员发生故障,负载均衡器需要知道哪些其他成员共享会话。这通过使用 domain 属性进行配置。所有具有相同域的 worker 都被假定共享会话。

出于维护目的,您可以告知负载均衡器不允许在某些成员上创建任何新会话,甚至完全不使用它们。这由成员属性 activation 控制。Active 值允许正常使用成员,disabled 将不会在其上创建新会话,但仍允许粘滞请求,而 stopped 将不再向该成员发送任何请求。在维护前一段时间将激活状态从 "active" 切换到 "disabled" 将会耗尽 worker 上的会话并最大程度地减少中断。根据应用程序的使用模式,耗尽可能需要几分钟到几小时。在维护前立即将 worker 切换到 stopped 状态将减少 mod_jk 记录的错误日志。

最后,您还可以通过将 activation 设置为 disabled,并结合添加到其他 worker 的 redirect 属性来配置热备 worker

# The advanced router LB worker
worker.list=router
worker.router.type=lb
worker.router.balance_workers=worker1,worker2

# Define the first member worker
worker.worker1.type=ajp13
worker.worker1.host=myhost1
worker.worker1.port=8009
# Define preferred failover node for worker1
worker.worker1.redirect=worker2

# Define the second member worker
worker.worker2.type=ajp13
worker.worker2.host=myhost2
worker.worker2.port=8009
# Disable worker2 for all requests except failover
worker.worker2.activation=disabled

worker1 上的 redirect 标志告诉负载均衡器,如果 worker1 出现问题,则将请求重定向到 worker2。在所有其他情况下,worker2 将不会接收任何请求,从而充当热备用。

关于将 activation 设置为 disabled 的最后一点说明:请求中包含的会话 ID 既可以作为请求 URL 的一部分(;jsessionid=...)发送,也可以通过 cookie 发送。当使用书签或长时间运行的浏览器时,可能会发送带有指向禁用成员的旧的无效会话 ID 的请求。由于负载均衡器没有有效会话列表,它会将请求转发到禁用成员。因此,耗尽会话所需的时间比预期长。为了处理这种情况,您可以在 Web 应用程序中添加一个 Servlet 过滤器,检查请求属性 JK_LB_ACTIVATION。此属性包含字符串 "ACT"、"DIS" 或 "STP" 之一。如果您检测到 "DIS" 并且请求的会话不再活动,请删除会话 cookie 并使用自引用 URL 进行重定向。重定向的请求将不再携带会话信息,因此负载均衡器不会将其发送到禁用的 worker。请求属性 JK_LB_ACTIVATION 已在版本 1.2.32 中添加。

状态 Worker 属性

状态 worker 不与 Tomcat 通信。相反,它负责 worker 管理。它与负载均衡器 worker 结合使用时特别有用。

# Add the status worker to the worker list
worker.list=jkstatus
# Define a 'jkstatus' worker using status
worker.jkstatus.type=status

接下来是将请求挂载到 jkstatus worker。对于 Apache HTTP 服务器,请使用

# Add the jkstatus mount point
JkMount /jkmanager/* jkstatus 

为了获得更高级别的安全性,请使用

# Enable the JK manager access from localhost only
<Location /jkmanager/>
  JkMount jkstatus
  Require ip 127.0.0.1
</Location>