(mongodb副本集) PSA模式添加、修改节点
PSA模式介绍
PSA模式(Primary-Secondary-Arbiter)是MongoDB复制集中的一种架构配置。在这种模式下,复制集由一个主节点(PRIMARY)、一个从节点(SECONDARY)和一个仲裁者节点(ARBITER)组成。
在MongoDB的复制集中,仲裁者节点(Arbiter)是一种特殊类型的节点,其主要作用是在主节点(Primary)不可用时参与选举过程,帮助复制集选择一个新的主节点。以下是仲裁者节点的一些特点:
- 不存储数据:与普通的从节点(Secondary)不同,仲裁者节点不存储数据副本,因此不会占用额外的存储资源。
- 投票权:尽管仲裁者节点不存储数据,但它拥有一个投票权,可以在选举新主节点时参与投票。
- 减少成本:由于仲裁者节点不需要存储数据,因此可以在成本较低的机器上运行,或者在不同的数据中心运行,以提高复制集的可用性和容错能力。
- 提高选举效率:在复制集中,选举新主节点需要超过半数的投票。在只有两个从节点的复制集中,如果一个从节点不可用,复制集将无法进行选举。引入仲裁者节点可以确保即使一个从节点不可用,复制集仍然可以进行选举。
- 不参与数据复制:仲裁者节点不参与数据复制过程,因此不会增加网络和存储的负担。
- 不影响业务:由于仲裁者节点不处理业务读写请求,其故障不会影响业务的正常运行。
PSA模式下添加/修改节点出现的问题
情况一:添加副节点
rs.add()
添加的节点默认priority和votes都为1。然而,在PSA模式中,通常希望新添加的节点不参与选举(即votes
为0),并且priority
为0以避免其成为主节点。如果新添加的节点具有投票权和优先级,那么在主节点宕机时,它可能会被选举为主节点,这可能会导致数据不一致和可用性问题。
myrepl:PRIMARY> rs.add('127.0.0.1:27019')
...{"ok" : 0,"errmsg" : "Rejecting reconfig where the new config has a PSA topology and the secondary is electable, but tfig contains only one writable node. Refer to https://docs.mongodb.com/manual/reference/method/rs.reconfigForPSASet/steps on reconfiguring a PSA set.","code" : 103,"codeName" : "NewReplicaSetConfigurationIncompatible","$clusterTime" : {"clusterTime" : Timestamp(1731679536, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
...
情况二:修改副节点
这里副节点的priority
和votes
一开始都为0,报错原因同上:在PSA模式中,通常希望新添加的节点不参与选举(即votes
为0),并且priority
为0以避免其成为主节点。
myrepl:PRIMARY>var cfg = rs.conf()
myrepl:PRIMARY>cfg.members[2].priority = 1
myrepl:PRIMARY>cfg.members[2].votes = 1
myrepl:PRIMARY>rs.reconfig(cfg){"ok" : 0,"errmsg" : "Rejecting reconfig where the new config has a PSA topology and the secondary is electable, but the old config contains only one writable node. Refer to https://docs.mongodb.com/manual/reference/method/rs.reconfigForPSASet/ for next steps on reconfiguring a PSA set.","code" : 103,"codeName" : "NewReplicaSetConfigurationIncompatible"
}
PSA模式下如何添加/修改节点
在PSA模式下,如果直接使用rs.reconfig()
修改节点可能会失败,因为MongoDB不允许在只有一个可写节点的情况下重新配置PSA拓扑。在这种情况下,应使用rs.reconfigForPSASet()
方法,它分两步重新配置副本集:
这里假设是在添加第三个节点,其为副节点。对节点的修改同理。
// 获取当前副本集的配置信息,并将其存储在变量cfg中
cfg = rs.conf();// 直接修改cfg对象中的members数组的第3个元素(索引为2,因为索引从0开始)
// 这个操作是在内存中修改副本集的配置,还没有应用到副本集
myrepl:PRIMARY> cfg.members[2] = { "_id": 2, // 为新成员指定一个唯一的_id"host": "127.0.0.1:27019", // 指定新成员的主机地址和端口"votes": 1, // 允许新成员参与选举,拥有1票"priority": 1 // 设置新成员的优先级为1,这意味着它可以被选举为主节点
};// 使用rs.reconfigForPSASet方法重新配置副本集
// 这里的2表示我们正在修改members数组中的第3个成员(索引为2)
// cfg是我们刚刚修改过的包含新成员信息的配置对象
rs.reconfigForPSASet(2, cfg);
rs.reconfigForPSASet()
rs.reconfigForPSASet()
方法是 MongoDB 中用于在 PSA(Primary-Secondary-Arbiter)模式的副本集中安全添加或修改副节点的函数。
rs.reconfigForPSASet( memberIndex: <num>, config: <configuration>, { "force" : <boolean>, "maxTimeMS" : <int> })
-
memberIndex
:正在添加或修改的从节点的索引。 -
config
:用于指定副本集新配置的文档。 -
force
:可选参数,不建议使用force: true
,因为这可能导致已提交的写入操作回滚。 -
maxTimeMS
:可选参数,指定在rs.reconfigForPSASet()
操作期间处理每次重新配置的累积时间限制(以毫秒为单位)。
rs.reconfigForPSASet()
分两步重新配置副本集:
- 首先,使用
{ votes: 1, priority: 0 }
添加或修改从节点。 - 一旦添加或修改的从节点赶上所有已提交的写入,请重新配置从节点以具有非零优先级
{ votes: 1, priority: <num> }
。