Mongodb 笔记06 副本集的组成、从应用程序连接副本集、管理

时间:2021-06-29 16:24:51

副本集的组成

1. 同步:MongoDB的复制功能是使用操作日志oplog实现的,操作日志包含了主节点的每一次写操作。oplog是主节点的local数据库中的一个固定集合。备份节点通过查询整个集合就可以知道要进行

复制的操作了。每个备份节点都维护者自己的oplog,记录每一次从主节点复制数据的操作。这样,每个成员都可以作为同步源提供给其他成员使用。

2. 将oplog中的同一个操作执行多次,与只执行一次的效果是一样的。如果单个操作会影响多个文档,那么每个受影响的文档都会对应oplog中的一条日志。例如db.remove()删除了10个文档,那就对应十条日志记录。

3. oplog是主节点的local数据库中的一个固定集合。先从数据库同步数据,然后从日志里同步以后的数据。

4. 为了避免陈旧备份节点的出现,让主节点使用比较大的operlog保存足够多的操作日志是很重要的。大的operlog会占用更多的磁盘空间,通常来说,这是一个比较好的折衷方案,因为磁盘会越来越便宜。

而且实际中使用的oplog只有一小部分,因此oplog不会占用太多RAM。

5. 心跳:为了维护最新的视图,每个成员每隔两秒就会向其他成员发送一个心跳请求。心跳请求的信息量非常小,用于检查每个成员的状态。心跳最重要的功能之一就是让主节点知道自己是否满足集合"大多数"

的条件。如果主节点不再得到"大多数"服务器的支持,它就会退位,变成备份节点。

6. 成员状态:主节点,备份节点,STARTUP(成员刚启动),STARTUP2(初始化同步过程),RECOVERING(正常,但暂不能处理读请求),ARBITER(仲裁者状态)

7. 系统出问题时会处于一下状态:DOWN(不可达),UNKNOW(),REMOVED(成员被移除时),ROLLBACK(回滚中),FATAL(错误)

8. 回滚:有些情况下,回滚可能会导致数据丢失,这些丢失的数据被保存到一个.bson文件中,可以手动恢复。

9. 某些情况下,如果要回滚的内容太多,MongoDB可能承受不了。如果要回滚的数量大于300M,或者要回滚30分钟以上的操作,回滚就会失败。对于回滚失败的节点,必须要重新同步。

从应用程序连接副本集

1. 默认情况下,驱动程序会连接到主节点,并且将所有请求都路由到主节点。应用程序可以像使用单台服务器一样进行读和写,副本集会在后台默默处理热备份。

2. 之前,我们使用getLastError命令检查写入是否成功。也可以使用这个命令确保写入操作被复制到备份节点。参数"w"会强制要求getLastError等待,一直到给定数量的成员都执行完了最后的写入操作。

    MongoDB有一个特殊的关键字可以传递给"w",就是"majority"。  db.runCommand({"getLastError":1,"w":"majority"}) 输出字段中wirttenTo表示操作被复制到了哪些服务器上。

3. db.runCommand({"getLastError":1,"w":"majority","wtimeout":1000})    设置等待超时时间。

4. 通常将"w"用于控制写入速度读。MongoDB的写入速度太快,主节点上执行完写入操作后,备份节点还来不及跟上。阻止这种行为的一种常用方式是定期调用getLastError,将"w"参数指定为大于1的值。

    这样会强制这个连接上的写操作一直等待知道复制成功。注意:这只会阻塞这个连接上的写操作,其他连接上的写操作仍然会被立即执行完成并返回。

5. 如果希望应用程序的行为更自然更健壮,应该定期调用getLastError,同时指定majority和一个合理的超时时间。如果这个命令超时了,需要找出出错原因。

6. "w"的值也可以为一个整数(N),表示当操作成复制到N-1(主节点减一)个从节点后,返回成功的结果。

7. 自定义复制保证规则:

1). 保证复制到每个数据中心的一台服务器上

2). 保证写操作被复制到可见节点的"大多数"

3). 创建其他规则。可以无限制的创建各种规则。记住,创建自定义规则的两个步骤(上面两条也使用):

a. 使用键值对设置成员的"tags"字段。

b. 基于刚刚创建的分组创建规则。

规则是一种非常强大的副本集配置方式,虽然它理解和设置起来都有些复杂。除非有非常特殊的复制要求,否则使用"w":"majority"就已经非常安全了。

8. 默认情况下,驱动程序会将所有的请求都路由到主节点。可以通过设置驱动程序的读取首选项配置其他选项。可以在读选项中设置需要将查询路由到的服务器的类型。

9. 不建议将请求发送到备份节点的原因:

1). 出于一致性考虑:备份节点有时可能因为加载问题、配置错误、网络故障等原因,备份节点可能会落后主节点几分钟,几小时,甚至几天。

2). 出于负载的考虑:这种扩展方式非常危险,很容易导致系统意外过载,一旦出现这种问题,很难恢复。导致恶性循环。

10. 何时可以从备份节点读取数据:主节点挂掉时,仍然能执行读操作,并且你并不在意读到数据是否为最新。

如果要从一个落后的备份节点读取数据,就要牺牲一致性。另一方面,如果希望写操作返回之前被复制到所有副本集成员,就要牺牲写入速度。

可以使用Secodary (只访问备份节点)和 Secondary preferred(备份节点挂了,可以访问主节点) 端选项设置,修改访问到备份节点。

11. 如果某些请求必须从主节点读取数据,那就对这些请求使用Primary选项。如果另一些读请求并不要求数据是最新的,那么可以对这些读请求使用Primary preferred选项。如果某些请求对

      低迟延的要求大过一致性要求,那么可以使用Nearest选项。

12. 可以考虑在备份节点建立一个单独索引,然后客户单直接连接到这个备份节点上。

管理

1. 以单机模式启动成员:是指要重启成员服务器,让它成为一个单击运行的服务器,而不再是一个副本集成员(这只是临时的)。

如果要对一台服务器进行维护,可以重启服务器,重启时不使用replSet选项。这样它就会成为一个单击的mongod,可以对其进行读和写。我们不希望副本集中的其他服务器联系到这台服务器,

所以可以让它监听不同的端口(这样副本集的其他成员就找不到它了)。最后,保持dbpath的值不变,因为重启后要对这台服务器的数据做一些操作。举例:mongod --port 3000 --dbpath /var/lib/db

2. 副本集配置总是以一个文档的形式保持在local.system.replSet集合中。

3. 创建副本集:首先启动所有成员服务器,然后使用rs.initiate命令将配置问答经传递给其中一个成员。

var config = { "_id":"spock", "members":[{"_id":0,"host":"server-1:27017"},{"_id":0,"host":"server-2:27017"},{"_id":0,"host":"server-3:27017"}]}

rs.initiate(config)

只需要对副本集中的一个成员调用rs.initiate就可以了。收到initiate命令的成员会自动将配置和传递给副本集中的其他成员。

4. 修改副本集成员。可以查看 创建副本集 模块

5. 创建比较大的副本集:副本集最多只能拥有12个成员,其中只有7个成员拥有投票权。这是为了减少心跳请求的网络流量和选举花费的时间。如果要创建7个以上成员副本集,只有7个成员可以拥有投票权,

需要将其他成员的投票数量设置为0:rs.add({"_id":7,"host":"server-7:27017","votes":0})。如果希望某个成员可以优先被选举为主节点,应该使用优先级。

6. 强制重新配置:如果副本集无法再达到"大多数"要求的话,那么它就无法选举出新的主节点,这是你可能会希望重新配置副本集。这种情况下,可以在备份节点上调用rs.reconfig强制重新配置副本集。在

shell中连接到一个备份节点,使用"force"选项执行rs.reconfig命令。

7. 修改成员状态:

1). 把主节点变为备份节点:rs.stepDown() 默认维持60秒,如果这期间没有新的主节点产生。这个节点可以要求重新进行选举。也可以添加参数:rs.stepDown(600)  降为主节点10分钟。

2). 阻止选举:如果需要对主节点进行一些维护,但是不希望这段时间内将其他成员选举为主节点,那么可以在备份节点上执行freeze命令,以强制他们始终处于备份节点状态:

rs.freeze(1000) 这个命令以秒为单位,表示多长时间内保持备份状态。调用rs.freeze(0) 恢复备份节点被选举的权力。

也可以在主节点上执行rs.freeze(0),这样可以将退位的主节点重新变为主节点。

3). 维护模式:当在副本集成员上执行某个非常耗时的操作时,这个成员就进入了维护模式:强制成员进入RECOVERING状态。有时,成员会自动进入维护模式,比如在成员上做压缩时。

可以通过repletMaintenanceMode命令强制一个成员进入维护模式。维护模式下的备份节点不再处理读请求。可以一次提高服务器性能,更快的从主节点复制数据。

8. 监控复制:

1). 查看日志

2). replSetGetStatus 命令,可以返回副本集中每个成员的当前信息。这个命令还有一个对对应的辅助函数:rs.status() 。可以返回成员的状态,更新时间,最后一次心跳时间等。

这份报告是由rs.status()命令的成员角度得出的:由于网络故障,这份报告可能不准确或过时。

9. 复制图谱:如果在备份节点上运行rs.status(),输出信息中会有一个名为syncingTo的*字段,用于表示当前成员正从哪个成员处复制。如果在每个成员上运行该命令,就可以弄清楚复制图谱。

副本集成员要么从主节点复制,要么从数据比它新的成员处复制。自动复制链越长,经写操作复制到所有服务器所花费的时间就越长。

可以通过replSetSyncFrom(或者辅助函数rs.syncFrom())命令修改成员的复制源来进行修改。

10. 复制循环:正常情况下不会产生,除非强制修改了复制源。

11. 禁用复制链:将allowChaing设置为false之后,所有成员都会从主节点复制数据。如果主节点变得不可用,那么各个成员就从其他备份节点复制数据。

12. 计算延迟:在备份节点上运行db.printSlaveReplicationInfo() ,可以得到当前成员的复制源,以及当前成员相对复制源落后的程度等信息。延迟并不表示需要多长时间才能更新到最新数据。也可能

是写操作比较少,造成延迟过大的幻觉。很快就会更新到最新数据。

13. 调整oplog大小:每一个可能成为主节点的服务器都应该拥有足够大的oplog,以预留足够的时间窗用于进行维护。

增加oplog大小的步骤:如果当前服务器是主节点,让它退位,以便让其他成员的数据能够尽快更新到与它一直;关闭当前服务器;将当前服务器以单机模式启动;临时将oplog中最后一条insert操作

保存到其他集合;删除当前oplog;创建一个新的oplog;将最后一条操作记录写会oplog;将当前服务器作为副本集成员重新启动。

14. 从延迟节点中恢复: 

第一种方法:关闭所有其他成员;删除其他成员数据目录中的所有数据;重启所有成员

第二种方法:关闭所有成员,包括延迟备份节点;删除其他成员的数据目录;将延迟节点的数据文件复制到其他服务器;重启所有成员

15. 创建索引

1). 如果向从节点发送创建索引的命令,主节点会正常创建索引,然后备份节点在复制"创建所有"操作时也会创建索引。这是最简单创建索引的方式,但创建索引是一个需要消耗大量资源的操作,

可能会导致成员不可用。如果所有备份节点都在同一时间开始创建索引,那么几乎所有成员都会不可用,一直到索引创建完成。

2). 只在一个成员上创建索引,以降低对应用程序的影响:

关闭一个备份节点服务器;将这个服务器以单机模式启动;在单机模式下创建索引;索引创建完成之后,将服务器作为副本集成员重新启动;对副本集中的每个备份节点重复前面的步骤。

3). 副本集从节点都创建完索引后,主节点创建索引的选择:

a. 在主节点上创建索引。在系统"空闲期"创建索引,是一个不错的选择。或者修改读取首选项,在主节点创建索引期间,将读操作发送到备份节点上。备份节点上已有索引,不会再复制索引。

b. 主节点退化为备份节点。执行上面备份节点创建索引的步骤。

4). 可以为备份节点创建与其他成员不同的索引。这种方式在做离线数据处理时会非常有用,但是,如果某个备份节点的索引与其他成员不同,那么它永远不能成为主节点:应该将它的优先级设为0

16. 在预算有限的情况下进行复制

17. 主节点如何跟踪延迟:作为其他成员同步源的成员会维护一个名为local.slaves的集合,这个集合中保存着所有正从前成员进行数据同步的成员,以及每个成员的数据新旧程度。

可以通过:db.slaves.find() 方法查看延迟。local.slaves集合实际上是内存中数据结构的"回声",所以其中的数据可能会有几秒的延迟。

网络故障可能会导致slaves中出现"_id" 相同的记录,需要登录到每台mongod,删除local.me集合,重启mongod。

"影同步" 保证复制链中的复制信息也会发送到主节点。

如果服务器地址发生了变化,可能会在本地数据库中看到异常。遇到这种情况,删除local.slaves集合即可。

mongod不会自动清理slaves集合。

18. 主从模式:有两种模式应该使用主从模式而不是副本集:需要多于11个备份节点 ,或者需要复制单个数据库。否则,除非不得已,都应该使用副本集。