当前位置: 首页 > news >正文

keycloak~分布式部署中会话过期清理机制

Keycloak 分布式部署中会话过期清理机制

在 Keycloak 分布式部署(使用外部独立部署的 Infinispan)的架构下,sessionsclientSessions 的过期清理涉及两种不同的部署模式,机制略有不同:

架构模式 1:Embedded + Remote Store(嵌入式缓存 + 远程存储)

这种模式下,Keycloak 节点有本地嵌入式缓存,同时配置了远程存储(Remote Store)连接到外部 Infinispan 集群。

/*** @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>*/
@ClientListener
public class RemoteCacheSessionListener<K, V extends SessionEntity>  {

清理机制:

  1. 本地缓存自动过期
    • 当会话数据写入本地嵌入式缓存(DefaultSegmentedDataContainer)时,会同时设置 lifespanmaxIdle 参数
    • Infinispan 的内置过期机制会自动清除过期条目

图片

  1. 远程缓存事件同步
    • RemoteCacheSessionListener 通过 Hot Rod Client Listener 机制监听远程缓存事件
    • 当远程 Infinispan 中条目被删除时,会触发 @ClientCacheEntryRemoved 事件:
    @ClientCacheEntryRemovedpublic void removed(ClientCacheEntryRemovedEvent event) {K key = (K) event.getKey();if (shouldUpdateLocalCache(event.getType(), key, event.isCommandRetried())) {this.executor.submit(event, () -> {// We received event from remoteCache, so we won't update it backcache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD, Flag.IGNORE_RETURN_VALUES).remove(key);});}}
  1. 重要限制
    • Infinispan 不发送过期事件(Expiration Event)给 Hot Rod 客户端监听器!
    • 远程 Infinispan 中的条目过期时,不会主动通知 Keycloak 节点
    • 本地缓存的清理完全依赖于本地 Infinispan 的自动过期机制

架构模式 2:Remote Only(纯远程模式)

这种模式下,Keycloak 不维护本地会话缓存,所有会话数据都直接存储在外部 Infinispan 集群中。

    @Overridepublic void removeAllExpired() {//rely on Infinispan expiration}@Overridepublic void removeExpired(RealmModel realm) {//rely on Infinispan expiration}

清理机制

  • 完全依赖远程 Infinispan 的过期机制
  • Keycloak 本地 JVM 中没有 DefaultSegmentedDataContainer,因为不使用嵌入式缓存
  • 所有读取操作直接访问远程缓存,过期数据自然不会被读取到

关键代码:过期时间计算

无论哪种模式,会话的过期时间都通过 SessionTimeouts 计算:

    public static long getUserSessionLifespanMs(RealmModel realm, ClientModel client, UserSessionEntity userSessionEntity) {return getUserSessionLifespanMs(realm, false, userSessionEntity.isRememberMe(), userSessionEntity.getStarted());}public static long getUserSessionLifespanMs(RealmModel realm, boolean offline, boolean rememberMe, int started) {long lifespan = SessionExpirationUtils.calculateUserSessionMaxLifespanTimestamp(offline, rememberMe,TimeUnit.SECONDS.toMillis(started), realm);if (offline && lifespan == IMMORTAL_FLAG) {return IMMORTAL_FLAG;}lifespan = lifespan - Time.currentTimeMillis();if (lifespan <= 0) {return ENTRY_EXPIRED_FLAG;}return lifespan;}

总结:本地 JVM 中 DefaultSegmentedDataContainer 对象的清理方式

场景 清理机制
本地条目自然过期 Infinispan 嵌入式缓存的内置过期 Reaper 线程自动清理
远程条目被删除 通过 RemoteCacheSessionListener@ClientCacheEntryRemoved 事件同步删除本地条目
远程条目自然过期 不会主动通知!本地条目依赖自身的过期时间自动失效
Failover 事件 触发 onFailover 回调,清空整个本地缓存(ispnCache::clear)以保证一致性

潜在问题

由于远程 Infinispan 的过期事件不会通知本地缓存,在以下情况下可能存在短暂的数据不一致

  1. 远程条目已过期被清除
  2. 但本地缓存的过期时间还没到
  3. 此时本地可能返回一个"幽灵会话"

Keycloak 的解决方案

  • 在每次从本地缓存获取会话时,都会检查 Expiration.isExpired()
  • 如果计算出的过期时间已经过了,即使缓存条目存在也会被视为无效
    public boolean isExpired() {return maxIdle == SessionTimeouts.ENTRY_EXPIRED_FLAG || lifespan == SessionTimeouts.ENTRY_EXPIRED_FLAG;}
/*** @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>*/
@ClientListener
public class RemoteCacheSessionListener<K, V extends SessionEntity>  {
    @ClientCacheEntryRemovedpublic void removed(ClientCacheEntryRemovedEvent event) {K key = (K) event.getKey();if (shouldUpdateLocalCache(event.getType(), key, event.isCommandRetried())) {this.executor.submit(event, () -> {// We received event from remoteCache, so we won't update it backcache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD, Flag.IGNORE_RETURN_VALUES).remove(key);});}}
    @Overridepublic void removeAllExpired() {//rely on Infinispan expiration}@Overridepublic void removeExpired(RealmModel realm) {//rely on Infinispan expiration}
    public static long getUserSessionLifespanMs(RealmModel realm, ClientModel client, UserSessionEntity userSessionEntity) {return getUserSessionLifespanMs(realm, false, userSessionEntity.isRememberMe(), userSessionEntity.getStarted());}public static long getUserSessionLifespanMs(RealmModel realm, boolean offline, boolean rememberMe, int started) {long lifespan = SessionExpirationUtils.calculateUserSessionMaxLifespanTimestamp(offline, rememberMe,TimeUnit.SECONDS.toMillis(started), realm);if (offline && lifespan == IMMORTAL_FLAG) {return IMMORTAL_FLAG;}lifespan = lifespan - Time.currentTimeMillis();if (lifespan <= 0) {return ENTRY_EXPIRED_FLAG;}return lifespan;}
    public boolean isExpired() {return maxIdle == SessionTimeouts.ENTRY_EXPIRED_FLAG || lifespan == SessionTimeouts.ENTRY_EXPIRED_FLAG;}
http://www.jsqmd.com/news/321464/

相关文章:

  • 汽车制造领域,asp.net如何实现文件夹上传的自动化流程?
  • 2026 年 GEO 优化服务商深度选型:从技术到效果的长期价值挖掘指南
  • 2026主动健康监测养老机器人技术解析与主流产品评测
  • 2026年8款降AI率工具亲测推荐:知网维普双平台实测通过
  • 周六福项链质量如何?推荐6款性价比高,口碑公认!
  • 基于SSM架构的农产品溯源管理系统
  • 贯流风扇靠谱供应商价格如何,选购要点分享
  • Google 打击恶意住宅代理网络:什么才是合规可用的代理服务设施?
  • 2026 年腾讯元宝 GEO 优化深度解析:从技术到效果的聚焦效果服务商甄选指南
  • 2026年代理IP公司
  • 深聊质量好的离心风扇品牌,上海神逵智能上榜
  • 【免费下载】中国农村统计年鉴2000-2024
  • 基于elsa工作流封装一套变量、组件的体系
  • 2026年指纹浏览器品牌
  • 讲讲江西中医药大学中医师承班需要面试吗及性价比情况
  • 知网vs维普AIGC检测有什么区别?选对平台少走弯路
  • netty收发
  • 2026年海外代理IP厂家
  • 知网AIGC检测不通过?3招搞定,附避坑清单
  • 中科全程港澳台联考基础班怎么样,靠谱的港澳台联考培训推荐
  • 计算机毕业设计springboot健身房管理系统 基于SpringBoot的健身中心信息化管理平台设计与实现 SpringBoot框架下的体育运动场馆智能管理系统开发
  • 2026年代理IP供应商
  • 手把手教你用AI生成软著材料,30分钟搞定全套文档
  • 分析环境空气颗粒物综合采样器厂家哪家好,宇华智环口碑咋样
  • 计算机毕业设计springboot房产销售系统 SpringBoot驱动的数字化楼盘营销平台 基于SpringBoot的在线房屋交易与营销系统
  • 总结聚氨酯生产厂家排名,建筑行业值得选的厂家有哪些?
  • 毕业论文降AI必备的5款工具,学姐亲测不达标可退款
  • 2026年指纹浏览器开发商
  • 2026年代理IP哪家好
  • 保姆级教程:软著申请全流程详解(附材料模板)