writeConcern参数
writeConcern决定一个写操作落到多少个节点上才算成功。writeConcern的取值包括:
- 0:发起写操作,不关心是否成功;
- 1~集群最大数据节点数:写操作需要被复制到指定节点数才算成功;
- majority:写操作需要被复制到大多数节点上才算成功。
发起写操作的程序将阻塞到写操作到达指定的节点数为止。
writeConcern的默认值是1,即我们的数据写到一个节点上便成功了。
我们以一个3节点复制集不做任何特别设定(默认值)的例子来说明:
假设客户端执行 db.test.insert({count:1}) 这样的操作,那么首先会进入到Primary主节点当中,将{count:1}这条数据写到主节点当中便成功返回。注意:这里所说的写到Primary节点中,并不一定是指写到Primary的盘中,有可能只是写到Primary节点的内存当中。此时后台会同步的将这条数据同步到另外的两个节点Secondary1和Secondary2当中。
在这种情况下,是会产生丢数据的情况的,即当我们写入到Primary主节点后,成功返回给客户端,此时主节点crash,所以会导致从节点Sencondary1和Secondary2没来得及将这条数据同步过来。这个时候两个从节点通过选举产生的新的主节点当中便少了刚刚插入的这条数据,也就是产生了所谓的丢数据的场景。
解决方式:
我们通过writeConcern参数来保证数据写入的安全性,防止主节点宕机导致数据丢失,将之前的插入语句改下为以下格式:
- db.test.insert({count:1},{writeConcern:{w:"majortiy"}})
这样写操作需要被复制到大多数节点上才会成功返回。
接下来来看另一个参数:journal(进一步保证数据写入的安全性)
我们知道writeConcern可以决定写操作到达多少个节点才算成功,journal则定义如何才算成功。取值包括:
- true:写操作落到journal文件中才算成功;
- false:写操作到达内存即算成功。
- 例:db.test.insert({count:1},{writeConcern:{w:"majortiy"}},{journal:{j:"true"}})
writeConcern参数意义:保证数据非常安全的写到分布式集群,我们就需要使用writeConcern这个参数,如果需要进一步保证数据的持久性,则可以通过journal参数。
writeConcern实验
由于之前我已经在本地搭建好了一个3节点复制集,所以就直接开始我们的实验部分啦:
首先进入到我们的Primary主节点当中:
接下来,查看复制集的信息:
接下来,我们需要配置延迟节点,模拟网络延迟(复制延迟):
开始测试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[0].slaveDelay=10
- conf.members[0].priority=0
- rs.reconfig(conf)
观察复制延迟下的写入,以及timeout参数:
- db.test.insert({count:1},{writeConcern:{w:3}})
- db.test.insert({count:1},{writeConcern:{w:3,wtimeout:3000}})