在《通过一步步创建sharded cluster来认识MongoDB》一文中,对MongoDB的特性做了一些介绍,包括高性能、高可用、可扩展(水平伸缩),其中,MongoDB的高可用性依赖于replica set的复制与自动failover。对MongoDB数据库的使用有三种模式:standalone,replica set, shareded cluster,在前文中详细介绍了shared cluster的搭建过程。
standalone就是单个mongod,应用程序直接连接到这个Mongod,在这种情况下无分区容错性可言,也一定是强一致性的。对于sharded cluster,每一个shard也都推荐是一个replica set。MongoDB中的shards维护的是独立的数据子集,因此shards之间出现了分区影响不大(在chunk迁移的过程可能还是有影响),因此也主要考虑的是shard内部replica set的分区影响。所以,本文中讨论MongoDB的一致性、可用性问题,针对的也是MongoDB的replica set。
对于replica set,只有一个primary节点,接受写请求和读请求,其他的secondary节点接受读请求。这是一个单写、多读的情况,比多读、多写的情况还是简化了许多。后文为了讨论,也是假设replica set由三个基点组成,一个primary,两个secondary,且所有节点都持久化数据(data-bearing)
MongoDB关于一致性、可用性的权衡,取决于三者:write-concern、read-concern、read-preference。下面主要是MongoDB3.2版本的情况,因为read-concern是在MongoDB3.2版本中才引入的。
write-concern:
write concern表示对于写操作,MongoDB在什么情况下给予客户端响应。包括下面三个字段:
{ w: <value>, j: <boolean>, wtimeout: <number> }
w: 表示当写请求在value个MongoDB实例处理之后才向客户端返回。取值范围:
1:默认值,表示数据写入到standalone的MongoDB或者replica set的primary之后返回
0:不用写入就直接向客户端返回,性能高,但可能丢数据。不过可以配合j:True来增加数据的可持久性(durability)
>1: 只有在replica set环境下才有用,如果value大于的replica set中节点的数目,那么可能导致阻塞
‘majority’: 当数据写入到replica set的大多数节点之后向客户端返回,对于这种情况,一般是配合read-concern使用:
After the write operation returns with a w: "majority" acknowledgement to the client, the client can read the result of that write with a "majority" readConcern
j:表示当写请求在写入journal之后才向客户端返回,默认为False。两点注意:
如果在对于未开启journaling的MongoDB实例使用j:True,会报错
在MongoDB3.2及之后,对于w>1, 需要所有实例都写到journal之后才返回
wtimeout:表示写入的超时时间,即在指定的时间(number),如果还不能向客户端返回(w大于1的情况),那么返回错误
默认为0,相当于没有设置该选项
在MongoDB3.4中,加入了writeConcernMajorityJournalDefault.这么一个选项,使得w,j在不同的组合下情况下不同:
read-reference:
在前文已经讲解过,一个replica set由一个primary和多个secondary组成。primary接受写操作,因此数据一定是最新的,secondary通过oplog来同步写操作,因此数据有一定的延迟。对于时效性不是很敏感的查询业务,可以从secondary节点查询,以减轻集群的压力。
MongoDB指出在不同的情况下选用不同的read-reference,非常灵活。MongoDB driver支持一下几种read-reference:
primary:默认模式,一切读操作都路由到replica set的primary节点
primaryPreferred:正常情况下都是路由到primary节点,只有当primary节点不可用(failover)的时候,才路由到secondary节点。
secondary:一切读操作都路由到replica set的secondary节点
secondaryPreferred:正常情况下都是路由到secondary节点,只有当secondary节点不可用的时候,才路由到primary节点。
nearest:从延时最小的节点读取数据,不管是primary还是secondary。对于分布式应用且MongoDB是多数据中心部署,nearest能保证最好的data locality。
如果使用secondary或者secondaryPreferred,那么需要意识到:
(1) 因为延时,读取到的数据可能不是最新的,而且不同的secondary返回的数据还可能不一样;
(2) 对于默认开启了balancer的sharded collection,由于还未结束或者异常终止的chunk迁移,secondary返回的可能是有缺失或者多余的数据
(3) 在有多个secondary节点的情况下,选择哪一个secondary节点呢,简单来说是“closest”即平均延时最小的节点,具体参加Server Selection Algorithm
read-concern:
read concern是在MongoDB3.2中才加入的新特性,表示对于replica set(包括sharded cluster中使用复制集的shard)返回什么样的数据。不同的存储引擎对read-concern的支持情况也是不一样的
read concern有以下三个level:
local:默认值,返回当前节点的最新数据,当前节点取决于read reference。
majority:返回的是已经被确认写入到多数节点的最新数据。该选项的使用需要以下条件: WiredTiger存储引擎,且使用election protocol version 1;启动MongoDB实例的时候指定 --enableMajorityReadConcern选项。
linearizable:3.4版本中引入,这里略过了,感兴趣的读者参考文档。
在文章中有这么一句话:
Regardless of the read concern level, the most recent data on a node may not reflect the most recent version of the data in the system.
就是说,即便使用了read concern:majority, 返回的也不一定是最新的数据,这个和NWR理论并不是一回事。究其根本原因,在于最终返回的数值只来源于一个MongoDB节点 ,该节点的选择取决于read reference。
在这篇文章中,对readconcern的引入的意义以及实现有详细介绍,在这里只引用核心部分:
readConcern 的初衷在于解决『脏读』的问题,比如用户从 MongoDB 的 primary 上读取了某一条数据,但这条数据并没有同步到大多数节点,然后 primary 就故障了,重新恢复后 这个primary 节点会将未同步到大多数节点的数据回滚掉,导致用户读到了『脏数据』。
当指定 readConcern 级别为 majority 时,能保证用户读到的数据『已经写入到大多数节点』,而这样的数据肯定不会发生回滚,避免了脏读的问题。
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com