WriteConcern需按场景分层配置:客户端级设默认值但可被覆盖,集合级最常用且优先级居中,事务内须统一指定;w=0有丢数据风险,务必验证集群实际投票节点数。
WriteConcern 不是“设一次就完事”的配置,它必须按使用场景选层级、按一致性要求选参数,否则容易出现写入成功但数据不可读、或写入卡死超时等问题。WriteConcern(全局默认)适用于大多数操作都需强一致性的服务,比如支付类写入。但要注意:它会被更细粒度的设置覆盖(如集合级、事务级),所以不是“最高优先级”。
Go 驱动中常用方式:
client, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://rs1:27017,rs2:27017,rs3:27017").SetWriteConcern(writeconcern.Majority()))
Node.js 驱动可通过 URI 设置:
mongodb://rs1:27017/?w=majority&j=true&wtimeout=5000
w=majority 表示写入必须被多数投票节点确认,适合防止主节点宕机后丢失已确认写入j=true 强制日志落盘,避免断电丢数据;但会显著降低吞吐量wtimeout=5000 是硬性保护,防止因节点故障导致写入无限等待WriteConcern(最常用)日志、监控等弱一致性场景常需降级写关注,而用户订单等关键数据需升级,这时集合级设置最实用——它比客户端级优先,又比单次操作传参更轻量。
Go 示例:
collection := client.Database("mydb").Collection("orders").WithOptions(options.Collection().SetWriteConcern(writeconcern.W2()))
Node.js 示例:
const ordersColl = db.collection('orders', { writeConcern: { w: 2, j: true } });
w=2 要求主节点 + 1 个从节点确认,比 w=majority 更快(尤其在 5 节点集群中,majority=3,而 w=2 永远只需 2 个)w=2 在只有 2 个数据节点的副本集中等价于 w=majority,但在 3+ 节点时行为不同,务必核对实际成员数votes > 0,也会参与 w=majority 计算,可能意外拉高确认门槛WriteConcern
这是最容易踩的坑:事务中所有写操作共享同一 WriteConcern,且只能在 startTransaction() 时通过 TransactionOptions 统一指定,不能对 insert 或 update 单独调用 WithWriteConcern()。
session.StartTransaction(options.Transaction().SetWriteConcern(writeconcern.Majority()))
$inc)替代WriteConcern,但一旦显式设置,就完全覆盖——哪怕你只设了 w=1,整个事务也按此执行w=0 和 Unacknowledged 的真实风险很多人以为 w=0 只是“更快”,其实它连主节点内存写入成功都不保证:网络中断、主节点崩溃、甚至驱动进程 crash 都可能导致“看似成功实则丢数据”。
writeconcern.Unacknowledged() 和 writeconcern.W0() 等价,但后者更直白,建议统一用 W0()
hidden 还留着 votes: 1,这时候 w=majority 可能突然卡住。上线前务必用 rs.status() 确认实际投票节点数,并在压测中观察 wtimeout 是否频繁触发。