Rollback
如果一个primary在插入过程中,出现down机,且插入的数据有一部分secondary没有来得及通过oplog同步。那么down机的primary(old primary)拥有的数据版本即是最新的(version L)。同时,因为down机,自然也会通过选举产生新的primary(new primary)。
选出的new primary自然拥有相对老的数据(version O)。这时候,new primary 会继续接受新的请求。
假设,没有down机,正常数据版本变化应该是:version O -> L -> N
而:new primary 的数据版本变化是: version O -> N`
这里也就出现了2个问题:
1.数据出现了断层
2.old primary如果作为secondary回到集群,带了version L 的数据,会出现数据差异(N`与L的差异)。这里,也就是需要ROLLBACK的原因了。
mongodb会根据old primary和new primary之间oplog的差异,自动进行rollback来使old primary和new primary同步。
- 解决数据断层:被old primary rollback的数据会存放到一个单独的rollbakc files里面,可以通过人工操作来恢复它(O->L的数据)。
- 当rollback超过30分钟或者大于300MB,rollback会失败。
为了防止roll back 的发生,我们可以使用write concern。(会显著降低写性能)
Write concern
write concern即把“写”操作,在集群多个节点上执行成功才返回结果。
wtimeout :限定时间内完成。否则返回失败。
- 0代表不设定时间
- 如果设定了超时,发生超时,超时前的写操作不会回滚(应用程序需要自行安排逻辑处理超时)
在majority数量节点上写入:
db.products.insertOne(
{ “_id”: 10, “item”: “envelopes”, “qty”: 100, type: “Self-Sealing” },
{ writeConcern: { “w” : “majority”, “wtimeout” : 100 } } — majority
);
在指定数量节点上写入:
db.products.insertOne(
{ “_id”: 10, “item”: “envelopes”, “qty”: 100, type: “Self-Sealing” },
{ writeConcern: { “w” : 2, “wtimeout” : 100 } } —- primary and one secondary(计算原则为:n+1,n个secondary + 1个primary)
);
Hidden,?delayed, and?priority 0?可以成为w: N的对象。
在指定分组数量上写入: N组,写入每个组的至少一个节点。
var config = rs.config()
> config.members[0].tags = {“dc” : “us-east”}
> config.members[1].tags = {“dc” : “us-east”}
> config.members[2].tags = {“dc” : “us-east”}
> config.members[5].tags = {“dc” : “us-west”}
> config.members[6].tags = {“dc” : “us-west”}
config.settings = {}
> config.settings.getLastErrorModes = [{“eachDC” : {“dc” : 2}}]
> rs.reconfig(config)
db.products.insertOne( { “_id”: 10, “item”: “envelopes”, “qty”: 100, type: “Self-Sealing” }, { writeConcern: { “w” : “eachDC”, wtimeout : 1000 } });
Delayed secondaries 只会在设置的slaveDelay 时间之后才会返回写入成功。
从Replica Set读数据
读的方式:
- primary —默认方式,只从primary读,primary down集群无法读。
- primary preferred —优先从primary读,primary down,从secondary读
- secondary —只 从 secondary 读, secondary全down集群无法读
- secondary prefrred —优先从 secondary 读, secondary全down,从 primary 读
- Nearest — 从ping time延迟最低的节点读数据
- 直接连接到某个节点,从某个节点读取数据。(比如某个secondary,有自己额外的索引,且不要求数据一致性,可以利用那个索引优化一些读)
Multi-document transactions?的读操作只能读?primary.
使用secondary来分担读任务的缺点:
- 因为同步的不一致或者不及时,读到的很可能不是最新的数据。
- 如果是集群来分担读的话,很可能造成一个点垮了之后,任务分给其他节点,然后其他节点又造成超负荷,最后整个集群彻底崩塌。(如果没崩塌,你回复跨掉的节点如果需要再同步,也会给其他节点造成负担。) —-sharding 时用来分担读任务更好的方案。