Keycloak - Infinispan Redis 缓存存储

15

目前正在以standalone-ha模式设置Keycloak集群,以便能够在Docker Swarm上运行。在Keycloak中,用户会话存储在嵌入式Infinispan存储器中,可以将Infinispan配置为跨集群的分布式缓存。

我还将所有者设置为2,但问题是...在缩减规模期间,如果缓存所包含的两个所有者都被杀死,则存在用户会话丢失的可能性。

我也阅读了Infinispan Redis缓存存储的相关内容,但我不确定如何配置它。

问题1: 是否可以配置Keycloak Infinispan使用Redis存储?

问题2: 如果不可能,有没有一种方法可以克服这个问题?

任何建议都将很有帮助。


您是否可以将缩减策略配置为仅每次终止一个服务器?Infinispan 应该能够检测到丢失的服务器并在其余节点上重新平衡在该服务器上缓存的会话。 - shonky linux user
当您使用Swarm时,这可能会引起您的兴趣:https://wildfly-swarm.gitbooks.io/wildfly-swarm-users-guide/content/advanced/jgroups.html - Yves Martin
3个回答

8
由于此PR https://github.com/keycloak/keycloak/commit/056ba75a72b1595ca9fa471f5693201fd5b2c7ae,默认情况下(Keycloak最新版本6.0.1),使用InfinispanChangelogBasedTransaction.java的Infinispan Connection SPI具有非常特殊的CacheDecorator.java用途,将skipCacheStore。这意味着无论您是否配置具有持久性的存储,该存储都将被忽略。
为了实现您想要的内容,除了配置存储之外,还需要自定义这里的大多数SPI,以确保Keycloak将使用缓存存储。
这也不容易,因为该过程涉及到许多技巧,例如,由于Keycloak使用Jboss的Marshaller,如果您自定义这些SPI,则必须带来大部分org.keycloak.models.sessions.infinispan包并注册您的模块,以确保Wildfly能够看到实体进行编组。
另一件事是,你应该使用Redis将大多数缓存指向一个公共数据库,除了authenticationSessions不能与sessions位于同一个数据库中,否则会出现冲突,例如RootAuthenticationSesssionEntity被发现但预期为SessionEntityWrapper。
总之,这个过程是痛苦的,但如果您想尝试并完成它,这是我实现它的方法:
  • 引入自定义InfinispanConnectionProviderFactory以完全能够使用infinispan配置,然后像下面这样配置我的容器:
private Configuration getRedisConfiguration(int database) {
    ConfigurationBuilder cb = new ConfigurationBuilder();
    cb.persistence()
      .passivation(false)
      .addStore(RedisCacheStoreConfigurationBuilder.class)
      .ignoreModifications(false)
      .fetchPersistentState(false)
      .purgeOnStartup(false)
      .preload(false)
      .shared(true)
      .addProperty("host", System.getenv("REDIS_HOST"))
      .addProperty("port", System.getenv("REDIS_PORT"))
      .addProperty("database", String.valueOf(database));

    return cb.build();
  }

您所看到的 RedisCacheStoreConfigurationBuilder 基本上是原始存储的简化版本,但我不需要Sentinel或Server模式,我只想连接到主机、端口和数据库。

然后,我基本上复制了 org.keycloak.models.sessions.infinispan ,删除了与缓存删除相关的所有内容,并且不使用装饰器使用缓存而是跳过缓存存储。

如果我能提供帮助,请告诉我,我将准备一篇更详细的文章,解释如何执行此操作,还涉及一个包含我所说的代码的存储库。 如果有人仍在尝试,请告诉我更多信息。


1
你有详细步骤的文章吗?我很好奇如何使用它。因为我想知道用户会话何时过期。 - amj
有一个后台任务在运行,用于删除过期的会话。在你拥有的模型的一个接口中,你可以实现 removeExpiredSessions 方法,该方法将被后台线程调用,你可以配置它的运行频率。 - Guilherme Oliveira
如果我们提供会话认证类来存储在Redis中,而不是触碰缓存类,会发生什么? - Kamyar

2
当期望动态地扩展大型系统时,有望避免在配置中注册可用节点列表的限制。因此,Redis节点发现在这里是有益的。
Infinispan本身支持Redis存储作为扩展,实现了SPI并添加了XML实体以简化配置: 但是,WildFly infinispan子系统尚未支持此扩展,因为Keycloak依赖于WildFly。
因此,我期望完成以下任务,以使Infinispan Redis Store可用于WildFly和Keycloak: 工作正在进行中,可能会发布代码和配置。

顺便说一下,使用JGroups“IP多播”地址配置Infinispan的standalone-ha预计实现动态集群复制,无需Redis。 - Yves Martin
我不知道wildfly在使用这些存储方面是否有任何更新。另一种配置keycloak使用HotRod上的远程infinispan实例,然后让infinispan集群基本上代理到redis作为“缓存存储”,我自己没有做过这个。 - Phillip Fleischer
@YvesMartin 感谢您的解释。请问您最终是否在某个地方发布了博客文章和示例代码/配置? - Sayo Oladeji

1

为什么要在Infinispan后面使用Redis存储?

一个更简单的解决方案可能是配置文件或共享数据库持久化。对于这样的缓存用例,基于文件的持久性可能已经足够了。请参见此处中有关使用基于文件的持久性配置Infinispan的示例。或者,您可以将其存储到共享数据库中,例如Postgresql,但这需要更多的设置(请参见ref card的示例)。


“True但是如果你想要动态扩展,在配置/注册(无论是针对infinispan还是postgresql)可能很长的服务器节点清单时,会受到很大的限制。采用Redis存储作为infinispan后端,并放在动态负载均衡器后面,在扩展时避免了任何维护。(我们部署在Openshift/Kubernetes上)。” - Yves Martin
如果使用远程Infinispan客户端,它们会获取初始的Infinispan服务器列表,然后动态地发现节点。连接Infinispan客户端和服务器的二进制协议处理拓扑信息。 - Galder Zamarreño

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