Keycloak: 专用 Infinispan 集群的远程存储配置

15

最近,我加强了我的Keycloak部署,使用专用的Infinispan集群作为remote-store,为Keycloak的各种缓存提供额外的持久性层。更改本身进行得相当顺利,但在进行此更改后,我们开始看到很多登录错误,由于expired_code错误消息:

WARN [org.keycloak.events] (default task-2007) type=LOGIN_ERROR, realmId=my-realm, clientId=null, userId=null, ipAddress=192.168.50.38, error=expired_code, restart_after_timeout=true

这个错误信息通常在短时间内以相同的IP地址重复出现数十次。原因似乎是最终用户的浏览器在登录时无限重定向,直到浏览器本身停止循环。
我看到了一些GitHub问题(https://github.com/helm/charts/issues/8355)也记录了这种行为,共识似乎是这是由于Keycloak集群无法通过JGroups正确发现其成员所致。
当考虑到默认配置中一些Keycloak缓存在Keycloak节点之间分布时,这种解释是有道理的。但是,我已经修改了这些缓存以成为具有指向我的新Infinispan集群的remote-store的本地缓存,并且我认为我对此的工作方式做出了一些不正确的假设,导致此错误开始发生。
以下是我的Keycloak缓存配置方式:
<subsystem xmlns="urn:jboss:domain:infinispan:7.0">
    <cache-container name="keycloak" module="org.keycloak.keycloak-model-infinispan">
        <transport lock-timeout="60000"/>
        <local-cache name="realms">
            <object-memory size="10000"/>
        </local-cache>
        <local-cache name="users">
            <object-memory size="10000"/>
        </local-cache>
        <local-cache name="authorization">
            <object-memory size="10000"/>
        </local-cache>
        <local-cache name="keys">
            <object-memory size="1000"/>
            <expiration max-idle="3600000"/>
        </local-cache>
        <local-cache name="sessions">
            <remote-store cache="sessions" remote-servers="remote-cache" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                    true
                </property>
                <property name="marshaller">
                    org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
            </remote-store>
        </local-cache>
        <local-cache name="authenticationSessions">
            <remote-store cache="authenticationSessions" remote-servers="remote-cache" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                    true
                </property>
                <property name="marshaller">
                    org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
            </remote-store>
        </local-cache>
        <local-cache name="offlineSessions">
            <remote-store cache="offlineSessions" remote-servers="remote-cache" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                    true
                </property>
                <property name="marshaller">
                    org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
            </remote-store>
        </local-cache>
        <local-cache name="clientSessions">
            <remote-store cache="clientSessions" remote-servers="remote-cache" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                    true
                </property>
                <property name="marshaller">
                    org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
            </remote-store>
        </local-cache>
        <local-cache name="offlineClientSessions">
            <remote-store cache="offlineClientSessions" remote-servers="remote-cache" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                    true
                </property>
                <property name="marshaller">
                    org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
            </remote-store>
        </local-cache>
        <local-cache name="loginFailures">
            <remote-store cache="loginFailures" remote-servers="remote-cache" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                    true
                </property>
                <property name="marshaller">
                    org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
            </remote-store>
        </local-cache>
        <local-cache name="actionTokens">
            <remote-store cache="actionTokens" remote-servers="remote-cache" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                    true
                </property>
                <property name="marshaller">
                    org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
            </remote-store>
        </local-cache>
        <replicated-cache name="work">
            <remote-store cache="work" remote-servers="remote-cache" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                    true
                </property>
                <property name="marshaller">
                    org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
            </remote-store>
        </replicated-cache>
    </cache-container>
    <cache-container name="server" aliases="singleton cluster" default-cache="default" module="org.wildfly.clustering.server">
        <transport lock-timeout="60000"/>
        <replicated-cache name="default">
            <transaction mode="BATCH"/>
        </replicated-cache>
    </cache-container>
    <cache-container name="web" default-cache="dist" module="org.wildfly.clustering.web.infinispan">
        <transport lock-timeout="60000"/>
        <distributed-cache name="dist">
            <locking isolation="REPEATABLE_READ"/>
            <transaction mode="BATCH"/>
            <file-store/>
        </distributed-cache>
    </cache-container>
    <cache-container name="ejb" aliases="sfsb" default-cache="dist" module="org.wildfly.clustering.ejb.infinispan">
        <transport lock-timeout="60000"/>
        <distributed-cache name="dist">
            <locking isolation="REPEATABLE_READ"/>
            <transaction mode="BATCH"/>
            <file-store/>
        </distributed-cache>
    </cache-container>
    <cache-container name="hibernate" module="org.infinispan.hibernate-cache">
        <transport lock-timeout="60000"/>
        <local-cache name="local-query">
            <object-memory size="10000"/>
            <expiration max-idle="100000"/>
        </local-cache>
        <invalidation-cache name="entity">
            <transaction mode="NON_XA"/>
            <object-memory size="10000"/>
            <expiration max-idle="100000"/>
        </invalidation-cache>
        <replicated-cache name="timestamps"/>
    </cache-container>
</subsystem>

请注意,与默认的standalone-ha.xml配置文件相比,大部分缓存配置都没有改变。我在这里所做的更改是将以下缓存更改为local并将它们指向我的远程Infinispan集群:
  • sessions
  • authenticationSessions
  • offlineSessions
  • clientSessions
  • offlineClientSessions
  • loginFailures
  • actionTokens
  • work
这是我remote-cache服务器的配置:
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
    <!-- Default socket bindings from standalone-ha.xml are not listed here for brevity -->
    <outbound-socket-binding name="remote-cache">
        <remote-destination host="${env.INFINISPAN_HOST}" port="${remote.cache.port:11222}"/>
    </outbound-socket-binding>
</socket-binding-group>

以下是我在Infinispan方面的缓存配置:

<subsystem xmlns="urn:infinispan:server:core:9.4" default-cache-container="clustered">
    <cache-container name="clustered" default-cache="default">
        <transport lock-timeout="60000"/>
        <global-state/>
        <replicated-cache-configuration name="replicated-keycloak" mode="SYNC">
            <locking acquire-timeout="3000" />
        </replicated-cache-configuration>
        <replicated-cache name="work" configuration="replicated-keycloak"/>
        <replicated-cache name="sessions" configuration="replicated-keycloak"/>
        <replicated-cache name="authenticationSessions" configuration="replicated-keycloak"/>
        <replicated-cache name="clientSessions" configuration="replicated-keycloak"/>
        <replicated-cache name="offlineSessions" configuration="replicated-keycloak"/>
        <replicated-cache name="offlineClientSessions" configuration="replicated-keycloak"/>
        <replicated-cache name="actionTokens" configuration="replicated-keycloak"/>
        <replicated-cache name="loginFailures" configuration="replicated-keycloak"/>
    </cache-container>
</subsystem>

我认为我对本地缓存与远程存储如何工作有一些错误的假设,希望有人能为我澄清。我的目的是使Infinispan集群成为Keycloak所有缓存的真正数据源。通过将每个缓存设置为本地,我认为数据会通过Infinispan集群复制到每个Keycloak节点,这样在keycloak-0上对本地authenticationSessions缓存的写入将同步持久化到通过Infinispan集群连接的keycloak-1上。
我认为正在发生的是,在Keycloak上对本地缓存的写操作与将该值持久化到远程Infinispan集群不同步。换句话说,当对authenticationSessions缓存执行写入操作时,它并不会阻塞等待该值被写入Infinispan集群,因此在另一个Keycloak节点上立即读取此数据会导致本地和Infinispan集群中的缓存未命中。
我正在寻求一些帮助,以确定当前配置为什么会导致此问题,并且需要对remote-store的行为进行澄清-是否有一种方法可以使对由remote-store支持的本地缓存的写入是同步的?如果没有,有没有更好的方法来实现我在这里尝试完成的任务?
以下是其他一些可能相关的细节:
  • Keycloak和Infinispan都部署在Kubernetes集群的同一命名空间中。
  • 我正在使用KUBE_PING进行JGroups发现。
  • 使用Infinispan控制台,我能够验证所有缓存都复制到了所有Infinispan节点,并且它们都有一定数量的条目 - 它们并没有完全未使用。
  • 如果我在一个Keycloak节点上添加一个新的realm,它会成功显示在其他Keycloak节点上,这让我相信work缓存正在在所有Keycloak节点之间传播。
  • 如果我登录到一个Keycloak节点,我的会话会保留在其他Keycloak节点上,这让我相信与会话相关的缓存正在在所有Keycloak节点之间传播。
  • 我正在为Keycloak使用粘性会话作为临时解决方案,但我相信修复这些潜在的缓存问题是更持久的解决方案。

提前致谢!


嗨,Michael,你能放置Keycloak和Infinispan日志吗?它们是否连接并正确注册? - Ariel Carrera
1
嗨@ArielCarrera,这是其中一个keycloak节点的日志:https://gist.github.com/mrparkers/dd65e969b2a364aea589e7b431798d47,这是其中一个infinispan节点的日志:https://gist.github.com/mrparkers/fd52fec72fda15cfdb5351b6109d9960我几乎有100%的信心,节点正在相互发现,并且正在使用远程缓存,但我不确定“authenticatedSessions”缓存是否被复制得像我希望的那样快。 - Michael Parker
2个回答

18

当您配置Keycloak集群时,请注意以下几点。

在谈论“无限重定向”的主题时,我曾经在开发环境中遇到过类似的问题。虽然Keycloak团队已经修复了与无限循环相关的若干个错误(例如KEYCLOAK-5856KEYCLOAK-5022KEYCLOAK-4717KEYCLOAK-4552KEYCLOAK-3878),但有时这是由于配置问题造成的。

如果站点是HTTPS,则要检查是否也通过HTTPS访问Keycloak服务器。

我记得当Keycloak放置在HTTPS反向代理后并且所需的头部未传递到Keycloak时,我也遇到了类似的无限循环问题(头X-FOWARDED...)。解决方法是正确设置环境。当集群中的节点发现不工作正确(JGroups)时,也可能出现类似的问题。

关于错误消息“expired_code”,我会验证每个节点的时钟是否同步,因为这可能会导致此类过期的令牌/代码错误。

现在更好地了解您的配置后,使用“local-cache”模式与指向infinispan集群的远程存储似乎并不不合适。虽然通常情况下,共享存储(如远程缓存)通常与无效缓存一起使用,其中通过集群避免复制完整数据(请参见可应用于此处的评论https://developer.jboss.org/message/986847#986847),但是与分布式或无效化缓存相比可能没有太大的差异。

我认为一个带有远程存储的分布式缓存会更适用(或者使用“失效缓存”来避免将大量数据复制到所有者身上),但是我并不能确定“本地缓存”与远程存储(共享)如何配合工作,因为我从未尝试过这种配置。首先,我会选择测试分布式缓存或失效缓存,根据其对已清除/失效数据的处理方式来决定。通常,本地缓存不会与集群中的其他远程节点同步。如果这种实现在内存中保留本地映射,即使远程存储中的数据被修改,在某些情况下也可能不会反映这些变化。

回到您的配置主题,除了复制缓存有一些限制并且通常比仅将数据复制到定义的所有者的分布式缓存慢一些(复制缓存在所有节点中都写入)。还有一种称为散布式缓存的变体,其效果更好,但例如缺乏事务支持(您可以在此处查看比较图表:https://infinispan.org/docs/stable/user_guide/user_guide.html#which_cache_mode_should_i_use)。由于需要发送的复制消息数量,因此复制通常仅在小型集群(8或10个服务器以下)中表现良好。分布式缓存允许Infinispan通过按条目定义一定数量的副本来实现线性扩展。

选择您尝试构建的这种类型的配置而不是类似于Keycloak提出的配置(standalone-ha.xml)的主要原因在于,当您需要独立扩展应用程序的Infinispan集群或使用Infinispan作为持久存储时,可以实现这样的需求。

我将解释Keycloak如何管理其缓存以及它基本上将其分成两组或三组,以便您更好地理解所需的配置。

通常,要在集群中配置Keycloak,只需像使用传统Wildfly实例一样启动和配置Keycloak HA模式即可。如果观察Keycloak安装中附带的standalone.xml和standalone-ha.xml之间的差异,可以注意到基本上添加了对“Jgroups”、“modcluster”的支持,并且缓存在Wildfly / Keycloak(HA)节点之间分布(先前为本地)。

详细说明:

  • jgroups子系统被添加,它将负责连接群集节点并在群集中执行消息传递/通信。JGroups提供网络通信功能、可靠的通信和其他功能,如节点发现、点对点通信、多播通信、故障检测和群集节点之间的数据传输。
  • EJB3缓存从简单缓存(在本地内存中没有事务处理)变为分布式缓存。但是,根据我扩展这个项目的经验,我可以确保Keycloak项目不需要使用EJB3。
  • 缓存:"realms"、"users"、"authorization"和"keys"保留在本地,因为它们只用于减少数据库负载。
  • 缓存:"work"变成了复制缓存,因为Keycloak使用它来通知群集节点必须逐出/使其无效的缓存条目,因为它的状态已经被修改。
  • 缓存" sessions "、" authenticationSessions "、" offlineSessions "、" clientSessions "、" offlineSessions "、" loginFailures "和" actionTokens "变为分布式,因为它们比复制缓存性能更好(见https://infinispan.org/docs/stable/user_guide/user_guide.html#which_cache_mode_should_i_use),因为你只需要将数据复制到所有的owner节点。
  • Keycloak对其默认HA配置提出的其他更改是将“web”和“ejb”(以及以上)缓存容器分发,以及将“hibernate”缓存更改为“invalidation-cache”(类似于本地缓存但带有失效同步)。

我认为你的缓存配置应该定义为"分布式缓存",例如" sessions "、" authenticationSessions "、" offlineSessions "、" clientSessions "、" offlineClientSessions "、" loginFailures "和" actionTokens "(而不是"本地缓存")。然而,由于你使用了远程共享存储,你应该进行测试以查看它的工作情况,正如我之前所说的。

另外,名为"work"的缓存应该是"复制缓存",而其他缓存("keys"、"authorization"、"realms" 和 "users")应该被定义为"本地缓存"。

在你的Infinispan集群中,你可以将其定义为“分布式缓存”(或“复制缓存”)。

记住:

在复制缓存中,集群中的所有节点都保存所有的键,即如果一个键存在于一个节点上,则它也存在于所有其他节点上。在分布式缓存中,保留一定数量的副本以提供冗余和容错能力,但通常远少于集群中的节点数。分布式缓存比复制缓存提供了更高程度的可扩展性。分布式缓存还能够透明地在整个集群中定位键,并提供用于快速读取远程存储的状态的L1缓存。您可以在相关的用户指南章节中阅读更多内容。

Infinispan文档参考:缓存模式

正如Keycloak(6.0)文档所说:

Keycloak有两种类型的缓存。一种缓存位于数据库前面,以减少对数据库的负载,并通过将数据保存在内存中来降低总体响应时间。该类型的缓存用于保存领域、客户端、角色和用户元数据,这是一种本地缓存。即使您与更多的Keycloak服务器集群在一起,本地缓存也不会使用复制。相反,它们仅在本地保留副本,如果条目被更新,则发送一个失效消息到集群的其余部分并将其驱逐。还有单独的复制缓存工作,其任务是向整个集群发送失效消息,通知哪些条目应从本地缓存中删除。这极大地减少了网络流量,使事情更加高效,并避免在网络上传输敏感元数据。
第二种缓存处理管理用户会话、脱机令牌和跟踪登录失败,以便服务器可以检测密码钓鱼和其他攻击。这些缓存中保存的数据是临时的,仅在内存中,但可能在集群之间进行复制。
文档参考:cache configuration 如果您想阅读另一篇好的文档,可以查看“跨数据中心”部分(cross-dc mode),特别是“3.4.6 Infinispan cache”(infinispan cache)部分。
我使用Keycloak 6.0.1和Infinispan 9.4.11.Final进行尝试,这是我的测试配置(基于standalone-ha.xml文件)。 Keycloak infinispan subsystem:
    <subsystem xmlns="urn:jboss:domain:infinispan:8.0">
        <cache-container name="keycloak" module="org.keycloak.keycloak-model-infinispan">
            <transport lock-timeout="60000"/>
            <local-cache name="realms">
                <object-memory size="10000"/>
            </local-cache>
            <local-cache name="users">
                <object-memory size="10000"/>
            </local-cache>
            <distributed-cache name="sessions" owners="1" remote-timeout="30000">
                <remote-store cache="sessions" remote-servers="remote-cache" socket-timeout="60000" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                true
                </property>
                <property name="marshaller">
org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
                </remote-store>
                </distributed-cache>
            <distributed-cache name="authenticationSessions" owners="1" remote-timeout="30000">
                <remote-store cache="authenticationSessions" remote-servers="remote-cache" socket-timeout="60000" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                true
                </property>
                <property name="marshaller">
org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
                </remote-store>
                </distributed-cache>
            <distributed-cache name="offlineSessions" owners="1" remote-timeout="30000">
                <remote-store cache="offlineSessions" remote-servers="remote-cache" socket-timeout="60000" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
true
                </property>
                <property name="marshaller">
org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
                </remote-store>
                </distributed-cache>
            <distributed-cache name="clientSessions" owners="1" remote-timeout="30000">
                <remote-store cache="clientSessions" remote-servers="remote-cache" socket-timeout="60000" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
true
                </property>
                <property name="marshaller">
org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
                </remote-store>
                </distributed-cache>
            <distributed-cache name="offlineClientSessions" owners="1" remote-timeout="30000">
                <remote-store cache="offlineClientSessions" remote-servers="remote-cache" socket-timeout="60000" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                true
                </property>
                <property name="marshaller">
org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
                </remote-store>
                </distributed-cache>
            <distributed-cache name="loginFailures" owners="1" remote-timeout="30000">
                <remote-store cache="loginFailures" remote-servers="remote-cache" socket-timeout="60000" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                true
                </property>
                <property name="marshaller">
org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
                </remote-store>
                </distributed-cache>
            <replicated-cache name="work"/>
            <local-cache name="authorization">
                <object-memory size="10000"/>
            </local-cache>
            <local-cache name="keys">
                <object-memory size="1000"/>
                <expiration max-idle="3600000"/>
            </local-cache>
            <distributed-cache name="actionTokens" owners="1" remote-timeout="30000">
                <remote-store cache="actionTokens" remote-servers="remote-cache" socket-timeout="60000" fetch-state="false" passivation="false" preload="false" purge="false" shared="true">
                <property name="rawValues">
                true
                </property>
                <property name="marshaller">
org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
                </property>
                </remote-store>
                <object-memory size="-1"/>
                <expiration max-idle="-1" interval="300000"/>
            </distributed-cache>
         </cache-container>

Keycloak套接字绑定:

<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
    <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
    <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
    <socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
    <socket-binding name="http" port="${jboss.http.port:8080}"/>
    <socket-binding name="https" port="${jboss.https.port:8443}"/>
    <socket-binding name="jgroups-mping" interface="private" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
    <socket-binding name="jgroups-tcp" interface="private" port="7600"/>
    <socket-binding name="jgroups-udp" interface="private" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
    <socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
    <socket-binding name="txn-recovery-environment" port="4712"/>
    <socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="remote-cache">
<remote-destination host="my-server-domain.com" port="11222"/>  
</outbound-socket-binding>
    <outbound-socket-binding name="mail-smtp">
        <remote-destination host="localhost" port="25"/>
    </outbound-socket-binding>
</socket-binding-group>

Infinispan集群配置:

<subsystem xmlns="urn:infinispan:server:core:9.4" default-cache-container="clustered">
    <cache-container name="clustered" default-cache="default" statistics="true">
        <transport lock-timeout="60000"/>
        <global-state/>
        <distributed-cache-configuration name="transactional">
            <transaction mode="NON_XA" locking="PESSIMISTIC"/>
        </distributed-cache-configuration>
        <distributed-cache-configuration name="async" mode="ASYNC"/>
        <replicated-cache-configuration name="replicated"/>
        <distributed-cache-configuration name="persistent-file-store">
            <persistence>
                <file-store shared="false" fetch-state="true"/>
            </persistence>
        </distributed-cache-configuration>
        <distributed-cache-configuration name="indexed">
            <indexing index="LOCAL" auto-config="true"/>
        </distributed-cache-configuration>
        <distributed-cache-configuration name="memory-bounded">
            <memory>
                <binary size="10000000" eviction="MEMORY"/>
            </memory>
        </distributed-cache-configuration>
        <distributed-cache-configuration name="persistent-file-store-passivation">
            <memory>
                <object size="10000"/>
            </memory>
            <persistence passivation="true">
                <file-store shared="false" fetch-state="true">
                    <write-behind modification-queue-size="1024" thread-pool-size="1"/>
                </file-store>
            </persistence>
        </distributed-cache-configuration>
        <distributed-cache-configuration name="persistent-file-store-write-behind">
            <persistence>
                <file-store shared="false" fetch-state="true">
                    <write-behind modification-queue-size="1024" thread-pool-size="1"/>
                </file-store>
            </persistence>
        </distributed-cache-configuration>
        <distributed-cache-configuration name="persistent-rocksdb-store">
            <persistence>
                <rocksdb-store shared="false" fetch-state="true"/>
            </persistence>
        </distributed-cache-configuration>
        <distributed-cache-configuration name="persistent-jdbc-string-keyed">
            <persistence>
                <string-keyed-jdbc-store datasource="java:jboss/datasources/ExampleDS" fetch-state="true" preload="false" purge="false" shared="false">
                    <string-keyed-table prefix="ISPN">
                        <id-column name="id" type="VARCHAR"/>
                        <data-column name="datum" type="BINARY"/>
                        <timestamp-column name="version" type="BIGINT"/>
                    </string-keyed-table>
                    <write-behind modification-queue-size="1024" thread-pool-size="1"/>
                </string-keyed-jdbc-store>
            </persistence>
        </distributed-cache-configuration>
        <distributed-cache name="default"/>
        <replicated-cache name="repl" configuration="replicated"/>
        <replicated-cache name="work" configuration="replicated"/>
        <replicated-cache name="sessions" configuration="replicated"/>
        <replicated-cache name="authenticationSessions" configuration="replicated"/>
        <replicated-cache name="clientSessions" configuration="replicated"/>
        <replicated-cache name="offlineSessions" configuration="replicated"/>
        <replicated-cache name="offlineClientSessions" configuration="replicated"/>
        <replicated-cache name="actionTokens" configuration="replicated"/>
        <replicated-cache name="loginFailures" configuration="replicated"/>
    </cache-container>
</subsystem>

附言:将属性“所有者”从1更改为您喜欢的值。

我希望有所帮助。


谢谢您的回复!您能帮我理解使用远程存储器来复制缓存的行为吗?也就是说,如果缓存work(例如)在所有Keycloak节点上都被复制,并且它有一个指向专用infinispan集群的远程存储器,该集群也在其所有节点上进行了复制,那么当节点启动、关闭等时,它会如何表现?在实现此功能时,是否应担心竞争条件? - Michael Parker
嗨@MichaelParker,也许我误解了您尝试进行的配置,我将尝试重写答案并澄清如果我想更改集群配置,则我将尝试在压力测试中测试哪种配置。目前,我有一个使用本地、分布式和复制缓存的KC集群,仅处于HA模式(没有专用的Infinispan集群)。 - Ariel Carrera
谢谢你的帮助!你更新后的答案包含了我正在寻找的信息。 - Michael Parker
我将尝试使用您提供的共享远程存储信息来推进无效缓存。如果这不起作用,我认为使用复制缓存配置可能已经足够了,因为我的集群相对较小。 - Michael Parker
好的,迈克尔,我们来做吧。也许我可以在接下来的几周尝试一些测试。让我们保持联系。 - Ariel Carrera
显示剩余2条评论

1
很棒的交流,大家都有着与Michael相同的假设,我配置了我的本地缓存使用远程存储,并期望密钥始终从远程存储中读写,但显然这不是它的工作方式。
可惜在所有的交流中,我找不到原因,为什么我们不能将本地infinispan配置为仅作为远程infinispan的代理,以保持这些实例无状态,并且更容易重新部署。

我认为@ariel-carrera已经回答了这个问题。通常,本地缓存不会与集群中的其他远程节点同步。如果这种实现在内存中保留了本地映射,则即使远程存储中的数据被修改,在某些情况下也可能不会反映这些更改。 - Madhusudanan K K C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接