Queryable Encryption 在分片集群中完全可用,但需满足三前提:MongoDB 6.0+企业版(或7.0+社区版)、所有分片与config server启用enableEncryption: true、keyVaultNamespace必须指向未分片集合。

Queryable Encryption 在分片集群中是否可用?
完全可用,但必须满足三个硬性前提:MongoDB 6.0+ 企业版(或 7.0+ 社区版已有限支持)、所有分片和 config server 均启用 enableEncryption: true、客户端驱动配置的 keyVaultNamespace 必须指向一个**未分片的集合**(通常是 encryption.__keyVault)。
常见错误是把 keyVault 集合也做了分片——这会导致 AutoEncryptionError: key not found,因为密钥查找依赖精确的 _id 查询,而分片会破坏单文档原子性保障。
-
keyVault集合必须建在非分片数据库中,且不能有分片键 - 所有 mongos 实例需能访问该集合,网络策略要放行
- 若使用 AWS KMS,各分片节点必须拥有相同 IAM 权限,否则部分节点加解密失败
分片键与加密字段能否重叠?
不能。如果某个字段既用作分片键(如 tenantId),又标记为 deterministic 加密字段,写入时会报错 Cannot encrypt field used as shard key。
原因在于:分片键值需在 mongos 层完成路由计算,而 Queryable Encryption 的密文生成发生在客户端驱动层,mongos 无法解析密文对应原始值,也就无法决定路由到哪个分片。
- 解决方案一:改用
random模式加密该字段(但失去等值查询能力) - 解决方案二:保留明文分片键,仅对其他敏感字段(如
ssn、email)加密 - 解决方案三:用复合分片键,例如
{tenantId: 1, _id: 1},其中tenantId明文,_id由 ObjectId 保证分布
如何让加密查询跨分片生效?
Queryable Encryption 的查询重写逻辑在客户端完成,mongos 收到的是已重写的密文查询条件,因此天然支持跨分片执行——但前提是驱动版本 ≥ 6.3,且 autoEncryption 配置中启用了 mongocryptdSpawnPath(旧版)或使用内置加密子系统(6.0+)。
典型失败场景是:应用连接的是单个分片而非 mongos,此时加密查询会被直接发往该分片,其他分片数据不可见,造成结果遗漏。
- 务必确认连接字符串指向 mongos 地址,而非
mongodb://shard01:27018这类直连地址 - 执行
db.runCommand({getShardVersion: 1})验证当前连接是否识别为分片上下文 - 加密字段的索引必须在每个分片上单独创建(驱动不自动同步),否则查询会退化为全分片扫描
密钥轮换时分片集群要注意什么?
密钥轮换本身不涉及分片逻辑,但操作窗口期存在风险:新旧密钥并存期间,若某分片尚未加载新密钥配置,或客户端缓存了旧密钥句柄,就可能出现部分文档可查、部分不可查的情况。
关键点在于密钥元数据(__keyVault 中的 masterKey 字段)更新后,所有 mongos 和分片节点需在 5 分钟内完成密钥刷新(默认 TTL)。超时未刷新会导致 KeyNotFound 错误。
- 轮换前先用
mongosh连接每个分片,执行db.getSiblingDB("encryption").getCollection("__keyVault").find()确认密钥状态一致 - 避免在流量高峰执行轮换;建议配合
maxTimeMS控制查询超时,防止阻塞 - 轮换后立即测试跨分片等值查询(如
{ ssn: "123-45-6789" }),而非只查单一分片
加密不是加一层壳就完事。分片架构下,密钥分发路径、查询路由时机、索引部署粒度,每一处都可能成为密文失效的断点。最常被忽略的是:你以为在查“所有用户”,其实只查了第一个分片——因为连接错了入口。











