9.4. 粘性会话

典型的集群部署包括负载均衡器(逆向代理)以及 2 个或更多红帽在专用网络上的 Red Hat Single Sign-On 服务器。出于性能考虑,如果负载均衡器将所有与特定浏览器会话相关的请求转发到同一个红帽单点登录后端节点,这可能很有用。

其原因在于,Red Hat Single Sign-On 在涵盖保存与当前身份验证会话和用户会话相关的数据的情况下,使用 Infinispan 分布式缓存。默认情况下,Infinispan 分布式缓存配置为一个所有者。这意味着,特定会话只保存在一个集群节点中,另一个节点需要远程查找会话(如果它们想要访问它)。

例如,如果 ID 为 123 的验证会话保存在 node1 上的 Infinispan 缓存中,而 node2 需要查找此会话,则需要通过网络将请求发送到 node1,以返回特定会话实体。

如果特定会话实体始终在本地可用,则可使用粘性会话的帮助。带有公共前端负载均衡器的集群环境中的工作流和两个后端红帽单点登录节点可能如下所示:

  • 用户发送初始请求以查看红帽单点登录登录屏幕
  • 此请求由 frontend 负载均衡器提供,它将转发到一些随机节点(如 node1)。严格说,该节点不需要随机,但可以根据其他标准(客户端 IP 地址等)选择。它完全取决于底层负载均衡器的实施和配置(逆向代理)。
  • Red Hat Single Sign-On 使用随机 ID(如 123)创建身份验证会话,并将其保存到 Infinispan 缓存中。
  • Infinispan 分布式缓存根据会话 ID 的哈希分配会话的主所有者。有关此问题的详情,请参阅 Infinispan 文档。我们假设将 node2 分配为此会话的所有者。
  • Red Hat Single Sign-On 使用 < session-id>.<owner-node-id> 格式创建 cookie AUTH_SESSION_ID。在我们的示例中,它是 123.node2
  • 使用 Red Hat Single Sign-On 登录屏幕和浏览器中的 AUTH_SESSION_ID cookie 返回响应

此时,如果负载均衡器将所有下一个请求转发到 node2,这是具有 ID 123 的身份验证会话的所有者,因此 Infinispan 可以在本地查询该会话时很有用。身份验证完成后,身份验证会话将转换为用户会话,该会话也将保存在 node2 上,因为它具有相同的 ID 123。

集群设置不强制使用粘性会话,但出于上述原因,性能很好。您需要通过 AUTH_SESSION_ID cookie 配置负载均衡器来粘性。具体操作方法取决于您的负载均衡器。

建议您在 Red Hat Single Sign-On side 中在启动时使用系统属性 jboss.node.name,其值对应于您的路由名称。例如,-Djboss.node.name=node1 将使用 node1 来识别路由。此路由将由 Infinispan 缓存使用,当节点是特定密钥的所有者时,将附加到 AUTH_SESSION_ID cookie。以下是使用这个系统属性启动命令的示例:

cd $RHSSO_NODE1
./standalone.sh -c standalone-ha.xml -Djboss.socket.binding.port-offset=100 -Djboss.node.name=node1

通常,在生产环境下,路由名称应使用与后端主机相同的名称,但这不是必须的。您可以使用不同的路由名称。例如,如果您要将 Red Hat Single Sign-On 服务器的主机名隐藏到您的专用网络中。

9.4.1. 禁用添加路由

有些负载均衡器可以自行配置来添加路由信息,而不依赖于后端红帽单点登录节点。但如上述所述,推荐使用 Red Hat Single Sign-On 添加路由。这是因为,在以性能提高的情况下,红帽单点登录知道知道特定会话所有者的实体,并可路由到该节点,这不一定是本地节点。

如果您更喜欢在 Red Hat Single Sign-On 中添加以下内容到 RHSSO_HOME/standalone/configuration/standalone-ha.xml 文件中的 AUTH_SESSION_ID cookie,可以禁用在 Red Hat Single Sign-On 子系统配置中添加路由信息:

<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
  ...
    <spi name="stickySessionEncoder">
        <provider name="infinispan" enabled="true">
            <properties>
                <property name="shouldAttachRoute" value="false"/>
            </properties>
        </provider>
    </spi>

</subsystem>