什么是writeConcern
writeConcern决定一个写操作落到多少个节点上才算成功,这决定了mongodb是否会丢失数据。
writeConcern的取值包括:
- 0:发起写操作,不关心是否成功;
- 1~集群最大数据节点数:写操作需要被复制到指定节点数才算成功;
- majority:写操作需要被复制到大多数节点上才算成功。
发起写操作的程序将阻塞到写操作到达指定的节点数为止。
默认行为
应用程序试图写入x=1,进入mongodb的primary节点,一旦写入primary(未必是写到磁盘里,可能只是写入到内存中),就向客户端响应acknowledge。
之后由mongodb另外的线程将数据由primary异步复制到secondary1和secondary2。此时如果primary发生crash,会导致该数据丢失。
w:"majority"
要解决上述问题,可以使用大多数节点确认模式。
当x=1写入primary后没有返回,写入进程等待数据复制到secondary1或者secondary2后primary发送acknowledge。
此时如果primary发生crash,secondary1会成为新的主节点。
w:"all"
数据要写入全部节点,才返回成功。
j:true
日志的作用是给一个数据库节点在宕机的时候可以快速恢复刚才的写操作,所以一般数据库都先写日志文件,再写数据文件。
默认一个操作进到primary内存的时候,并不会等写日志,而就返回了。
writeConcern可以决定写操作到达多少个节点才算成功,journal则定义如何才算成功。取值包括:
- true:写操作落到journal文件中才算成功;
- false:写操作达到内存计算成功。
writeConcern的意义
对于5个节点的复制集来说,写操作落到多少个节点上才算是安全的?
- 1
- 2
- 3
- 4
- 5
- majority
writeConcern实验
在复制集测试writeConcern参数
db.test.insert({count:1},{writeConcern:{w:"majority"}})
db.test.insert({count:1},{writeConcern:{w:3}})
db.test.insert({count:1},{writeConcern:{w:4}})
配置延迟节点,模拟网络延迟(复制延迟)
conf=rs.conf()
conf.members[2].slaveDelay=5 // 等待5s去同步主节点数据
conf.memvers[2].priority=0 // 如果有延迟,则不可以参与选举
rs.reconfig(conf)
观察复制延迟下的写入,以及timeout参数
db.test.insert({count:1},{writeConcern:{w:3}})
db.test.insert({count:1},{writeConcern:{w:3,wtimeout:3000}}) // 数据可能已经写入,需要根据日志等进行后续操作
注意事项
- 虽然多余问半数的writeConcern都是安全的,但通常只会设置majority,因为这是等待写入延迟时间最短的选择;
- 不要设置writeConcern等于总节点数,因为一旦有一个节点故障,所有写操作都将失败;
- writeConcern虽然会增加写操作延迟时间,但并不会显著增加集群压力,因此无论是否等待,写操作最终都会复制到所有节点上。设置writeConcern只是让写操作等待复制后再返回而已;
- 赢对重要数据应用{w:"majority"},普通数据可以应用{w:1}以确保最佳性能。