MongoDB 的 Read Preference 是什么?和 Read Concern 有什么区别?
简化版
Read Preference 决定读请求发往复制集的哪个节点,例如默认读 Primary,也可以读 Secondary;Read Concern 决定读到什么一致性级别。一个管“读哪里”,一个管“读到什么保证”,不能混为一谈。
详细版
Read Preference 常见模式有 primary、primaryPreferred、secondary、secondaryPreferred、nearest。默认 primary 能最大程度避免读到旧数据;读 Secondary 可以分担读压力,但可能遇到复制延迟。
Read Concern 则关注可见性和一致性,例如 local、majority、snapshot。面试回答时可以举例:把 Read Preference 设为 secondary,只是让读走从库,不代表读到最新数据;要结合复制延迟、业务读新鲜度和 Read Concern 一起设计。
完整版教学
一、Read Preference 解决读路由问题
MongoDB 复制集通常有一个 Primary 和多个 Secondary。写请求走 Primary,读请求默认也走 Primary。
Read Preference 用来告诉驱动:读请求应该发给哪个成员。
client read
|
v
read preference
|
+-- primary
+-- secondary
+-- nearest
记忆钩子:Read Preference 问的是“去哪个节点读”,不是“读到多新”。
二、常见模式要知道取舍
| 模式 | 含义 | 常见用途 | 风险 |
|---|---|---|---|
primary | 只读主节点 | 默认、强读新鲜度 | 主节点压力更大 |
primaryPreferred | 优先主,主不可用读从 | 降级可用性 | 故障时可能读旧 |
secondary | 只读从节点 | 报表、低新鲜度读 | 可能复制延迟 |
secondaryPreferred | 优先从,从不可用读主 | 读压分摊 | 一致性体验不稳定 |
nearest | 按延迟选近节点 | 跨地域读 | 可能读到较旧数据 |
默认 primary 是保守选择。只有明确能接受旧读,才应该把业务读流量放到 Secondary。
三、Read Concern 是另一件事
Read Concern 决定读取数据的可见性语义。它回答的是:这次读要看到本地已写入的数据,还是多数节点确认的数据,还是事务快照里的数据。
| 概念 | 回答的问题 | 例子 |
|---|---|---|
| Read Preference | 读哪个节点 | secondaryPreferred |
| Read Concern | 读什么一致性级别 | majority |
| Write Concern | 写入确认到什么程度 | { w: "majority" } |
面试里最容易混的是 Read Preference 和 Read Concern。读从库不等于 majority,一致性级别也不等于读路由。
四、读 Secondary 会遇到复制延迟
假设用户修改昵称,写入 Primary 成功,但 Secondary 还落后 3 秒。
T0 write primary: name = "Alicia"
T1 read secondary: name = "Alice"
T4 secondary catches up: name = "Alicia"
如果业务场景是“用户刚保存资料立刻回显”,这种旧读体验很差。此时应读 Primary,或者对刚写后的读做特殊路由。
如果业务场景是后台报表、推荐计算、异步分析,读 Secondary 可能可以接受。
五、读写分离不是免费午餐
很多人把 Read Preference 当成 MongoDB 读写分离开关,以为读从库就能无脑扩展读能力。
实际要考虑:
- Secondary 读压力会影响复制应用速度。
- 复制延迟会导致旧读。
- 大查询可能拖慢从库,影响故障切换质量。
- 跨地域 nearest 可能读到更旧的数据。
- 连接串配置错误会让核心链路读到非预期节点。
因此读从库要按业务分层,而不是全局一刀切。
六、工程上怎么设计读策略
可以按读新鲜度分级。
强新鲜度:订单支付结果、用户刚修改资料 -> primary
可短暂旧读:商品详情、内容页 -> primaryPreferred 或 secondaryPreferred
分析查询:报表、离线检查 -> secondary
跨地域低延迟:就近浏览类请求 -> nearest,但要说明旧读风险
在代码中也要避免把全局连接串配置得过于激进。核心写后读链路最好显式使用 Primary。
七、常见误区与追问
- 误区:Read Preference 和 Read Concern 是一回事。 Read Preference 管读路由,Read Concern 管一致性可见性。
- 误区:读 Secondary 一定能降低整体压力。 如果从库被大查询压住,复制延迟会扩大,还会影响故障恢复。
- 误区:
nearest就是最优选择。 它按延迟选节点,可能牺牲读新鲜度。 - 追问:为什么默认读 Primary? 默认更符合多数业务对写后读新鲜度的预期。
- 追问:什么场景适合读 Secondary? 报表、分析、低新鲜度列表、可接受延迟的查询。
- 追问:写后立刻读怎么保证体验? 对该链路读 Primary,或使用会话、因果一致性等机制,并监控复制延迟。
八、加强记忆
Read Preference 记成“读哪里”,Read Concern 记成“读到什么保证”。默认读 Primary 最稳;读 Secondary 能分摊部分读压力,但要承担复制延迟和旧读风险;nearest 更偏低延迟路由,不保证最新。面试回答时用“订单结果读主、报表读从”的例子,最容易把工程取舍讲清楚。