前言
在技术社区混了这么长时间,因为一些常见的技术问题反复被问到,总是想写写文章把它们讲清楚。无奈很多时候看似基础的技术问题背后都隐藏着很深的原因,想要一次性说清楚太花时间,而平时又没有很多时间能花在上面(主要是懒),所以产生了写一系列文章的想法,讲讲我或我的客户使用 MongoDB 过程中经常遇到的各种“坑”。话虽如此,难者不会会者不难,希望看了这些讲解你就不再认为这些是“坑”了。
在讲解这些问题前,我会假设读者已经对 MongoDB 有了最基础的了解,因此一些基本名词和概念就不做过多的解释,请自己查阅相关资料。
PSS vs PSA
什么是 PSS/PSA?
在 MongoDB 复制集中,存在三种类型的角色:
PRIMARY: 主节点(P)
SECONDARY: 从节点(S)
ARBITER: 仲裁节点(A)
构建一个复制集至少需要 3 个节点,所以用户就有了两种选择,即 PSS 和 PSA。注意:记住 A 的作用始终是把集群中具有投票权的节点总数凑成奇数用,防止“脑裂”。因此诸如 PAA,PSSAA 之类的配置是没有存在的意义的,极端情况下还会扰乱集群的正常工作。
PSA 有什么好处?
最直接的好处:省钱啊!随便找台机器,不消耗什么资源就可以运行一个 A,比一个 S 的成本小多了。
PSA 有什么问题?
读写失效
最直接的问题来自于 MongoDB 中的一个配置选项 {w: “majority”},这个配置决定了一次成功的写入操作需要到达多少个节点才算真正的成功,w 可以定义为 1,2,…n(n<= 集群节点总数)或 majority。而 majority 是保证在集群故障时不丢失数据的必要配置(关于 majority 和 w 以后再专门写文章讨论)。其代表的意义是:集群中必须有大多数节点收到并确认了一个写操作,这个写操作才算成功。在三个节点的集群中,{w: “majority”} == {w: 2}。因此如果集群配置是 PSA,由于 A 是不存数据的,所以集群中能够确认写操作的节点只有 P 和 S,刚好是 2。到这里可能有人已经看出问题了:在 PSA 中如果有一个数据节点宕机,则再也不能满足{w: “majority”},所有使用这种配置的写操作都会失败。因此可以说,PSA 在一定程度上丢失了高可用性,因为任何一个数据节点的失效都会导致{w: “majority”} 类型写入的失败。引申一下,ReadConcern 同样有可选值 majority,因此同样可能因为一个数据节点的失效而失效。
集群部分功能失效
可能你会觉得:什么 {w: “majority”} 没听说过啊,我也不在乎丢失数据,那用 PSA 是不是就没有问题了?当然不是!在很多你没注意到的场景都存在着{w: “majority”}。比如:
分片集群数据迁移。无论源或者目标片中不能够满足大多数时,迁移都会失败。
分片集群管理。包括但不限于以下这些操作实际上都隐含着{w: “majority”}。一旦不能满足,这些操作都会失败:
db.dropDatabase()
db.collection.drop()
db.collection.dropIndex({…})
sh.shardCollection(…)
db.createUser(…)
结论
majority 比你想象的更重要,PSA 不能够提供足够的可用数据节点来保证 majority,因此在很多场景下会引发隐藏的错误。在有可能的情况下,应尽量使用 PSS 代替 PSA。