了解 Infinispan 和 JGroups 中的故障检测

本指南介绍了 JGroups 如何检测故障实例以及如何配置它。它解释了可用于自定义的配置属性及其权衡以实现所需的检测速率。

JGroups 的使用场景以及故障检测为何重要

Keycloak 使用 Infinispan 在 Keycloak 内部和 Infinispan 的外部实例中存储与会话相关的分布式缓存信息。Keycloak 实例以及外部 Infinispan 实例都形成集群,集群节点之间的通信由 JGroups 处理。不同外部 Infinispan 集群在多站点设置中的通信也由 JGroups 处理。

此类集群中的每个节点都服务于会话数据,这对于 Keycloak 服务请求至关重要。无响应的节点会导致请求阻塞,并可能导致调用方出现超时和错误。如果节点发生故障,则需要将请求重定向到剩余的节点,并且需要从集群中的备份节点重新分发其数据。

导致通信故障的 TCP 连接中断

TCP 连接中断会对集群性能产生影响,因此需要检测连接中断,以便关闭连接并建立新的连接。请注意,TCP 是一种阻塞/同步协议,如果连接无法正常工作,则线程将在 Socket::write 操作中被阻塞。内核参数 tcp_retries2 配置了内核强制关闭连接之前的失败重试次数。引用 内核文档

此值会影响活动 TCP 连接的超时时间,当 RTO 重传未得到确认时。默认值为 15,产生 924.6 秒的假设超时时间,并且是有效超时的下限。

在此期间,集群性能会下降。在镜像或容器中更改内核参数不可取,但 JGroups 具有可配置的属性,可以检测和强制关闭这些断开的连接。

对于使用 Kubernetes 中的 TUNNEL 协议的跨站点网络通信,Infinispan Pod 流量通过 JGroups Gossip Router Pod 转发。超时时间在 Infinispan CR YAML 文件中配置,如下所示

infinispan.yaml
  service:
    type: DataGrid
    sites:
      local:
        discovery:
          heartbeats:
            interval: 10000 (1)
            timeout: 30000 (2)
1 interval 毫秒向 Gossip 路由器发送心跳。
2 在未收到消息或心跳后,连接到 Gossip 路由器的最大时间(毫秒),在此时间后连接将关闭。
以上值是 Infinispan 运算符配置的默认值。

缩短间隔和超时时间会加快 JGroups 检测断开连接的速度。但是,由于心跳频率增加,这也会增加网络使用率。请注意,两个集群中的所有 Infinispan Pod 都将向所有已配置的 Gossip Router Pod 发送心跳。

默认设置应该适用于 99% 的用例。

对于 Infinispan 或 Keycloak 集群中的集群内通信,故障检测会检测并关闭断开的 TCP 连接。有关更多信息,请参见 检测无响应节点 部分。

检测无响应节点

集群中的节点可能会发生故障,发生这种情况后,需要重定向流量和数据。JGroups 中的故障检测由默认的 JGroups 配置(随 Infinispan 提供)中提供的协议 FD_ALL3 提供。

FD_ALL3 是一种简单的心跳协议,每个成员定期进行多播心跳。当从另一个 Pod 接收数据或心跳时,该 Pod 被认为是活跃的,否则该 Pod 被认为是可疑的,并且可能会从组视图中删除。

心跳间隔和超时时间配置如下所示

<infinispan>
   <jgroups>
      <stack name="my-tcp" extends="tcp"> (1)
         <FD_ALL3 stack.combine="COMBINE"
               interval="8000" (2)
               timeout="40000"/> (3)
      </stack>
   </jgroups>

   <cache-container>
      <transport stack="my-tcp"/> (4)
   </cache-container>
</infinispan>
1 自定义堆栈名称。
2 发送心跳到集群的间隔(毫秒)。
3 超时时间(毫秒),如果在此时间内未收到心跳或数据,则该节点会被怀疑。
4 JGroups 要使用的堆栈名称。
以上示例显示了默认值。

对于包含 M 个 Pod 的集群,每个 Pod 将在每个间隔生成 M-1 个心跳消息。缩短 intervaltimeout 会提高崩溃 Pod 的检测速度,但会通过传输的额外消息对网络产生更大的影响。

如果启用了跨站点,FD_ALL3 心跳也会流向远程集群。跨站点通道具有自己的配置,可以独立于集群内通信进行配置。

默认设置应该适用于 99% 的用例。

在怀疑 Pod 之后,会触发新的组视图更改,但不会包含崩溃的成员。此事件会关闭与该 Pod 的任何断开的 TCP 连接,并解除可能阻塞的线程的阻塞。

读写操作的超时时间

Infinispan 具有三个可配置的超时时间,这些超时时间会影响 Keycloak 和 Infinispan 集群中的读写操作。这些是锁定超时时间、远程超时时间和跨站点远程超时时间。

如果超时时间与上面描述的故障检测超时时间和间隔保持一致,则它们允许在连接或节点故障后至少进行一次重试。这允许为调用方提供有效响应,并隐藏发生的错误。

锁定超时时间是操作等待释放锁的等待时间。这应该是所有超时时间中最短的。

远程超时时间是 Infinispan Pod 等待同一集群中其他 Pod 响应的时间。它会影响写入(在复制数据时)和读取(如果本地不存在副本,则 Pod 会从其他 Pod 中获取数据)。

最后,对于多站点部署,跨站点远程超时时间是等待另一个集群确认更新的等待时间。

更改这些值可能会直接影响响应时间。尽管在正常操作期间,Infinispan 在几毫秒内做出响应,但如果工作负载较高、Pod 崩溃或网络中断,则可能会达到这些超时时间。

缩短超时时间会缩短响应时间;Infinispan 会更快放弃,但会增加报告给用户的错误率。延长这些值可能会减少错误数量,因为它为 Infinispan 完成工作负载提供了更多时间,但会延长最终用户观察到的响应时间。

要更新使用 Infinispan 运算符部署的 Infinispan 集群中的任何超时值,请按照以下步骤更新您的 CacheCR

apiVersion: infinispan.org/v2alpha1
kind: Cache
metadata:
  name: sessions
spec:
  clusterName: infinispan
  name: sessions
  template: |-
    distributedCache:
      mode: "SYNC"
      owners: 2
      statistics: "true"
      remoteTimeout: "15000" (1)
      locking:
        acquireTimeout: "10000" (2)
      backups:
        cluster-b:
          backup:
            strategy: "SYNC"
            timeout: "15000"  (3)
1 等待本地集群中其他 Pod 响应的超时值(毫秒)。
2 等待锁定释放的超时值(毫秒)。
3 等待远程集群响应的超时值(毫秒)。
示例显示了默认值。仅添加要更新的超时的行。

对于在 Keycloak 服务器中运行的 Infinispan 集群,需要自定义的 Infinispan XML 文件。更改缓存配置,如所示,并添加要更新的属性(以粗体显示)

<distributed-cache name="sessions" owners="2" statistics="true" remote-timeout="15000"> (1)
    <locking acquire-timeout="10000"/> (2)
    <backups>
        <backup site="cluster-b" timeout="15000"/> (3)
    </backups>
</distributed-cache>
1 等待本地集群中其他 Pod 响应的超时值(毫秒)。
2 等待锁定释放的超时值(毫秒)。
3 等待远程集群响应的超时值(毫秒)。
示例显示了默认值。