PAYATHON 2026

Spring Boot 使用 Spring Session Redis 后如何采集会话指标?

数据小陈

使用 Spring Session Redis 后,原来的六项 Tomcat 会话指标不能直接反映 Redis 中的会话状态。Spring Boot 的标准 Tomcat 指标采集没有提供自动切换到 Redis 会话统计的等价方案。如果需要这些统计维度,需要补充自定义采集逻辑,但仍可复用 Actuator、Micrometer 和现有监控系统。

为什么接入 Redis 后指标停止更新?

问题中列出的 tomcat_sessions_* 指标来自 Tomcat 自身的会话管理器。Micrometer 的 TomcatMetrics 读取 org.apache.catalina.Manager,例如通过 getActiveSessions() 获取当前会话数,通过 getSessionCounter() 获取创建总数。采集实现

Spring Session Redis 的自动配置生效后,SessionRepositoryFilter 会让应用使用由 Redis 支撑的 HttpSession 实现。会话生命周期由 Spring Session 管理,因此 Tomcat 管理器的统计不会随这些会话的创建和销毁而更新。Spring Session 工作原理

统计来源改变后,指标可能仍然存在,却保持为零或不再变化。如果指标完全消失,则需要检查 Actuator、指标过滤与 Tomcat 采集配置。仅凭添加依赖这一信息,无法确定指标消失的具体原因。

六项指标应如何替代?

先确定统计范围:是单个应用进程,还是同一 Redis 会话命名空间下的全部会话。共享 Redis 后,这两种统计结果可能相差很大。

原指标自定义采集时的处理方式
tomcat_sessions_active_current_sessions统计当前仍有效的会话,使用 Gauge;不能简单等同于 Redis key 数量
tomcat_sessions_active_max_sessions记录当前有效会话数的历史峰值;它不是配置的会话数量上限
tomcat_sessions_alive_max_seconds按选定的结束条件记录会话存活时长,并明确最大值的保留周期
tomcat_sessions_created_sessions_total根据创建事件或首次成功持久化记录 Counter,并说明采用哪种口径
tomcat_sessions_expired_sessions_total根据超时事件记录 Counter,同时明确是否包含主动失效
tomcat_sessions_rejected_sessions_total在实际执行会话准入限制的位置计数

Tomcat 的 rejected 指因达到最大活动会话数而未能创建的会话。Redis 写入失败、认证失败或连接池耗尽都不能直接算作同一种拒绝。Tomcat Manager 定义

自定义时建议使用独立指标前缀,例如 app.session.*,避免监控面板继续把它们解释为 Tomcat 本地统计。

如何用会话事件接入 Micrometer?

如果只需要创建、超时和主动删除的观测计数,可以监听 Spring Session 事件,前提是实际使用的仓库支持发布这些事件。RedisSessionRepository 不支持会话事件发布,而 RedisIndexedSessionRepository 支持相关事件。仓库 API 说明

如果项目支持以下属性,且由 Spring Boot 自动配置会话仓库,可以设置:

spring.session.redis.repository-type=indexed

这项配置会选择支持索引和事件的仓库,但不会自动生成上述六项指标。原问题没有提供版本和显式配置,使用前应核对项目对应版本,并确认实际的 SessionRepository 类型。Redis 仓库配置

下面的示例假设应用已经配置好 Micrometer 的 MeterRegistry,并且能够收到相应的会话事件。它记录当前应用实例收到的事件次数:

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.context.event.EventListener;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.stereotype.Component;

@Component
public class SessionEventMetrics {

    private final Counter created;
    private final Counter expired;
    private final Counter deleted;

    public SessionEventMetrics(MeterRegistry registry) {
        this.created = registry.counter("app.session.events.created");
        this.expired = registry.counter("app.session.events.expired");
        this.deleted = registry.counter("app.session.events.deleted");
    }

    @EventListener
    public void onCreated(SessionCreatedEvent event) {
        created.increment();
    }

    @EventListener
    public void onExpired(SessionExpiredEvent event) {
        expired.increment();
    }

    @EventListener
    public void onDeleted(SessionDeletedEvent event) {
        deleted.increment();
    }
}

示例将超时与主动删除分开统计。SessionExpiredEvent 和 SessionDeletedEvent 都属于 SessionDestroyedEvent;如果同时监听父类和子类来累加同一个销毁计数,会出现重复计算。事件关系说明

为什么不能直接用创建数减销毁数计算当前会话数?

这种算法需要从完整、可靠的初始状态开始,并且不能遗漏或重复处理事件。实际部署中容易遇到以下情况:

  • 应用启动时,Redis 中已经存在会话,本地计数却从零开始。
  • 多个实例订阅同一会话命名空间,可能收到同一批事件;直接求和会重复统计。
  • 实例重启、订阅断开或事件处理失败,可能导致计数与实际状态偏离。
  • 会话超时事件依赖 Redis Keyspace notifications,通知时间也不保证等于逻辑过期时间。

Spring Session 对 Redis Cluster 的事件订阅也有额外限制,不能默认每个节点上的事件都能被完整观测。事件与过期机制、Redis Cluster 注意事项

如果需要可信的全局当前会话数,应维护可校准的共享统计状态或专用会话索引,处理过期、主动失效和 Session ID 变更,并明确允许的统计延迟。可以定时更新采集结果,再由 Gauge 读取,避免每次监控抓取都遍历 Redis。

也不要直接统计整个命名空间的 key:其中可能包含会话数据、索引和过期辅助结构,物理 key 的存在时间也不一定等于会话有效时间。

如何确认采集结果符合预期?

先确认实际仓库类型,再分别验证新建会话、正常访问、主动失效和超时几个场景。正常访问已有会话时,不应不断增加创建计数;多实例部署时,应检查一次会话操作会被多少实例观测到,并据此确定聚合方式。

若还需要排查 Tomcat 指标本身是否启用,可按对应版本检查 server.tomcat.mbeanregistry.enabled=true。它只影响 Tomcat 采集,不会让 Tomcat 开始统计 Redis 会话。Spring Boot 指标配置

备注:内容仅供参考。