Keycloak - Infinispan Redis 缓存存储
Posted
技术标签:
【中文标题】Keycloak - Infinispan Redis 缓存存储【英文标题】:Keycloak - Infinispan Redis cache store 【发布时间】:2018-02-03 12:50:30 【问题描述】:目前在standalone-ha模式下设置一个keycloak集群,以便能够在docker swarm上运行。在 keycloak 中,用户会话被缓存在嵌入式 infinispan 存储中,并且 infinispan 可以配置为跨集群的分布式缓存。
我也将所有者设置为 2,但问题是.. 在缩减期间,用户会话可能会丢失,如果包含缓存的所有者在缩减期间都被杀死-下。
我还阅读了有关 Infinispan Redis 缓存存储的信息,但我不确定如何配置它。
问题 1: 是否可以将 Keycloak Infinispan 配置为使用 Redis 存储?
问题 2: 如果这是不可能的,有没有办法可以克服这个问题?
任何建议都会有所帮助。
【问题讨论】:
您能否将缩减策略配置为一次仅终止一台服务器? Infinispan 应该检测到丢失的服务器,并在剩余节点上重新平衡缓存在该服务器上的会话。 当你使用 Swarm 时,可能会感兴趣:wildfly-swarm.gitbooks.io/wildfly-swarm-users-guide/content/… 【参考方案1】:由于这个 PR https://github.com/keycloak/keycloak/commit/056ba75a72b1595ca9fa471f5693201fd5b2c7ae 默认情况下(Keycloak 最新版本 6.0.1),使用 InfinispanChangelogBasedTransaction.java
的 Infinispan Connection SPI
有一个非常特殊的使用 CacheDecorator.java
将 skipCacheStore
。这意味着无论您是否配置具有持久性的存储,该存储都将被忽略。
为了实现您想要的,除了配置存储之外,您还必须在此处自定义大部分 SPI https://github.com/keycloak/keycloak/tree/master/model/infinispan/src/main/resources/META-INF/services 以确保 Keycloak 将使用缓存存储。
这也不是一件容易的事,因为这个过程涉及很多好处,例如,由于 Keycloak 使用 Jboss 的 Marshaller,如果你自定义这个 SPI,你将不得不带上大部分 org.keycloak.models.sessions.infinispan
包并注册您的模块以确保 Wildfly 能够看到要编组的实体。
另外一点是,你应该在Redis中配置大部分缓存指向一个公共数据库,除了authenticationSessions
不能和sessions
在同一个数据库中,否则会出现类似@的冲突987654330@ 已找到,但应为 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
基本上是原始存储的精简版本,但我不需要哨兵或服务器模式,我只想连接到主机、端口和数据库。
然后我基本上复制了org.keycloak.models.sessions.infinispan
,删除了与删除缓存相关的所有内容,而不是正常使用没有装饰器的缓存来跳过CacheStore。
如果我能提供帮助,请告诉我,我会准备一篇文章,详细说明如何执行此操作,其中还包括一个包含我正在谈论的代码的存储库。如果有人还在尝试这个,请告诉我更多信息。
【讨论】:
你有帖子吗,有详细的步骤。我很好奇,如何使用它。这是因为我想知道用户会话何时过期。 有一个后台作业正在运行以删除过期的会话。你有removeExpiredSessions
方法要实现的模型的接口之一,将由这个后台线程调用,你可以配置它运行的频率..
如果我们提供会话认证类存储在redis中并且不接触缓存类呢?【参考方案2】:
当期望动态扩展大型系统时,应避免在配置中注册可用节点列表的这种约束。所以 Redis 节点发现在这里是一个好处。
Infinispan 本身支持 Redis Store 作为实现 SPI 和添加 XML 实体以简化配置的扩展:
http://infinispan.org/docs/cachestores/redis/
https://github.com/infinispan/infinispan-cachestore-redis
http://infinispan.org/docs/stable/user_guide/user_guide.html#custom_cache_stores
但 WildFly infinispan 子系统(尚)不支持此扩展 - 因为 Keycloak 依赖于 WildFly。
因此,我希望通过以下任务使 Infinispan Redis Store 可用于 WildFly 和 Keycloak:
为 infinispam redis 存储 jar 创建 jboss 模块 - 参见 modules/system/layers/base/org/infinispan/
创建一个“自定义缓存存储”工厂,能够从 WildFly 配置键/值属性实例化 Redis 存储对象(存储、服务器和连接池)。这也必须作为 jboss 模块添加到 WildFly 中
使用 WildFly infinispan 子系统 "local-cache" "custom" 来配置这个工厂的属性 class
和 properties
: https://wildscribe.github.io/WildFly/11.0/subsystem/infinispan/cache-container/local-cache/store/custom/index.html
工作正在进行中,可能会发布代码和配置。
【讨论】:
对了,Infinispan配置了JGroups“IP多播”地址的standalone-ha,预计可以实现动态集群复制,不需要Redis... 我不知道wildfly是否有任何关于这些商店使用情况的更新。另一种配置 keycloak 以通过 HotRod 使用远程 infinispan 实例,然后让 infinispan 集群基本上代理到 redis 作为“缓存存储”的选项,我自己没有这样做。 @YvesMartin 感谢您的解释。请问您最终是否在某处发布了博客文章和示例代码/配置?【参考方案3】:在 Infinispan 后面使用 Redis 存储有什么特别的原因吗?
一个更简单的解决方案可能是将持久性配置到文件或共享数据库。对于这样的缓存用例,基于文件的持久性可能就足够了。请参阅here,例如使用基于文件的持久性配置 Infinispan。或者,您可以存储到共享数据库,例如Postgresql,但这需要更多设置(例如,参见ref card)。
【讨论】:
是的,但如果您想动态扩展,必须配置/注册一个(可能很长)服务器节点列表(对于 infinispan 或 postgresql)是一个很大的限制。将 Redis Store 作为动态负载均衡器后面的 infinispan 后端可避免在扩展时进行任何维护。 (我们部署在 Openshift / Kubernetes) 如果使用远程 Infinispan 客户端,这些客户端会获取初始 Infinispan 服务器列表,然后动态发现节点。链接 Infinispan 客户端和服务器的二进制协议处理拓扑信息。以上是关于Keycloak - Infinispan Redis 缓存存储的主要内容,如果未能解决你的问题,请参考以下文章
Amazon ECS 上的 Keycloak 集群失败(org.infinispan.commons.CacheException:缓存的初始状态传输超时)
如何在一个 Kubernetes 集群中的命名空间之间隔离 Keycloak Infinispan,以防止 KC pod 相互发现和同步