配置分布式缓存

了解如何配置缓存层

Keycloak 旨在实现高可用性和多节点集群设置。当前的分布式缓存实现构建在 Infinispan 之上,Infinispan 是一款高性能、可分布式的内存数据网格。

启用分布式缓存

当您使用 start 命令在生产模式下启动 Keycloak 时,缓存将被启用,并且网络中的所有 Keycloak 节点都将被发现。

默认情况下,缓存使用 UDP 传输栈,以便节点使用基于 UDP 的 IP 多播传输进行发现。对于大多数生产环境而言,存在比 UDP 更好的发现替代方案。Keycloak 允许您从一组预定义的默认传输栈中选择,或者定义您自己的自定义栈,正如您将在本指南的后面部分看到的那样。

要显式启用分布式 infinispan 缓存,请输入以下命令

bin/kc.[sh|bat] start --cache=ispn

当您使用 start-dev 命令在开发模式下启动 Keycloak 时,Keycloak 只使用本地缓存,并且分布式缓存通过隐式设置 --cache=local 选项而完全禁用。local 缓存模式仅供开发和测试之用。

配置缓存

Keycloak 提供了一个带有合理默认值的缓存配置文件,位于 conf/cache-ispn.xml 中。

缓存配置是一个常规的 Infinispan 配置文件

下表概述了 Keycloak 使用的特定缓存。您可以在 conf/cache-ispn.xml 中配置这些缓存

缓存名称 缓存类型 描述

realms

本地

缓存持久化的 realm 数据

users

本地

缓存持久化的用户数据

authorization

本地

缓存持久化的授权数据

keys

本地

缓存外部公钥

work

复制

在节点之间传播失效消息

authenticationSessions

分布式

缓存身份验证会话,在身份验证过程中创建/销毁/过期

sessions

分布式

缓存持久化的用户会话数据

clientSessions

分布式

缓存持久化的客户端会话数据

offlineSessions

分布式

缓存持久化的离线用户会话数据

offlineClientSessions

分布式

缓存持久化的离线客户端会话数据

loginFailures

分布式

跟踪登录失败,欺诈检测

actionTokens

分布式

缓存操作令牌

缓存类型和默认值

本地缓存

Keycloak 在本地缓存持久数据,以避免不必要的往返数据库。

以下数据使用本地缓存保存在集群中的每个节点上

  • realms 和相关数据,如客户端、角色和组。

  • users 和相关数据,如授予的角色和组成员资格。

  • authorization 和相关数据,如资源、权限和策略。

  • keys

realm、用户和授权的本地缓存默认配置为最多保存 10,000 个条目。本地密钥缓存默认可以保存最多 1,000 个条目,并且默认每小时过期一次。因此,密钥将被强制定期从外部客户端或身份提供者下载。

为了获得最佳运行时并避免额外的往返数据库,您应该考虑查看每个缓存的配置,以确保最大条目数与数据库的大小一致。您可以缓存的条目越多,服务器需要从数据库中获取数据的次数就越少。您应该评估内存利用率和性能之间的权衡。

本地缓存的失效

本地缓存提高了性能,但在多节点设置中带来了挑战。

当一个 Keycloak 节点更新共享数据库中的数据时,所有其他节点都需要知道此更新,以便从其缓存中使该数据失效。

work 缓存是一个复制缓存,用于发送这些失效消息。此缓存中的条目/消息非常短命,并且您不应期望此缓存随着时间的推移而增长。

身份验证会话

每当用户尝试进行身份验证时,都会创建身份验证会话。一旦身份验证过程完成或由于达到其过期时间而结束,它们会自动销毁。

authenticationSessions 分布式缓存用于在身份验证过程中存储身份验证会话和与之关联的任何其他数据。

通过依赖于可分布式缓存,身份验证会话可供集群中的任何节点使用,以便用户可以重定向到任何节点而不会丢失其身份验证状态。但是,生产就绪部署应始终考虑会话亲和性,并优先将用户重定向到最初创建其会话的节点。通过这样做,您将避免节点之间不必要的状态转移,并提高 CPU、内存和网络利用率。

用户会话

用户身份验证后,会创建一个用户会话。用户会话跟踪您的活动用户及其状态,以便他们可以无缝地身份验证到任何应用程序,而无需再次被要求提供其凭据。对于每个应用程序,用户都会使用客户端会话进行身份验证,以便服务器可以跟踪用户已身份验证的应用程序及其在每个应用程序的基础上的状态。

用户和客户端会话会在用户执行注销、客户端执行令牌撤销或由于达到其过期时间而结束时自动销毁。

会话数据默认存储在数据库中,并在需要时加载到以下缓存中

  • sessions

  • clientSessions

通过依赖于可分布式缓存,缓存的用户和客户端会话可供集群中的任何节点使用,以便用户可以重定向到任何节点,而无需从数据库中加载会话数据。但是,生产就绪部署应始终考虑会话亲和性,并优先将用户重定向到最初创建其会话的节点。通过这样做,您将避免节点之间不必要的状态转移,并提高 CPU、内存和网络利用率。

这些用于用户会话和客户端会话的内存缓存默认情况下每个节点限制为 10000 个条目,这减少了 Keycloak 针对较大安装的整体内存使用量。内部缓存将仅使用每个缓存条目的单个所有者运行。请考虑内存消耗和数据库利用率之间的权衡,并为缓存设置不同的大小,编辑 Keycloak 的缓存配置文件 (conf/cache-ispn.xml) 以设置 <memory max-count="..."/> 针对这些缓存。

易失性用户会话

默认情况下,用户会话存储在数据库中,并在需要时加载到缓存中。可以配置 Keycloak 仅在缓存中存储用户会话,并最大程度地减少数据库利用率。

由于此设置中的所有会话都存储在内存中,因此与之相关的有两个副作用:* 在所有 Keycloak 节点重启时丢失会话 * 内存消耗增加

按照以下步骤启用此设置

  1. 由于缓存是用户和客户端会话的唯一可靠来源,因此将缓存配置为不限制条目数并将每个条目复制到至少两个节点。为此,请编辑 Keycloak 的缓存配置文件 (conf/cache-ispn.xml) 以获取缓存 sessionsclientSessions,并进行以下更新

    • 删除 <memory max-count="..."/>

    • distributed-cache 标签的 owners 属性更改为 2 或更多

    以下显示了 sessions 缓存的最终配置示例。

    <distributed-cache name="sessions" owners="2">
        <expiration lifespan="-1"/>
    </distributed-cache>
  2. 使用以下命令禁用 persistent-user-sessions 功能

    bin/kc.sh start --features-disabled=persistent-user-sessions ...

启用 multi-site 功能时,无法禁用 persistent-user-sessions

离线用户会话

作为 OpenID Connect 提供者,服务器还能够验证用户并颁发离线令牌。与常规用户和客户端会话类似,当服务器在成功身份验证后颁发离线令牌时,服务器还会创建一个离线用户会话和一个离线客户端会话。

以下缓存用于存储离线会话

  • offlineSessions

  • offlineClientSessions

与常规用户和客户端会话缓存类似,离线用户和客户端会话缓存默认情况下每个节点也限制为 10000 个条目。从内存中逐出的项目将在需要时从数据库中按需加载。请考虑内存消耗和数据库利用率之间的权衡,并为缓存设置不同的大小,编辑 Keycloak 的缓存配置文件 (conf/cache-ispn.xml) 以设置 <memory max-count="..."/> 针对这些缓存。

密码暴力破解检测

loginFailures 分布式缓存用于跟踪有关登录失败尝试的数据。此缓存对于暴力破解保护功能在多节点 Keycloak 设置中正常工作是必需的。

操作令牌

操作令牌用于用户需要异步确认操作的情况,例如在忘记密码流程中发送的电子邮件中。actionTokens 分布式缓存用于跟踪有关操作令牌的元数据。

配置缓存最大大小

为了减少内存使用量,可以对存储在给定缓存中的条目数量设置上限。要指定缓存的上限,您必须提供以下命令行参数 --cache-embedded-${CACHE_NAME}-max-count=,并将 ${CACHE_NAME} 替换为您要应用上限的缓存的名称。例如,要对 offlineSessions 缓存应用 1000 的上限,您将配置 --cache-embedded-offline-sessions-max-count=1000。无法对以下缓存定义上限:actionTokenauthenticationSessionsloginFailureswork

配置缓存以实现可用性

分布式缓存将缓存条目复制到集群中的节点子集,并将条目分配给固定所有者节点。

每个分布式缓存(即数据的真相来源(authenticationSessionsloginFailuresactionTokens))默认有两个所有者,这意味着两个节点都拥有特定缓存条目的副本。非所有者节点查询特定缓存的所有者以获取数据。当两个所有者节点都处于脱机状态时,所有数据都会丢失。

默认的所有者数量足以在至少有三个节点的集群设置中容忍 1 个节点(所有者)故障。您可以根据需要自由更改所有者数量,以更好地适应您的可用性要求。要更改所有者数量,请打开 conf/cache-ispn.xml 并将分布式缓存的 owners=<value> 的值更改为您想要的值。

指定您自己的缓存配置文件

要指定您自己的缓存配置文件,请输入以下命令

bin/kc.[sh|bat] start --cache-config-file=my-cache-file.xml

配置文件相对于 conf/ 目录。

远程服务器的 CLI 选项

为了配置 Keycloak 服务器以实现高可用性和多节点集群设置,引入了以下 CLI 选项:cache-remote-hostcache-remote-portcache-remote-usernamecache-remote-password,简化了 XML 文件中的配置。一旦声明了任何 CLI 参数,就预期 XML 文件中不存在与远程存储相关的配置。

连接到不安全的 Infinispan 服务器

在生产环境中,不建议禁用安全功能!

在开发或测试环境中,启动一个不安全的 Infinispan 服务器更容易。对于这些用例,CLI 选项 cache-remote-tls-enabled 会禁用 Keycloak 和 Infinispan 之间的加密(TLS)。如果 Infinispan 服务器被配置为只接受加密连接,Keycloak 将无法启动。

CLI 选项 cache-remote-usernamecache-remote-password 是可选的,如果未设置,Keycloak 将连接到 Infinispan 服务器,而不会提供任何凭据。如果 Infinispan 服务器启用了身份验证,Keycloak 将无法启动。

传输堆栈

传输堆栈确保集群中分布式缓存节点以可靠的方式进行通信。Keycloak 支持各种传输堆栈

  • tcp

  • udp

  • kubernetes

  • ec2

  • azure

  • google

要应用特定缓存堆栈,请输入以下命令

bin/kc.[sh|bat] start --cache-stack=<stack>

当启用分布式缓存时,默认堆栈设置为 udp

可用的传输堆栈

下表显示了无需任何进一步配置即可使用 --cache-stack 构建选项使用的可用传输堆栈

堆栈名称 传输协议 发现

tcp

TCP

MPING(使用 UDP 多播)。

udp

UDP

UDP 多播

下表显示了使用 --cache-stack 运行时选项和最小配置即可使用的传输堆栈

堆栈名称 传输协议 发现

kubernetes

TCP

DNS_PING(需要将 -Djgroups.dns.query=<headless-service-FQDN> 添加到 JAVA_OPTS 或 JAVA_OPTS_APPEND 环境变量)。

其他传输堆栈

下表显示了 Keycloak 支持的传输堆栈,但需要一些额外的步骤才能工作。请注意,这些堆栈都不是 Kubernetes / OpenShift 堆栈,因此如果要在 Google Kubernetes 引擎上运行 Keycloak,则无需启用 google 堆栈。在这种情况下,请使用 kubernetes 堆栈。相反,如果您有一个在 AWS EC2 实例上运行的分布式缓存设置,则需要将堆栈设置为 ec2,因为 ec2 不支持 UDP 等默认发现机制。

堆栈名称 传输协议 发现

ec2

TCP

NATIVE_S3_PING

google

TCP

GOOGLE_PING2

azure

TCP

AZURE_PING

云供应商特定堆栈对 Keycloak 有额外的依赖项。有关这些依赖项的更多信息和指向存储库的链接,请参阅 Infinispan 文档

要为 Keycloak 提供依赖项,请将相应的 JAR 文件放在 providers 目录中,然后通过输入以下命令构建 Keycloak

bin/kc.[sh|bat] start --cache-stack=<ec2|google|azure>

自定义传输堆栈

如果可用的传输堆栈都不适合您的部署,您可以更改缓存配置文件并定义自己的传输堆栈。

有关更多详细信息,请参阅 使用内联 JGroups 堆栈

定义自定义传输堆栈
<jgroups>
    <stack name="my-encrypt-udp" extends="udp">
    <SSL_KEY_EXCHANGE keystore_name="server.jks"
        keystore_password="password"
        stack.combine="INSERT_AFTER"
        stack.position="VERIFY_SUSPECT2"/>
        <ASYM_ENCRYPT asym_keylength="2048"
        asym_algorithm="RSA"
        change_key_on_coord_leave = "false"
        change_key_on_leave = "false"
        use_external_key_exchange = "true"
        stack.combine="INSERT_BEFORE"
        stack.position="pbcast.NAKACK2"/>
    </stack>
</jgroups>

<cache-container name="keycloak">
    <transport lock-timeout="60000" stack="my-encrypt-udp"/>
    ...
</cache-container>

默认情况下,设置为 cache-stack 选项的值优先于您在缓存配置文件中定义的传输堆栈。如果您正在定义自定义堆栈,请确保未使用 cache-stack 选项,以便自定义更改生效。

保护缓存通信

当前的 Infinispan 缓存实现应该通过各种安全措施(如 RBAC、ACL 和传输堆栈加密)来保护。

JGroups 处理 Keycloak 服务器之间的所有通信,并且它支持用于 TCP 通信的 Java SSL 套接字。Keycloak 使用 CLI 选项来配置 TLS 通信,而无需创建自定义 JGroups 堆栈或修改缓存 XML 文件。

要启用 TLS,cache-embedded-mtls-enabled 必须设置为 true。它需要一个带有要使用的证书的密钥库:cache-embedded-mtls-key-store-file 设置密钥库的路径,cache-embedded-mtls-key-store-password 设置解密它的密码。信任库包含要接受来自的连接的有效证书,可以使用 cache-embedded-mtls-trust-store-file(信任库的路径)和 cache-embedded-mtls-trust-store-password(解密它的密码)进行配置。为了限制未经授权的访问,请为每个 Keycloak 部署使用自签名证书。

对于具有 UDPTCP_NIO2 的 JGroups 堆栈,请参阅 JGroups 加密文档,了解如何设置协议堆栈。

有关保护缓存通信的更多信息,请参阅 Infinispan 安全指南

公开缓存的指标

启用指标后,缓存的指标会自动公开。

要为缓存指标启用直方图,请将 cache-metrics-histograms-enabled 设置为 true。虽然这些指标提供了更多关于延迟分布的洞察,但收集它们可能会对性能产生影响,因此您应该谨慎地在已经饱和的系统中激活它们。

bin/kc.[sh|bat] start --metrics-enabled=true --cache-metrics-histograms-enabled=true

有关如何启用指标的更多详细信息,请参阅 启用 Keycloak 指标

相关选项

cache

定义用于高可用性的缓存机制。

在生产模式下,默认情况下使用 ispn 缓存来创建多个服务器节点之间的集群。在开发模式下,默认情况下,local 缓存会禁用集群,旨在用于开发和测试目的。

CLI: --cache
Env: KC_CACHE

ispn(默认)、local

cache-config-file

定义应该从哪个文件加载缓存配置。

配置文件相对于 conf/ 目录。

CLI: --cache-config-file
Env: KC_CACHE_CONFIG_FILE

cache-embedded-authorization-max-count

授权缓存可以存储在内存中的最大条目数。

CLI: --cache-embedded-authorization-max-count
Env: KC_CACHE_EMBEDDED_AUTHORIZATION_MAX_COUNT

cache-embedded-client-sessions-max-count

clientSessions 缓存可以存储在内存中的最大条目数。

CLI: --cache-embedded-client-sessions-max-count
Env: KC_CACHE_EMBEDDED_CLIENT_SESSIONS_MAX_COUNT

仅在配置了嵌入式 Infinispan 集群时可用

cache-embedded-keys-max-count

keys 缓存可以存储在内存中的最大条目数。

CLI: --cache-embedded-keys-max-count
Env: KC_CACHE_EMBEDDED_KEYS_MAX_COUNT

cache-embedded-mtls-enabled

加密 Keycloak 服务器之间的网络通信。

CLI: --cache-embedded-mtls-enabled
Env: KC_CACHE_EMBEDDED_MTLS_ENABLED

truefalse(默认)

cache-embedded-mtls-key-store-file

密钥库文件路径。

密钥库必须包含 TLS 协议使用的证书。默认情况下,它在 conf/ 目录下查找 cache-mtls-keystore.p12

CLI: --cache-embedded-mtls-key-store-file
Env: KC_CACHE_EMBEDDED_MTLS_KEY_STORE_FILE

cache-embedded-mtls-key-store-password

访问密钥库的密码。

CLI: --cache-embedded-mtls-key-store-password
Env: KC_CACHE_EMBEDDED_MTLS_KEY_STORE_PASSWORD

cache-embedded-mtls-trust-store-file

信任库文件路径。

它应该包含受信任的证书或签署证书的证书颁发机构。默认情况下,它在 conf/ 目录下查找 cache-mtls-truststore.p12

CLI: --cache-embedded-mtls-trust-store-file
Env: KC_CACHE_EMBEDDED_MTLS_TRUST_STORE_FILE

cache-embedded-mtls-trust-store-password

访问信任库的密码。

CLI: --cache-embedded-mtls-trust-store-password
Env: KC_CACHE_EMBEDDED_MTLS_TRUST_STORE_PASSWORD

cache-embedded-offline-client-sessions-max-count

offlineClientSessions 缓存可以存储在内存中的最大条目数。

CLI: --cache-embedded-offline-client-sessions-max-count
Env: KC_CACHE_EMBEDDED_OFFLINE_CLIENT_SESSIONS_MAX_COUNT

仅在配置了嵌入式 Infinispan 集群时可用

cache-embedded-offline-sessions-max-count

offlineSessions 缓存可以存储在内存中的最大条目数。

CLI: --cache-embedded-offline-sessions-max-count
Env: KC_CACHE_EMBEDDED_OFFLINE_SESSIONS_MAX_COUNT

仅在配置了嵌入式 Infinispan 集群时可用

cache-embedded-realms-max-count

realms 缓存可以存储在内存中的最大条目数。

CLI: --cache-embedded-realms-max-count
Env: KC_CACHE_EMBEDDED_REALMS_MAX_COUNT

cache-embedded-sessions-max-count

sessions 缓存可以存储在内存中的最大条目数。

CLI: --cache-embedded-sessions-max-count
Env: KC_CACHE_EMBEDDED_SESSIONS_MAX_COUNT

仅在配置了嵌入式 Infinispan 集群时可用

cache-embedded-users-max-count

users 缓存可以存储在内存中的最大条目数。

CLI: --cache-embedded-users-max-count
Env: KC_CACHE_EMBEDDED_USERS_MAX_COUNT

cache-metrics-histograms-enabled

为嵌入式缓存的指标启用直方图。

CLI: --cache-metrics-histograms-enabled
Env: KC_CACHE_METRICS_HISTOGRAMS_ENABLED

仅在启用指标时可用

truefalse(默认)

cache-remote-host

用于远程存储配置的远程服务器的主机名。

它替换了通过 XML 文件(请参阅 cache-config-file 选项)指定的配置的 remote-server 标签的 host 属性。如果指定了该选项,还需要 cache-remote-usernamecache-remote-password,并且 XML 文件中的相关配置不应存在。

CLI: --cache-remote-host
Env: KC_CACHE_REMOTE_HOST

cache-remote-password

用于远程存储的远程服务器身份验证的密码。

它替换了通过 XML 文件(请参阅 cache-config-file 选项)指定的配置的 digest 标签的 password 属性。如果指定了该选项,还需要 cache-remote-username,并且 XML 文件中的相关配置不应存在。

CLI: --cache-remote-password
Env: KC_CACHE_REMOTE_PASSWORD

仅在设置了远程主机时可用

cache-remote-port

用于远程存储配置的远程服务器的端口。

它替换了通过 XML 文件(请参阅 cache-config-file 选项)指定的配置的 remote-server 标签的 port 属性。

CLI: --cache-remote-port
Env: KC_CACHE_REMOTE_PORT

仅在设置了远程主机时可用

11222(默认)

cache-remote-tls-enabled

启用 TLS 支持,以与安全的远程 Infinispan 服务器进行通信。

建议在生产环境中启用。

CLI: --cache-remote-tls-enabled
Env: KC_CACHE_REMOTE_TLS_ENABLED

仅在设置了远程主机时可用

true(默认)、false

cache-remote-username

用于远程存储的远程服务器身份验证的用户名。

它替换了通过 XML 文件(请参阅 cache-config-file 选项)指定的配置的 digest 标签的 username 属性。如果指定了该选项,还需要 cache-remote-password,并且 XML 文件中的相关配置不应存在。

CLI: --cache-remote-username
Env: KC_CACHE_REMOTE_USERNAME

仅在设置了远程主机时可用

cache-stack

定义用于集群通信和节点发现的默认堆栈。

该选项仅在 cache 设置为 ispn 时生效。默认:udp。

CLI: --cache-stack
Env: KC_CACHE_STACK

tcpudpkubernetesec2azuregoogle 或任何

在本页上