聚合任务不能直接用readpreferencetags路由到指定标签节点,因为标签仅在非primary读取偏好模式下生效,且含$out或$merge等写入阶段的聚合必由主节点执行;纯读取型聚合需满足secondary/nearest偏好、无写入阶段、数据已同步、驱动支持等全部条件才可能落在冷节点。

为什么聚合任务不能直接用 readPreferenceTags 路由到指定标签节点
因为聚合($aggregate)本身不参与标签路由决策——真正起作用的是执行该聚合的**读取偏好模式**,而 readPreferenceTags 只在非 primary 模式下生效。更关键的是:如果聚合管道包含写入阶段(如 $out 或 $merge),MongoDB 会强制将整个操作路由到主节点,忽略所有标签和 nearest/secondary 设置。
常见错误现象:配置了 readPreference: 'nearest', readPreferenceTags: [{ "tier": "cold" }],但 explain() 显示仍走主节点;或冷节点日志完全无聚合请求记录。
-
$out和$merge阶段必须由主节点协调写入,即使你连接的是冷节点,请求也会被转发 - 纯读取型聚合(无
$out/$merge/$lookup到未分片集合等触发写行为的阶段)才可能落在带标签的从节点 - 使用
primary模式时,readPreferenceTags参数会被驱动静默忽略(官方明确禁止)
哪些聚合场景能真正落到冷节点上
只有满足全部以下条件的聚合,才可能由带 "tier": "cold" 标签的从节点实际执行:
- 读取偏好显式设为
secondary、secondaryPreferred或nearest - 管道中不含任何写入语义阶段:即不能有
$out、$merge、$lookup(若被查集合未分片且不在同一数据库)、$facet中含写阶段等 - 目标集合数据已同步到该冷节点(
rs.status()中确认optimeDate接近主节点) - 客户端驱动版本支持标签匹配(pymongo ≥ 4.0,Node.js mongodb driver ≥ 4.13)
典型可用场景:对归档订单表做只读统计(如 db.orders.aggregate([{$match: {createdAt: {$lt: ISODate("2023-01-01")}}}, {$group: {_id: "$status", count: {$sum: 1}}}])),且该表已按时间归档至冷节点。
如何验证聚合是否真走到了冷节点
不能只看连接字符串或客户端配置,必须从服务端确认:
- 在目标冷节点上开启慢日志:
db.setProfilingLevel(1, { slowms: 10 }),然后执行聚合,查system.profile是否有对应记录 - 用
db.currentOp({secs_running: {$gt: 0}})在冷节点上实时观察是否有你的聚合操作正在运行 - 检查
rs.status().members[n].lastHeartbeatRecv时间戳,确认该节点近期是活跃的(避免因同步延迟被驱动自动剔除) - 驱动层加日志:pymongo 可启用
log_info级别,Node.js 驱动可监听commandStarted事件,看serverHost是否为你期望的冷节点 IP
注意:nearest 模式下,若冷节点网络延迟高于 localThresholdMS(默认 15ms),驱动会自动跳过它——这不是配置失败,而是容错逻辑。
想让写入型聚合也定向到冷节点?只能靠分片 + Zone
副本集层面的 tags 对写入完全无效,这是设计限制。如果你的聚合必须输出到冷硬件(比如归档结果写入低速大容量磁盘),唯一可行路径是:
- 将集群升级为分片架构(至少 1 个 config server + 2 个 shard)
- 为冷硬件部署一个专用 shard,并打 zone 标签:
sh.addShardTag("shard-cold", "tier.cold") - 对目标集合启用分片,并基于时间字段(如
archivedAt)设置 zone range:sh.updateZoneKeyRange("db.archive_results", {archivedAt: MinKey}, {archivedAt: MaxKey}, "tier.cold") - 此时
$merge到db.archive_results会由 mongos 路由到带tier.coldzone 的 shard 上,物理落盘即完成冷数据隔离
这个方案绕开了副本集标签的读写分离天花板,但代价是架构复杂度陡增——很多团队卡在“到底值不值得为冷数据单独上分片”这一判断上。











