MongoDB从3.6版本开始引入了可重试写入、因果一致性和多文档事务,这些特性的背后都离不开一个共同的基础设施——会话(Session)。会话由服务端统一管理,保存在config.system.sessions集合以及每个实例的内存缓存中。当需要排查连接占用、事务残留或者只想看看当前有哪些活跃会话时,聚合管道阶段$listSessions就是官方提供的标准查询手段。这篇文章详细介绍它的使用方法、权限要求以及一些实用技巧。

$listSessions的基本概念与作用范围
首先要明确一点,$listSessions是聚合管道的一个阶段,而不是普通的查询命令。它只能作为aggregate操作的第一个阶段出现,如果放在其他阶段后面会直接报错。它的作用是把当前MongoDB实例内存缓存中的所有会话以文档流的形式吐出来,后续可以继续接$match、$project、$group等阶段做进一步处理。
这个阶段有个孪生兄弟叫$listLocalSessions。两者的区别在于:在副本集或分片集群环境中,$listSessions返回的是整个集群范围内缓存的会话(本质上依赖路由节点汇总),而$listLocalSessions只返回当前连接的那个节点本地缓存的会话。在单节点环境下两者结果基本一致,但在生产集群中排查问题时,分清这两个阶段的差别非常关键。
每个会话文档包含几个重要字段:_id是会话的UUID标识,lastUse记录最近一次使用时间,lastUseChopTime是内部维护的时间戳。如果会话正在执行事务,还会有transaction字段携带事务状态信息。理解这些字段是后续做过滤和统计的基础。
基本用法与代码示例
最直接的用法是对admin数据库执行聚合,注意$listSessions必须在admin库上运行,否则会报错。先给一个最简单的例子,列出当前所有会话:
use admin
db.aggregate([
{ $listSessions: {} }
])
参数传空对象表示不加任何过滤条件。你也可以传入{ allUsers: true }来列出所有用户的会话,但这个操作需要额外的权限,普通用户执行会抛出Unauthorized错误。还可以传入{ users: [ { user: "appUser", db: "admin" } ] }来只查看指定用户的会话,这在多业务共用一个集群时特别有用。
实际排查中很少需要看全部字段,通常会配合$match过滤掉已经超时的会话。会话默认超时时间是30分钟,可以通过服务端参数localLogicalSessionTimeoutMinutes调整。下面的例子筛选出最近十分钟内活跃的会话,并只保留关键信息:
use admin
db.aggregate([
{ $listSessions: { allUsers: true } },
{ $match: {
lastUse: { $gte: new Date(Date.now() - 10 * 60 * 1000) }
}},
{ $project: {
_id: 1,
lastUse: 1,
username: 1
}}
])
如果要统计当前活跃会话的数量,在管道末尾接一个$count阶段即可。这种写法在编写监控脚本时很方便,配合定时任务就能实现对会话数量的持续观测。
权限要求与常见报错排查
$listSessions对权限有明确要求。默认情况下,不传allUsers参数时,用户只能看到自己创建的会话;想要查看所有用户的会话,执行者必须拥有listAnySession权限动作,通常内置角色clusterManager或者自建包含该动作的角色可以满足。如果你的账户权限不足,会收到类似not authorized on admin to execute command的错误提示。
另一个常见报错是Unauthorized搭配错误信息listSessions may only be run against the admin database,这说明你没有切换到admin库。因为会话信息属于集群级元数据,MongoDB强制要求这类操作在admin库上执行,这一点和currentOp等命令的要求是一致的。
还有一种情况是管道阶段位置放错了。比如有人把$listSessions放在$match后面,会收到$listSessions is only valid as the first stage in a pipeline的报错。记住它必须是管道的第一个阶段,这一点在驱动程序中拼装管道时尤其容易疏忽。另外,如果查询结果里看到大量lastUse很旧的会话不必紧张,它们只是还没被后台清理任务回收,超过超时时间后MongoDB会自动将其标记为过期并清理。
实用技巧:结合$lookup关联用户信息
会话文档中的_id字段本身只有UUID,直接看并不知道是哪个业务建立的。这时可以利用$lookup把会话与config.system.sessions集合或者其他业务数据关联起来。下面演示一个将活跃会话按用户名分组统计的例子:
use admin
db.aggregate([
{ $listSessions: { allUsers: true } },
{ $group: {
_id: "$username",
sessionCount: { $sum: 1 },
latestUse: { $max: "$lastUse" }
}},
{ $sort: { sessionCount: -1 } }
])
这个管道可以快速回答“哪个用户持有的会话最多”这类问题。如果某个应用存在会话泄漏(比如驱动配置不当导致不断创建新会话而不复用),通过这个统计就能第一时间发现异常增长的用户,进而定位到具体的应用实例。
需要注意的是,$listSessions返回的是内存缓存中的快照,不保证强一致性,在会话数量极大的集群上执行也可能带来一定开销。建议在监控场景下控制执行频率,必要时优先使用$listLocalSessions缩小范围。掌握了这些用法之后,无论是日常运维还是故障排查,你都能对集群中的会话状况做到心中有数。
MongoDB聚合管道$listSessions修改时间:2026-09-10 22:06:39