mongos权限校验逻辑
背景
经常会发现线上权限的调整好像在mongos当中并没有立即生效,这是一个比较奇怪的问题,下面对这个问题进行一下研究。
mongos 认证逻辑分析
Mongos 的权限逻辑全部存在于 config server 当中。通过分析源码可以发现,当通过 mongos 访问认证以及访问数据库的时候,会经过以下过程:
- 首次请求:mongos 从 config server 获取权限信息,计算后存储到 Session 中
- 后续请求:直接从 Session 中读取权限信息
- 后台线程:每隔 30秒 刷新权限缓存信息,标记旧信息为过期
- 过期检查:后续请求发现 Session 中的权限信息已过期时,才会重新从 config 拉取最新权限
所以我们可以得出一个结论:设置权限后的 30s 内,权限变更在其他 mongos 上是不生效的,除非是在设置权限的那个 mongos 上(该 mongos 上的权限缓存会被立即置为无效)。
举个例子:有两个 mongos 实例,在 mongos1 上设置了权限之后,mongos1 上马上无法执行 dropDatabase(),而 mongos2 还是可以正常执行的。等待 30s 后,mongos2 的缓存刷新,权限才会生效。

解决方案
如果不想等待 30s 的缓存刷新周期,可以手动刷新 mongos 的用户信息缓存,让权限立即生效:
1 | db.getSiblingDB("admin").runCommand({ invalidateUserCache: 1 }) |
执行该命令后,mongos 会立即清除本地的用户权限缓存,下次请求时会重新从 config server 拉取最新的权限信息,权限变更马上生效。
验证流程:
1 | // 1. 权限变更后,直接执行会报 Unauthorized |
总结
- mongos 的权限信息缓存在本地,后台线程每 30秒 刷新一次
- 权限变更后,只有执行变更的那个 mongos 会立即生效,其他 mongos 需要等待缓存刷新
- 可以通过
invalidateUserCache命令手动刷新缓存,让权限立即生效 - 在多 mongos 的集群架构中,如果需要权限变更立即全局生效,需要对每个 mongos 都执行一次缓存刷新命令