MongoDB_副本集

  1. 什么是副本集?

    在MongoDB中创建一个副本集之后就可以使用复制功能了。副本集是一组服务器,其中有一个主服务器(primary),用于处理客户端请求,还有多个备份服务器(secondary),用于保存主服务器的数据副本。如果主服务器崩溃了,备份服务器会自动将其中一个成员升级为新的主服务器。

  2. 同步

    MongoDB的复制功能是使用操作日志oplog实现的,操作日志包含了主节点的每一次写操作。oplog是主节点的local数据库中的一个固定集合。备份节点通过查询这个集合就可以知道需要进行复制的操作。
    每个备份节点都维护着自己的oplog,记录着每一次从主节点复制的数据。这样每个成员都可以作为同步源提供给其他成员使用

  3. 初始化同步

    应该只在不需要暴露现有数据的情况下做初始化同步(或者将数据移到其他地方),因为mongod会首先将现有数据删除。
    克隆过程中的所有操作都会被记录到oplog中,如果有文档在这个过程中被移动了,就有可能会被遗漏,这样的文档需要重新克隆。
    初始化同步过程中经常遇到的问题是,克隆或创建索引耗费太长时间,导致新成员就与同步源的oplog“脱节”:新成员远远落后于同步源,导致新成员的数据同步速度赶不上同步源的变化速度,同步源会将新成员需要复制的某些数据覆盖掉。
    这个问题没有有效的解决办法,除非在不太忙时执行初始化同步,或者是从备份中恢复数据。

  4. 处理陈旧数据

    如果备份节点远远落后与同步源当前的操作,那么这个备份节点就是陈旧的。它会查看副本集中的其他成员,如果某个成员的oplog足够相近,可以用于处理那些落下的操作,就从这个成员处进行同步。为了避免陈旧节点的出现,让主节点使用比较大的oplog保存足够多的操作日志是很重要的。

  5. 心跳

    为了维护集合的最新视图,每个成员每隔两秒钟就会向其他成员发送一个心跳请求,用于检查每个成员的状态,以及让主节点知道自己是否满足“大多数”的条件。

  6. 建立副本集:

    使用–nodb选项启动一个mongo shell,这样可以启动shell但不连接到任何mongod:

    $ mongo --nodb
    

    通过下面的命令创建一个副本集:

    replicaSet = new ReplSetTest({“nodes”:3})

    该命令创建了一个包含三个服务器的副本集:一个主服务器和两个备份服务器。执行以下命令后Mongod服务器正式启动:

    replicaSet.startSet()
    replicaSet.initiate()

    现在有了3个mongod进程,分别运行在31000、31001、31002端口。
    另启一个shell连接运行在31000端口的mongod:

    conn1 = new Mongo(“localhost:31000”)

    不能对备份节点执行写操作。备份节点只通过复制功能写入数据,不接受客户端的写入请求。默认情况下客户端不能从备份节点读取数据,在备份节点上显式地执行setSlaveOk之后,客户端就可以从备份节点中读取数据了。
    测试自动故障转移功能:
    关掉主节点:

    primaryDB.adminCommand({“shutdown”:1})

    在备份节点执行isMaster():

    secondaryDB.isMaster()

    关闭副本集命令:

    replicaSet.stopSet()

  7. 配置副本集

    假设有一个运行在server1:27017上的单个mongod实例,首先为副本集选定一个名字:

    server1$ mongod --replSet spock -f mongod.conf --fork
    

    再启动两个mongod服务器作为副本集中的其他成员:

    server2$ mongod --replSet spock -f mongod.conf --fork
    server3$ mongod --replSet spock -f mongod.conf --fork
    

    创建一个配置文件,在配置文件中列出每一个成员,并且将配置文件发送给server1,然后server1会负责将配置文件传播给其他成员:

    config={
    “_id”:”spock”,
    “members”:[
    {“_id”:0,”host”:”server1”27017”},
    {“_id”:1,”host”:”server2”27017”},
    {“_id”:2,”host”:”server3”27017”}
    ]
    }

    将config对象发送给有数据的服务器:

    db=(new Mongo(“server1:27017”)).getDB(“test”)
    rs.initiate(config)

  8. 修改副本集配置:

    为副本集添加新成员:

    rs.add(“server4:27017”)

    从副本集中删除成员:

    rs.remove(“server1:27017”)

    重新配置副本集之后,副本集中会暂时没有主节点,之后会恢复正常。
    查看配置是否成功:

    rs.config()

    修改配置:

    var config=rs.config
    config.members[1].host=”server2:27017”
    rs.reconfig(config)

  9. 设计副本集:

    副本集中一个很重要的概念是“大多数”:选择主节点需要得到大多数节点支持,数据写入大多数节点是安全的。如果副本集中有些成员不可用,并不会影响大多数。因为大多数是基于副本集计算的。
    下面是两种推荐的配置:
    ① 将“大多数”成员放在同一个数据中心。
    ② 在两个数据中心各自放置数量相等的成员,在第三个地方放置一个用于决定胜负的副本集成员

  10. 选举机制

    当一个备份节点无法与主节点联通时,它就会联系并请求其他的副本集将自己选举为主节点。其他成员会做几项理性的检查:自身是否能够与主节点联通?希望被选举为主节点的备份节点的数据是否最新?有没有其他更高优先级的成员可以被选举为主节点?

  11. 成员配置选项

    ① 选举仲裁者
    仲裁者的唯一作用就是参与选举。仲裁者不保存数据,也不为客户端提供服务:它只是为了帮助具有两个成员的副本集能够满足“大多数”这个条件。
    启动仲裁者:

    rs.addArb{“server5:27017”}

    或者

    rs.add({“_id”:4,”host”:”server5:27017”,”arbiterOnly”:true})

    成员一旦以仲裁者的身份添加到副本集中,它就永远只能是仲裁者。
    最多只能使用一个仲裁者,并且应该是加入仲裁者之后总的成员数为奇数。
    如果可能,尽可能在副本集中使用奇数个数据成员,而不要使用仲裁者。

    ② 优先级
    优先级用于表示一个成员渴望成为主节点的程度,用0~100表示。默认是1,优先级0表示永远不能够成为主节点,这样的成员称为被动成员。
    设置优先级并不会导致副本集中选不出主节点,也不会使数据不够新的成员成为主节点。优先级的值只会影响副本集成员间相对优先级的大小关系。

    ③ 隐藏成员
    客户端不会向隐藏成员发送请求,隐藏成员也不会作为复制源(尽管当其他复制源不可用时隐藏成员也会被使用),因此,很多人会将不够强大的服务器或者备份服务器隐藏起来。为了隐藏server3,可以在它的配置中指定hidden:true。只有优先级为0的成员才能被隐藏(不能将主节点隐藏)

    var config=rs.config
    config.members[2].hidden=0
    config.members[2].priority = 0
    rs.reconfig(config)

    要将隐藏成员设为非隐藏,只需要将配置中的hidden设为false就可以了,或者删除hidden选项

    ③ 延迟备份节点
    延迟备份节点的数据会比主节点延迟指定的时间(单位是秒)。可以使用slaveDelay设置一个延迟的备份节点。slaveDelay要求成员的优先级是0。如果应用会将读请求路由到备份节点,应该将延迟备份节点隐藏掉。

    ④ 创建索引
    备份节点并不需要与主节点拥有相同的索引,甚至可以没有索引。如果某个备份节点的用途仅仅是处理数据备份或者是离线的批量任务,那么可以通过设置“buildIndexs”:false阻止备份节点创建索引。这是一个永久选项,指定了“buildIndexs”:false的成员永远无法恢复为可以创建索引的正常成员。

  12. 客户端到副本集的连接

    驱动程序连接到某个种子服务器之后,就能够得到其他成员的地址:

    “mongodb:server1:2017,server2:2017”
    
  13. 当希望应用程序在主节点挂掉时仍然可以执行读操作(并且你不在意读到的数据是否是最新的),这是可以将读请求发送给备份节点。失去主节点时,应用程序进入只读状态,这种读选项叫做主节点优先。从备份节点读数据有一个常见的参数,将读选项设置为Nearest,以便将读请求路由到延迟最低的成员。
    如果应用程序能够接受任何陈旧的数据,希望主节点只处理写请求,就可以使用Secondary读选项,这会使得读请求始终发送给备份节点
    Secondary preferred会优先将读请求路由到可用的备份节点,如果备份节点都不可用,请求就会被发送到主节点

你可能感兴趣的:(MongoDB)