MongoDB Read Concern、Write Concern 和 Read Preference 有什么区别?
简化版
Write Concern 控制写入要被多少节点确认才算成功;Read Concern 控制读取数据的一致性级别;Read Preference 控制读请求发往 primary 还是 secondary。简单说,Write Concern 管写得稳不稳,Read Concern 管读到的数据保证到什么程度,Read Preference 管从哪里读。
详细版
三者区别:
| 概念 | 控制对象 | 典型问题 |
|---|---|---|
| Write Concern | 写入确认级别 | 写入是否已被多数节点确认 |
| Read Concern | 读取一致性级别 | 读到的数据是否满足某种可见性保证 |
| Read Preference | 读路由位置 | 从 primary 读还是 secondary 读 |
例如:
writeConcern: { w: "majority" }:多数节点确认后写成功;readConcern: "majority":读取已被多数节点确认的数据;readPreference: "secondary":优先从 secondary 读取。
这三个配置共同影响一致性、延迟、可用性和读写压力分布。
完整版教学
一、为什么 MongoDB 要拆成三个概念
在复制集里,数据可能处于不同状态:
- primary 已经写入;
- secondary 还没复制;
- 多数节点已经确认;
- 某个节点网络延迟;
- 读请求可能发往不同节点。
所以 MongoDB 把写入确认、读取可见性、读取路由拆成三个配置,让应用按业务选择。
二、Write Concern 管写入确认
Write Concern 决定写操作要被多少节点确认。
例如:
db.orders.insertOne(
{ orderNo: "O1001" },
{ writeConcern: { w: "majority" } }
)
majority 表示多数投票节点确认后返回成功。这样即使 primary 很快故障,新主也更可能包含这次写入。
更强的写关注通常更安全,但延迟更高。
三、Read Preference 管从哪里读
Read Preference 决定读请求路由到哪里:
- primary;
- primaryPreferred;
- secondary;
- secondaryPreferred;
- nearest。
从 primary 读通常更容易读到最新数据;从 secondary 读可以分担压力、就近读取,但可能读到落后数据。
如果业务是订单支付结果查询,通常更偏向 primary;如果是报表或低一致性列表,可以考虑 secondary。
四、Read Concern 管读的一致性级别
Read Concern 控制读操作看到的数据保证。例如 majority 读关注会读取已被多数节点确认的数据。
它和 read preference 不是一回事。你可以从 secondary 读,但仍然要考虑这个 secondary 上数据是否满足所需读关注。
事务中还会涉及 snapshot 等更强语义。
五、三者如何组合思考
假设业务写订单后马上查询订单状态:
- 写入用低 write concern,可能故障后丢失;
- 查询读 secondary,可能复制延迟读不到;
- read concern 太弱,可能读到不符合预期的数据。
如果这是核心交易链路,就要选择更强写入确认和更合理读路径。如果只是浏览统计,可以牺牲一点新鲜度换性能。
六、用业务场景组合三者
这三个配置要一起看,不能孤立背概念。比如交易订单通常希望写入至少多数确认,读取走 primary 或满足 majority 语义;报表列表可以读 secondary,接受短暂延迟;本地开发或低价值日志可以降低写确认换吞吐。
| 场景 | Write Concern | Read Concern | Read Preference |
|---|---|---|---|
| 支付订单 | majority | majority 或事务语义 | primary |
| 普通内容浏览 | 默认或业务可接受级别 | 默认 | secondaryPreferred 可考虑 |
| 实时风控判断 | 偏强 | 偏强 | 优先 primary |
| 离线统计 | 可放宽 | 可放宽 | secondary 或分析副本 |
举例:写入用 w:1 后 primary 立刻故障,如果该写入尚未复制到多数节点,新 primary 可能没有这条数据;随后读 secondary 更可能看不到。这就是写确认、读保证和读位置共同决定一致性的原因。
七、常见误区与追问
Write Concern: 写成功要几个节点确认?
Read Concern: 读到的数据有什么一致性保证?
Read Preference: 读请求发到哪个节点?
记忆钩子:Write Concern 管“写稳不稳”,Read Concern 管“读的保证”,Read Preference 管“读去哪儿”。
- 误区:Read Preference 等于 Read Concern。 前者决定读哪个节点,后者决定读取数据的一致性语义,二者不是一回事。
- 误区:读 secondary 一定能分担压力且没有代价。 secondary 可能落后 primary,强一致读和写后读不能随便走 secondary。
- 误区:
w: majority就保证所有节点都有数据。 majority 只要求多数投票节点确认,不代表所有 secondary 都已同步。 - 追问:为什么强写确认会增加延迟? 写入要等待更多节点确认,网络、磁盘和复制延迟都会进入响应时间。
- 追问:写后读怎么配置更稳? 核心链路通常用较强 write concern,并从 primary 读或使用满足业务一致性要求的 read concern。
- 追问:什么时候可以放宽这些配置? 低价值日志、可重建数据、允许短暂旧数据的列表和报表,可以用性能和可用性换一致性。
八、加强记忆
MongoDB 一致性相关配置记成三句话:Write Concern 问“写到几个节点才算成功”,Read Concern 问“读到的数据有什么保证”,Read Preference 问“去哪个节点读”。强一致链路保守配置,低风险读场景可以换取性能和可用性。