Mongodb Manual阅读笔记:CH8 复制集

8 复制

Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作
Mongodb Manual阅读笔记:CH3 数据模型(Data Models)
Mongodb Manual阅读笔记:CH4 管理
Mongodb Manual阅读笔记:CH5 安全性
Mongodb Manual阅读笔记:CH6 聚合
Mongodb Manual阅读笔记:CH7 索引
Mongodb Manual阅读笔记:CH8 复制集
Mongodb Manual阅读笔记:CH9 Sharding

 

8 复制... 1

8.1复制说明... 2

8.1.1复制的目的... 3

8.1.2 MongoDB中的复制... 3

8.1.2.1 异步复制... 4

8.1.2.2 动故障转移... 4

8.1.2.3 额外功能... 4

8.2复制概述... 4

8.2.1复制集成员... 5

8.2.1.1 Primary成员... 5

8.2.1.2 Secondary成员... 6

8.2.1.3仲裁成员... 7

8.2.2复制集部署结构... 8

8.2.2.1策略... 8

8.2.2.2 部署方案... 9

8.2.3复制集高可用... 10

8.2.3.1故障转移... 10

8.2.3.2在故障转移时rollback. 11

8.2.4 复制集中的读和写... 11

8.2.4.1复制集的写注意... 12

8.2.4.2读偏好... 13

8.2.4.3读偏好过程... 14

8.2.5复制过程... 15

8.2.5.1复制集oplog. 15

8.2.5.2复制集数据同步... 16

8.2.6 主从复制... 17

8.2.6.1基本操作... 17

8.2.6.2主从配置选项... 18

8.2.6.3安全性... 18

8.2.6.4管理和主从复制部署... 18

8.3复制集教程... 20

8.3.1复制集部署教程... 20

8.3.1.1部署复制集... 20

8.3.1.2测试或开发环境部署复制集... 21

8.3.1.3部署多地理位置复制集... 22

8.3.1.4添加仲裁... 23

8.3.1.5把单实例转化为复制集... 24

8.3.1.6添加成员到复制集... 24

8.3.1.7删除成员... 25

8.3.1.8替换复制集成员... 25

8.3.2成员配置教程... 26

8.3.2.1配置适当的复制集成员... 26的优先级

8.3.2.2防止secondary变成primary. 26

8.3.2.3配置隐藏成员... 26

8.3.2.4配置延迟成员... 27

8.3.2.5配置非投票成员... 27

8.3.2.6secondary转为仲裁... 28

8.3.3复制集维护教程... 28

8.3.3.1修改Oplog大小... 28

8.3.3.2强制成员变成primary. 29

8.3.3.3重新同步成员... 30

8.3.3.4配置复制集Tag. 31

8.3.3.5有不可用成员... 33重新配置复制

8.3.3.6管理复制链... 33

8.3.3.7修改复制集中的主机名... 34

8.3.3.8配置secondary的同步目标... 35

8.3.4复制集故障排除... 36

8.3.4.1检查复制状态... 36

8.3.4.2检查复制延迟... 36

8.3.4.3测试成员之间的连接... 36

8.3.4.4多个成员重启导致socket异常... 36

8.3.4.5检查oplog大小... 37

8.3.4.6 Oplog文档时间戳错误... 37

8.3.4.7重复键错误... 37

8.4复制指南... 38

8.4.1 mongo shell上的复制方法... 38

8.4.2复制命令... 38

8.4.3复制集参考文档... 39

8.4.3.1复制集命令... 39

8.4.3.2复制集配置... 39

8.4.3.3 local数据库... 40

8.4.3.4复制集状态... 41

8.4.3.5读偏好... 42

 

Mongodb中的数据库复制集是一组mongod进程,维护了同一个数据集。复制集提供了冗余和高可用,是所有产品部署的基础。

8.1复制说明

复制是一个用来同步数据到多个服务的处理

8.1.1复制的目的

复制提供了融合和高可用,多个数据拷贝放在不同的数据服务上,以免出现单点故障,就算出现硬件错误也可以恢复,当出现问题的时候,只要把其中一个拷贝来替换原来的即可。

有时候也可以使用复制,来做读写分离,客户端可以指定从不同的服务上读取。

8.1.2 MongoDB中的复制

复制集是一组mongod实例维护了同一份数据,primary接受所有的写入。Secondaryprimary上获取这些写入然后应用到本地。

Primary接受所有client的写入操作,并且一个复制集只能有一个primary,这样才能提供严格的一致性。Primary把所有的写入操作都放在一个叫oplog的地方。

Secondary复制primaryoplog然后应用到自己的数据集上,secondary就是primary的一个影子,当primary不可用时,复制集会选一个secondary变成primary。客户端默认从primary读取数据,也可以通过制定读偏好,从secondary上读取。

当然你可以增加一个仲裁服务,仲裁没有数据,但是可以投票选出primary,如果你的复制集的成员是偶数的,可以增加一个仲裁,仲裁对硬件基本没什么要求。

Mongodb Manual阅读笔记:CH8 复制集

8.1.2.1 异步复制

Secondaryprimary上应用操作是异步的,在primary之后应用到secondary,虽然有些成员还是没有,但是复制集还可以继续运行,唯一的问题是secondary不能反映当前的数据状态。

8.1.2.2 自动故障转移

primary不能和其他成员交互超过10s,复制集会试图选择一个成员变成primary

Mongodb Manual阅读笔记:CH8 复制集

8.1.2.3 额外功能

复制集提供了一些选项来支持应用程序的需要,如,成员在多个数据中心,通过优先级来控制是否可以变成primary

8.2复制概述

介绍了复制集的选项,配置和特性

8.2.1复制集成员

复制集是一组mongodb提供的冗余和高可用,成员如下:

Primary,接受所有的写操作

Secondary,从primary上复制数据,唯一同一份数据。Secondary可以有额外的配置来用于特殊的使用。

还有一个就是仲裁,仲裁不维护数据,但是当当前primary不可用,仲裁可以投票给一个成员选出一个primary

一个复制集最多只能有12个成员,只有7个成员可以投票。最小的复制配置是1primary1secondary1个仲裁,或者1primary2secondary

Mongodb Manual阅读笔记:CH8 复制集

Mongodb Manual阅读笔记:CH8 复制集

8.2.1.1 Primary成员

Primary是唯一一个可以接受写入的成员,写入到primary之后然后记录到primaryoplog,然后secondary复制这些日志应用这些操作。

所有成员都可以接受读操作,默认应用程序会直接从primary上读取。

复制集只能有一个primary,也必须要有一个,当当前的primary不可用,可以换一个。

8.2.1.2 Secondary成员

Secondary维护了primary的数据备份,然后通过应用primaryoplog来异步的更新数据。一个复制集可以有多个secondary

客户端不能写入到secondary只能从secondary上读取。当primary不可用,复制集会从secondary上选一个。

还可以配置secondary

1.为了防止secondary变成primary,可以把优先级设为0

2.为了防止secondary读取可以把secondary设置为隐藏

3.用来维护一个历史的快照,用来恢复认为的错误。

优先级设置为0 成员

优先级为0secondary不能变成primary

把优先级为0的作为准备:因为当数据大的时候新增一个节点有困难,准备节点可以很快的去替换现在不可用的节点。一般是不太用准备节点,但是在不同硬件设备,不同物理环境状况下,0优先级可以保证可以选到一个合格的primary

0优先级和故障转移:考虑到潜在的故障,把优先级设置为0,并且保证你的主要数据中心包含了所有的合格可以变成primary的成员和可以投票的成员。

Mongodb Manual阅读笔记:CH8 复制集

隐藏成员

隐藏成员维护了primary的数据备份,但是对应用程序不可见。隐藏成员用来其他使用,隐藏成员难道优先级都为0,不能变成primary。使用db.isMaster()不显示隐藏成员,但是隐藏成员可以投票。

客户端的读取不能从隐藏成员上读取,隐藏成员一般用来做报表或者用来备份。如果用来备份,就要让隐藏成员尽量接近primary

为了避免隐藏成员关闭mongod,可以使用db.fsyncLock()来刷新所有的写入,并且在备份期间锁定mongod

Mongodb Manual阅读笔记:CH8 复制集

延迟成员

延迟成员,是primary数据的一个延迟。如果出现人为的错误,可以使用延迟成员来恢复。

要求:

1.优先级必须为0,2.不许是隐藏的,3.可以投票。

延迟成员是延迟应用oplog,所以当选择延迟时间的时候要考虑以下2点:

1.必须大于等于你的维护窗口

2.必须小于oplog的能力。

Mongodb Manual阅读笔记:CH8 复制集

8.2.1.3仲裁成员

仲裁不包含数据也不能成为primary,但是复制集可以增加一个仲裁来一起投票primary。仲裁可以让复制集成员变成奇数,但是不用复制数据。

当成员是偶数的时候再加仲裁。如果你把仲裁加入到一个奇数成员个数的集中,复制集可能会无法产生primary

Mongodb Manual阅读笔记:CH8 复制集

安全性

当启用auth的时候,仲裁会和其他成员交换凭据,仲裁使用keyfiles来验证到复制集。

交互:只有仲裁要投票,心跳,配置的时候才会和其他成员交互。当然也可以运行在可信任网络下。

8.2.2复制集部署结构

复制集的结构影响了复制集的容量和能力,标准的复制集是3个成员,这个成员提供了冗余和故障切换。尽量避免复杂,但是也可以让你的应用程序来决定结构。

8.2.2.1策略

决定成员个数

部署一个奇数成员:计数成员可以保证总是可以选出一个primary。如果成员是偶数的,那么假一个仲裁。仲裁只消耗很少的资源。

考虑错误容量:错误容量是有多少成员变的不可用了,但是还是可以选出primary。错误容量和复制集大小并不是直接相关的。也就是复制集的成员和选出primarymajority成员的差。

Mongodb Manual阅读笔记:CH8 复制集

在复制集上面加成员并不能增加错误容量。

使用隐藏和延迟成员来做特定的需求:可以用来备份,报表,和认为错误的恢复。

读负载均衡:如果有很高的读请求,可以从secondary上读来减少primary的读请求。

在需求前加容量:如果有加能力的需求要在需求提出之间加,就是必须要有备用的能力。

决定成员分布

地理位置上分布:为了保护主数据中心错误,至少要有一个节点在其他数据中心,并把这些成员的优先级设置为0

majority成员放在同一个数据中心:如果复制集成员在不同的数据中心,网络问题会导致数据中心之间无法交互。对于复制数据来说,成员间必须可以交流,并保持

保证成员可以创建一个majority,确认majority并且选一个primary。并在一个数据中心保持复制集成员的majority

使用Tag来确定操作目标:使用复制集tag来保证要操作某个复制集成员。

使用Journal来保护断电:可以使用journal来保护服务突然中断

8.2.2.2 部署方案

有以下几种部署模式:3成员复制集,4个或者更多复制集,多地理位置复制集。

3成员复制集

最小的结构就是3个成员,有2个方案2secondary1primary或者1secondary1个仲裁,1primary

2Secondary:这个方案任何时间都有2个数据备份,提供了错误容量和高可用。当primary不可用,会选一个secondary边长primary,然后继续运行,如果primary恢复会重新加入到复制集

1仲裁1Secondary:仲裁不保存数据,需求的资源也不是很大,但是限制了融合和错误容量。

但是这种方案,当primarysecondary任意一个不可用是,还是可以保持可用。如果primary不可用会选出一个primary

4个或者更多复制集

尽管标准的复制集是3个成员,但是增加一个成员也就正价了能力和冗余,可以用来读写分离。

增加成员保证:

1.集合是奇数个投票成员

2.虽然最多有12个成员,但是只有7个可以投票。

3.优先级为0的不能成为primary

4.majority成员应该在主数据中心

多地理位置分布复制集

在多个数据中心增加到复制集,增加了冗余和错误容量。在其他数据中心的成员应该把优先级设置为0 ,防止他们变成primary

多地理位置结构应该:

1.一个primary在主数据中心

2.一个secondary在主数据中心,这个成员在任何时间变为primary

3.优先级为0的再第二个数据中心,这个成员不能变成primary

如果primary不可用,复制集会从主数据中心中选一个变成primary。如果数据中心不能相互连接,在第二个数据中心中的成员不能成为primary

如果datacenter变成不可用,可以很快的通过手动方式来恢复第二个数据中心上的成员。

为了促成投票,主数据中心应该要保持绝大多数成员,并且保证复制集成员是奇数个,如果增加一个成员变成了偶数,就应该部署一个仲裁。

8.2.3复制集高可用

复制集使用自动故障转移来提供高可用性,高可用性可以让secondaryprimary不可用时变成primary

如果primary不可用,复制集会开始一个选举,来产生新的primary。在某些情况下故障转移需要请求rollback

8.2.3.1故障转移

复制集选举,在故障转移时回滚。

复制集选举

复制集使用选举的方法来确定成员是否会变长primary,在初始化复制集之后也会选举,任何primary不可用也会选举。primary是唯一一个可以写入的成员。当primary不可用,复制集会中恢复正常状态。

影响选举的条件和因素

心跳:如果心跳没有在10s中内返回,其他成员就会标记这个成员不可用

优先级:优先级影响选举,成员会给优先级最高的成员投票。所以优先级为0的不能成为primary

primary是优先级最高的,并且在最新oplog10s只能复制集不会发起投票。如果一个更高的成员oplogprimary差距在10s只能,复制集会投票让给最高优先级的节点。

Optimeoptimeoplog的时间戳,一个复制集成员不可能成为primary除非它的optime比其他成员都高。

连接:只有能连接到大多数成员的复制集成员才有可能成为primary

如果只有3个成员每一个都有一个vote,如果2个成员可以互相连接就可以选出来,如果2个成员不可用,剩下一个secondary不能变成primary。(因为票不够)。

网络分区:不再同一个网络会影响投票。如果primary被关闭,任何一方都没有形成大多数成员,那么就无法产生primary。为了避免这个状况保持却大多数成员在同一个数据中心。

投票(选举)机制

投票触发事件1.初始化一个复制集。2.secondaryprimary连接丢失,3.primary关闭

以下状况下primary会关闭:

1.收到一个replSetStepDown命令

2.如果有1个成员合格变为primary并且优先级最高

3.如果primary不能和大多数的成员交互。

参与投票:每个成员有一个优先级来表示是否可以合格成为primary。默认每个成员的优先级为1。优先级表示最有可能成为primary的权重。通过指定优先级让有能力变成primary的成员的放在一个数据中心。

得到票数最多的成员变成primary,默认所有成员只有1vote,只有在以下状态可以votePRIMARY, SECONDARY, RECOVERING, ARBITER, ROLLBACK

否决投票:所有的成员都可以否决投票以下状况下会否决:

1.如果不是vote成员

2.在成员中并不是最新的

3.优先级比别人低

4.如果一个优先级为0 的成员是最接近primary的成员,这种状况下另外一个合格成员catch up状态,并试图成为primary

5.如果当前的primary比选出来的成员要新

非投票成员:非投票成员不能投票,但是可以否决结果。vote0 即为非投票成员。尽量不要修改vote个数大于1,不然可能会出现问题。

8.2.3.2在故障转移时rollback

rollback是把之前primary的写操作还原,如果primary在写操作结束之前就不可用了,那么就要回滚写入,使用rollback来维持数据的一致性。

mongodb试图避免回滚,但是往往都是secondary不能及时赶上primary才导致回滚。

收集回滚数据:当回滚发生,管理员可以决定是否应用这些回滚。mongodb会把回滚数据写在rollback下的bson文件中。

只有应用了回滚数据,成员才能回滚。使用bsondump读取,使用monogorestore来应用到新的primary

避免复制集回滚:使用写注意保证写入操作传播到了复制集其他成员。

回滚限制mongod实例不会回滚超过300MB的回滚数据,只能使用初始化同步来初始化

8.2.4 复制集中的读和写

对于应用程序来说,复制集是透明的,默认客户端从primary上读写。当然客户端可以通过读偏好从其他成员上读取数据。但是secondary不能保证和primary的严格一致性。

为了保证一致性,你可以配置客户端和驱动来保证写入操作在完成前都已经写入到所有的成员上。

复制集的写注意,读偏好,读偏好过程。

8.2.4.1复制集的写注意

写注意使用getLasterError命令来返回写入操作完成之后的信息。

验证写入操作

默认写入操作只写到primary,通过getLastErrorw参数让写入操作写入到secondary。当wmajority会写入到集群的大多数成员。

如果指定的w值大于成员个数,会导致操作一直被堵塞,当然可以指定超时时间,超时退出。

修改默认的写注意

在复制集中可以通过getLastErrorDefault来修改默认的getLastError的行为。

cfg = rs.conf()

cfg.settings = {}

cfg.settings.getLastErrorDefaults = {w: "majority"}

rs.reconfig(cfg)

客户化写注意

可以通过复制集tag来配置客户化写注意,并通过getLastErrorDefaultgetLastErrorMode来使用。

单个Tag写注意

{ "use": "reporting" }

{ "use": "backup" }

{ "use": "application" }

{ "use": "application" }

{ "use": "application" }

可以用来确保写操作应用到了2个不同的use tag的值。

cfg = rs.conf()

cfg.settings = { getLastErrorModes: { use2: { "use": 2 } } }

rs.reconfig(cfg)

db.runCommand( { getLastError: 1, w: "use2" } )

特定客户端写注意

{ "disk": "ssd" }

{ "disk": "san" }

{ "disk": "spinning" }

使用这类tag不能指定到某个tag,可以用一下方式实现:

{ "disk": "ssd" }

{ "disk": "san", "disk.san": "san" }

{ "disk": "spinning" }

cfg = rs.conf()

cfg.settings = { getLastErrorModes: { san: { "disk.san": 1 } } }

rs.reconfig(cfg)

db.runCommand( { getLastError: 1, w: "san" } )

同时可以把这个配置设置为默认的

cfg = rs.conf()

cfg.settings.getLastErrorDefaults = { ssd: 1 }

rs.reconfig(cfg)

8.2.4.2读偏好

读偏好表示了如何从成员上读取数据。默认只从primary上读取,从primary上读取保证了读的是最新的数据,从secondary上读取提高的读的吞吐量,减少延迟但是数据不是最新的。

使用场景:

1.操作不会对前端应用的影响

2.多地理位置的应用可以从本地读取,减少网络延迟

3.在故障转移时,维护可用性。

读偏好模式

Primary:默认方式,所有读取都从primary操作

primaryPreferred,优先选择primary,如果不可用从secondary上读取

secondary,从secondary上读取

secondaryPreferred,首选secondary

nearest,从最近的节点读取

可以在连接对象,数据库对象,collection和每个操作上指定读偏好模式。如果是shard复制集也可以用读偏好。

shell中使用readPref光标方法来设置读偏好模式。

db.collection.find().readPref( { mode: 'nearest',

tags: [ {'dc': 'east'} ] } )

Tag设置

tag可以允许你指定客户化的读偏好和写注意。写注意和读偏好使用不同的方式来使用tag。读偏好使用tag的键值对,写注意使用有多少个不通知的tag

tagprimary是不兼容的,只能用来选择secondary,但是nearest读取方式,当和tag绑定的时候,会现在选择指定tag最近的机器,可能是primary可能是secondary

所有的接口使用相同的成员选择逻辑,来选择要读取的成员。

8.2.4.3读偏好过程

为了能能够确定操作的路由,应用程序定期更新他们存放复制集状态的视图,表明那个成员updown,或者是primary

成员选择

当你使用非primary上读取的时候,驱动会确定使用什么成员。

1.对可用的成员分配一个队列,带入成员类型

2.剔除和tag不匹配成员

3.确定那个成员最靠近client的绝对值

4.使用ping的距离过滤绝对值列表最近的成员,默认是15s可以通过驱动的secondaryAcceptLatencyMS--localThreshold或者localThreshold

5.随机选择一个成员来做读操作

然后驱动会关联线程连接到secondary成员。secondary读取的都是以前的数据。为了防止读的节点跳来跳去,第一次读之后驱动会指定一个成员,就不会从其他成员上读了,除非碰到一下问题:

1.使用不懂的读偏好执行

2.线程终端

3.客户端收到一个socket异常

当客户端发现有了一个新的primary,驱动会取消所有的线程到成员之间的连接。

自动重试

mongod和驱动之间的连接有2个注意点:

1.客户端获取当前的结果,应该都从相同的节点读取。

2.客户端应该最小化当数据库不可访问的时间。

所以mongod和驱动:

1.只要连接之后尽量使用同一个连接

2.如果存在读偏好,如果连接的那个mongod丢失了应该重新连接一个。

重连对应用程序来说是透明的,若连接允许从secondary上读取,当重连后,会从不同的secondary相继获取2个读返回,更具各个secondary的状态,这些文档可以反映数据库的不同时间点的状态。

3.当连接3个符合标准的成员之后,就会报错,如果少于3个成员,连接了所有成员之后报错。

4.发现故障转移状态之后,驱动视图尽快刷新复制集状态。

shard中的读偏好

shard集群中,shard如果是复制集的话,也可以使用读偏好。和非shard的复制集一样。和非shard复制集不一样的是,在shard集群中,所有从客户端和shard的交互都要通过mongosmongos是实际连接到所有成员的。然后mongos反映mongos 的读偏好并返回给客户端。

所有的mongos维护了自己的连接池,到复制集。所以:

1.如果不指定偏好为primary,默认mongos会重用连接,可能是不同的读偏好。所以最好显示指定读偏好。

2.所有nearest和延迟计算是值mongosmongod之间。

8.2.5复制过程

成员同步数据是连续的,第一步,先初始化同步整个数据,第二部通过oplog来连续的同步自己的数据。

8.2.5.1复制集oplog

Oplog是特定的capped collectoplog记录了所有数据库的修改操作。Mongoprimary上的写入都会被记录到oplog上,然后secondary复制oplog到自己的数据库再应用。

所有成员都可以从其他成员上获取oplog 然后再应用。

Oplog要保证,不管被应用多少次结果都是一样的,如初始化同步,rollbackshard块合并。

Oplog大小

启动的时候mongodb使用默认大小创建,这个大小根据操作系统的细节来决定。一般情况下默认的已经够用,默认oplog大小是5%的空闲磁盘空间。也可以使用oplogSize选项来指定。

1.linux64下默认大小为5%磁盘可用空间

2.OS X183MB

3.32系统,48MB

负荷要求更大的Oplog

更新多个文档:为了保证多次应用依然一样,多文档更新必须转化为对单个文档的更新。造成oplog的要求。

删除和插入一样的数据:这样虽然不会造成collection的增长,但是会造成oplog增长。

大量的in-place更新:大量的in-place更新,数据库大量记录操作,但是不会增长collection

Oplog状态

可以使用db.printReplicationInfo方法来查看oplog状态,可以通过在secondary成员上db.getReplicationInfo和复制的状态可以可以看到是否有刻意的delay

8.2.5.2复制集数据同步

复制集的数据同步有2中,1,初始化同步,2.使用不断的更新数据集。

初始化同步

初始化同步是复制所有数据从一个成员到另外一个成员。如果执行初始化同步,mongodb执行如下:

1.克隆所有数据库

2.应用所有的数据集

3.collection创建索引。

复制

初始化同步之后,复制成员从primary同步,当然同步对象是可以根据需要修改的。目标成员和源成员对buildIndexes设置必须相等。

合法性和持久性

在复制集中只有primary成员可以写,只有primary提供了严格的一致性。Journal提供了单实例写持久性。如果没有journalmongodb中断,就必须假设数据库是在不可用状态。

多线程同步

Mongo可以把写入操作分批来提高并发。Mongodb以命令空间分组批处理,并且使用一组线程来应用,但是写操作应用到一个命名空间是顺序的。

但是每个批处理,会堵塞所有读。作为结果secondary不能返回任何数据来反应当前数据库状态,这个不会在primary存在。

通过欲取索引来提高复制吞吐量

为了提高oplog应用性能,mongodb取保存了数据的内存页。当应用oplog,预取可以最小化mongodb write锁的时间。

8.2.6 主从复制

复制集优于主从复制,复制集可以有很多slave节点,主从复制可以转化复制集,也可以把复制集转化为主从复制。

8.2.6.1基本操作

初始化部署

2mongod一个主,一个从启动

mongod --master --dbpath /data/masterdb/

当用了master选项之后,mongod会创建local.oplog.$main collection

mongod --slave --source <masterhostname><:<port>> --dbpath /data/slavedb/

通过—source来指向master

配置主从部署

可以使用local.sources来指定一个master,不需要通过—source选项

1 use local

2 db.sources.find()

3 db.sources.insert( { host: <masterhostname><,only: databasename>} );

Host:host字段只想了一个master mongod实例,ip地址:port

Only:可选指定只会复制到指定的数据库

主从复制的考虑

Master会把操作写入到oplog,如果slave被拉下,那么就需要重新同步,一下状况会被拉下:1.slavemaster拉下太多,已经无法跟上。

2.因为slave停止,重启后发现已被master拉下。

当发现被拉下管理员需要手动启动重新同步,或者可以直接加参数—autoresync,为了防止出问题,可以把oplog的大小设置大一点默认只有磁盘可用空间5%的大小。

8.2.6.2主从配置选项

Master节点:mastersalve

Slave节点:sourceonlyslaveDelay

诊断

通过db.printReplicationInfo()可以看master状态。使用db.printSlaveReplicationInfo()查看slave状态,使用db.serverStatus返回复制状态。

8.2.6.3安全性

当启用auth,主从配置可以使用keyfile来做相互验证和交互。启用auth,设置keyfile指定keyfile文件,keyfile内容是随意的但是要一样。不可使用openssl来生成:

openssl rand -base64 741

8.2.6.4管理和主从复制部署

部署主从和复制集类似

如果要部署一个主从,可以用双节点复制集来代替。

{

_id : 'setName',

members : [

{ _id : 0, host : "<master>", priority : 1 },

{ _id : 1, host : "<slave>", priority : 0, votes : 0 }

]

}

把主从转化为复制集

重启当前master为单节点复制集

         a.确定是否是master

         b.干净关闭mongoddb.adminCommand({shutdown : 1, force : true})

         c.备份数据

         d.—replSet重启mongod

         e.初始化复制集,rs.initiate

使用rs.status来验证

切换到slave

1.关闭A

2.关闭b

3.dbpath中所有的local文件都复制到b

4.重启b—master选项。

变化slavemaster角色

1.使用fsync挂起写入

2.b跟上A

3.关闭B

4.dbpath上复制localb

5.使用—master启动b

6.做个写入,为了让oplog 有个起点

7.关闭b,有了local准备把local复制到a

8.关闭a,把b下的local复制到a

9.master启动b

10.使用slave启动a,包括fastsync

通过master磁盘的镜像创建slave

若可以对master无限的停止时间,可以复制数据到slave,然后通过—fastsync启动。

Fastsync是通过备份或者磁盘镜像来启动slave的一种方式,由管理员保证image的正确性跟上master,如果有master的备份,就可以用这个选项避免启动slave时完全同步。

通过slave磁盘镜像创建slave

也可以通过slave数据文件的快照复制,只有在mongod停止或者使用db.fsynclock()才能获取快照。

太老的slave使用重新同步

Oplog是有限的,当被拉下的太多,就没办法通过oplog同步了,需要重新同步。

use admin

db.runCommand( { resync: 1 } )

强制同步所有数据,如果在大数据库下会非常慢。这个和你删除slave下的数据文件,然后重新同步效果一样。

Slave

Slave不能链,只能通过master同步。如果从其他slave同步就会报错。

纠正Slave

通过修改local.source来修改slave的源。

1.重启不带—slave—source

2.修改local.sourcecollection

use local

db.sources.update( { host : "prod.mississippi" },

{ $set : { host : "prod.mississippi.example.net" } } )

3.重启可以带—source,也可以不带。

8.3复制集教程

管理复制集包含初始化复制集,增加删除成员,配置复制集,管理员不干预切换,自动切换个别状态要求手动干涉。

8.3.1复制集部署教程

介绍,部署复制集,为测试和开发部署复制集,多地理位置部署复制集,添加仲裁,把standalone转化为复制集,增加成员到复制集,从复制集中删除成员,替换复制集中的成员。

8.3.1.1部署复制集

介绍如何部署3节点复制集。如果想要从已有的数据库部署复制集,可以先把已有数据转化为复制集。

概述

3节点复制集已经提供了足够多的冗余和问题。复制集应该保证奇数个成员。来保证投票能够顺利进行。

基本过程是配置一个复制集,然后加入成员。

要求

尽量把不同的成员放到不同的主机上。再次之前先要在各个host上安装mongodb。并且保证成员之间可以相互通信。

过程

1.mongodb打开27017端口

2.可以通过dns或者主机名访问成员

3.保证可以相互通信

4.在配置文件或者启动参数中指定复制集名称。

为生产部署复制集

1.启动mongod指定一个复制集名,如果有配置文件写到配置文件上,如果没有可以用命令行参数。

2.连接到其中一个host

3.使用rs.initiate()初始化复制集

4.使用rs.conf()限制配置

{

"_id" : "rs0",

"version" : 4,

"members" : [{

"_id" : 1,

"host" : "mongodb0.example.net:27017"

}]

}

5.通过rs.add增加成员

rs.add("mongodb1.example.net")

rs.add("mongodb2.example.net")

完成后复制集会生产一个primary

8.3.1.2为测试或开发环境部署复制集

概述

3节点复制集已经提供了足够多的冗余和问题。复制集应该保证奇数个成员。来保证投票能够顺利进行。

基本过程是配置一个复制集,然后加入成员。

要求

对于测试或开发环境,可以安装在同一个系统或者虚拟系统上。当然在部署前要先安装mongodb。之前保证成员间的网络状况。

过程

1.创建数据文件夹

2.启动mongod,指定复制集名称,并指定端口

3.通过shell连接某个实例

4.使用rs.initiate()初始化复制集,也可以手动创建配置文件

5.显示配置文件。

rsconf = {_id: "rs0",

members: [{

_id: 0,

host: "<hostname>:27017"

}]

}

rs.initiate( rsconf )

6.添加节点,然后复制集自动选出primary

rs.add("<hostname>:27018")

rs.add("<hostname>:27019")

8.3.1.3部署多地理位置复制集

概述

复制集对单个实例错误提供了基本的保护,但是如果成员都在一个数据中心,如果数据中心出错,那么就会受到影响。这样可以把成员放到其他地方来避免。

要求

1.保证majority 投票成员在主数据中心。

2.若要部署仲裁放在主数据中心

若有2个成员在A1个在B那么A应该很靠近你的主应用程序的设备或者就在A上。

对于4成员的集群至少要有2个在A上。

过程

一般过程:

1.每个复制集成员在各自的设备上,所有Mongodb进程都使用27017端口。

2.每个成员都有可访问的DNS或者主机名

3.保证所有成员之间可以通信。

4.使用配置文件来进行配置。

多地理位置3节点复制集:

1.启动mongod –config /etc/mongodb.conf

2.打开mongo shell

3.使用rs.initiate来初始化复制集

4.rs.conf显示配置

5.rs.add增加节点

6.保证非主数据中心的优先级为0

cfg = rs.conf()

cfg.members[2].priority = 0

rs.reconfig(cfg)

注意点:rs.reconfig的时候会断开所有连接,并强制primarystep down,然后产生一个新的primary

多地理位置4节点复制集:

1.必须加入一个仲裁,对设备没有要求

2.决定分布:

         a.3个成员在A,一个成员在B优先级为01个仲裁在A

         b.2个成员在A,2个成员在B优先级为0,1个仲裁在A

         c.2个成员在A1个成员在B优先级为01个成员在C优先级为01个仲裁在A

1.启动mongod带上config

2.打开mongo shell

3.rs.initate初始化

4.rs.conf显示配置

5.添加节点rs.add

6.增加仲裁rs.addArb

7.非主数据中心的优先级修改为0

cfg = rs.conf()

cfg.members[2].priority = 0

rs.reconfig(cfg)

多于4节点成员多地理位置部署:

大型复制集部署应该遵循以下几点:

1.不要部署超过7个投票成员

2.如果有偶数个成员,通过部署仲裁保证主数据中心有majority成员。

3.如果是计数个成员保证主数据中心有majority成员

8.3.1.4添加仲裁

仲裁的作用是在投票的时候产生大多数,打破对峙。仲裁对硬件要求很低。

添加仲裁

1.创建仲裁的数据文件夹

2.启动仲裁服务–replSet

3.使用rs.addArb添加仲裁

8.3.1.5把单实例转化为复制集

过程

1.关闭实例

2.—replSet名启动

3.连接到实例

4.rs.initiate初始化

扩展复制集:

1.开启另外2个实例

2.rs.add添加节点

Shard考虑:

如果新建shard为复制集,需要在config数据库做一下操作:

1.连接到mongos然后运行一下命令

db.getSiblingDB("config").shards.save( {_id:"<name>", host:"<replica-set>/<member,><member,><...>" } )

2.重启所有mongos实例

8.3.1.6添加成员到复制集

概述

最大投票成员:如果增加成员到已经有7个投票成员的复制集中,你要不添加不投票成员或者删除一个已经有投票的成员。

控制脚本:关于生成环境部署,可以配置控制脚本来管理成员进程

已存在成员:可以添加新的成员到已存在复制集

数据文件:如果有一个备份和快照,可以直接把数据文件移动到新的系统,然后快速的初始化新成员。文件要求:

         1.从同一个复制成员中复制数据文件

         2.最老的操作要必须在primaryoplog,新成员必须要跟上primary

要求

1.活动的复制集

2.一个有能力的mongodb实例,可以通过网络访问活动的复制集

过程

准备数据文件夹策略:

1.保证数据文件夹下没有数据

2.手动从其他成员中复制数据

保证复制的文件在oplog窗口之内。

增加成员到已存在的复制集:

1.启动新的实例,指明—replSet

2.连接到复制集primary

3.使用rs.add增加成员

4.通过rs.conf查看成员。

配置和添加成员:

可以通过rs.add添加成员并配置。

rs.add({_id: 1, host: "mongodb3.example.net:27017", priority: 0, hidden: true})

8.3.1.7删除成员

使用rs.remove删除

1.关闭要删除的mongod

2.连接到当前primary,可以通过db.isMaster()查看

3.使用rs.remove删除成员

然后mongodb会产生一个primary

rs.remove("mongod3.example.net:27017")

rs.remove("mongod3.example.net")

 

通过rs.reconfig删除

通过修改复制集配置文档手动的删除成员。

1.关闭要删除的mongod

2.连接到当前primary

3.rs.conf显示配置文档

4.获取配置文档 cfg=rs.conf

5.修改cfg来删除成员,cfg.members.splice(2,1)来删除第3个成员。

6.rs.reconfig(cfg)来重新配置配置文档,执行后产生primary,所有连接断开。

7.通过rs.conf验证。

8.3.1.8替换复制集成员

如果需要修改复制集成员但是不改变成员的配置,可以如下使用

操作

修改host字段,_id会在重新配置时被修改,rs.reconfig,任何复制集配置的修改会触发primary关闭,强制投票重新生成primary。在投票期间所有的连接都会被断开。

cfg = rs.conf()

cfg.members[0].host = "mongo2.example.net"

rs.reconfig(cfg)

8.3.2成员配置教程

介绍,合适的成员优先级,防止secondary变成primary,隐藏成员配置,延迟成员配置,非选举成员配置,secondary转化为仲裁

8.3.2.1配置适当的复制集成员的优先级

如下命令修改成员优先级:

cfg = rs.conf()

cfg.members[0].priority = 0.5

cfg.members[1].priority = 2

cfg.members[2].priority = 2

rs.reconfig(cfg)

先取出配置文档,修改配置文档,然后reconfig

若优先级为0 就不能变成primary,隐藏,延迟,仲裁的优先级都为0.

优先级高的会有优先成为primary

8.3.2.2防止secondary变成primary

把优先级设置为0就能防止secondary变成primary

8.3.2.3配置隐藏成员

隐藏成员是复制集的一部分,不能成为primary,也不能被client访问。隐藏成员有投票权。

如果chainingAllowed设置允许secondary成员从其他secondary上同步数据。选择同步对象的时候mongodb更偏好从非隐藏成员同步。若要从隐藏成员同步,可以使用replSetSyncFrom

{

"_id" : <num>

"host" : <hostname:port>,

"priority" : 0,

"hidden" : true

}

hidden设置为true表示隐藏成员。

例子

cfg = rs.conf()

cfg.members[0].priority = 0

cfg.members[0].hidden = true

rs.reconfig(cfg)

注意点:

1.rs.reconfig会强制当前primary step down,导致投票。当primary step down所有的client都会被关闭,会花10-20s的时间。

2.如果成员是偶数的要增加一个仲裁成员保证顺利投票产生primary

8.3.2.4配置延迟成员

延迟成员的优先级为0,并且为隐藏成员,通过slaveDelay来设置延迟时间。

cfg = rs.conf()

cfg.members[0].priority = 0

cfg.members[0].hidden = true

cfg.members[0].slaveDelay = 3600

rs.reconfig(cfg)

延迟成员不能成为primaryslaveDlay为延迟时间。

注意点:

1.rs.reconfig会强制当前primary step down,导致投票。当primary step down所有的client都会被关闭,会花10-20s的时间。

2.如果成员是偶数的要增加一个仲裁成员保证顺利投票产生primary

8.3.2.5配置非投票成员

非投票成员,当投票成员超过7个的时候,增加非投票成员来提高分布式读。

cfg = rs.conf()

cfg.members[3].votes = 0

cfg.members[4].votes = 0

cfg.members[5].votes = 0

rs.reconfig(cfg)

注意点:

1.rs.reconfig会强制当前primary step down,导致投票。当primary step down所有的client都会被关闭,会花10-20s的时间。

2.如果成员是偶数的要增加一个仲裁成员保证顺利投票产生primary

通常,所有的成员都有1个票,防止了内部的对持,死锁,或不对的成员变成primary,通过使用优先级来控制是否能够成员primary

8.3.2.6secondary转为仲裁

如果secondary不需要保存数据,但是要保存投票,可以把secondary变成仲裁。可选:

1.仲裁运行在老的端口上

2.仲裁运行在新的端口上

仲裁运行在老的端口上

1.如果应用程序可以连接到secondary,那么修改应用程序不能到达这个secondary

2.关闭secondary

3.rs.remove删除这个成员

4.查看配置rs.conf验证

5.移动数据文件

6.创建新的数据文件夹

7.重启实例

8.使用rs.addArb增加成员

9.rs.conf验证配置

仲裁运行在新的端口上

1.如果应用程序可以连接到secondary,那么修改应用程序不能到达这个secondary

2.创建一个新的数据文件夹

3.启动指定新的端口

4.rs.addArb加入到复制集

5.rs.conf验证

6.关闭secondary

7.删除secondaryrs.remove

8.rs.conf验证

9.备份老的数据

8.3.3复制集维护教程

修改oplog大小,强制成员变成primary,重新同步复制集,配置复制集tag,重新配置不可用成员,管理复制链,修改主机名,配置secondary同步tag

8.3.3.1修改Oplog大小

Oplog是一个capped collection,所以不能用一般的方法修改大小,一般情况下oplog的默认大小足够用了。

过程

1.成员以standalone方式启动

2.用新的大小重新创建oplog

3.作为复制集成员重启

成员以standalone方式启动

db.shutdownServer()

mongod --port 37017 --dbpath /srv/mongodb

备份oplog

mongodump --db local --collection 'oplog.rs' --port 37017

为新的oplog备份

use local

db.temp.save( db.oplog.rs.find( { }, { ts: 1, h: 1 } ).sort( {$natural : -1} ).limit(1).next() )

删除oplog:

db = db.getSiblingDB('local')

db.oplog.rs.drop()

创建新的oplog

db.runCommand( { create: "oplog.rs", capped: true, size: (2 * 1024 * 1024 * 1024) } )

把备份的数据的最新数据插入到新的oplog

db.oplog.rs.save( db.temp.findOne() )

重启成员:

db.shutdownServer()

mongod --replSet rs0 --dbpath /srv/mongodb

处理所有secondary,处理primary时先把primary变成secondary

8.3.3.2强制成员变成primary

通过设置优先级

配置如下:

{

"_id":"rs",

"version":7,

"members": [

        {

"_id":0,

"host":"m1.example.net:27017"

        },

        {

"_id":1,

"host":"m2.example.net:27017"

        },

        {

"_id":2,

"host":"m3.example.net:27017"

        }]

}

1.设置优先级

cfg = rs.conf()

cfg.members[0].priority = 0.5

cfg.members[1].priority = 0.5

cfg.members[2].priority = 1

rs.reconfig(cfg)

以下是发生的时间:

1.m3,m2m1同步

2.m1优先级不是最高,如果m3同步被拉下很多m1不会step downm1等待m310s之内,再step down

3.根据有限制设置,投票m3变成primary

2.可选,如果m3拉下了10s多,并且在这段时间内你在不需要primary,可以强制step down

db.adminCommand({replSetStepDown: 86400, force: 1})

86400表示在24小时之内防止m1再变成primary,如果等会儿反悔想让m1再变成primary使用rs.freeze允许m1可以变成primary

使用命令

Mdb0 primarymdb1 secondarymdb2 secondary

1.使用rs.status查看状态

2.mdb2上使用rs.freeze(120),冻结120s,不让mdb2变成primary

3.rs.stepDown(120)primary,在120s不能成为primary

8.3.3.3重新同步成员

如果成员被拉下太多已经超过了oplog的窗口,那么就需要重新同步。

2个重新同步方案:

1.以空的数据文件夹启动,让mongod初始化同步

2.使用其他成员的备份同步

自动同步成员

1.如果已经存在一个成员,停止mongod,删除所有数据文件

2.启动mongod

这样mongod会初始化同步,初始化同步的时间取决于数据库的大小

初始化同步会影响其他成员,影响primary的吞吐量,可访问成员跟上primary

使用其他成员的备份同步

复制数据文件:你可以通过快照或者直接复制来抓数据。一般不能直接复制,因为在复制过程中,有修改行为。不能使用mongodump只能用快照复制。

同步成员:可以使用备份的数据文件直接启动即可。

8.3.3.4配置复制集Tag

Tag可以用来客户化写注意和读偏好

读偏好和写注意的不同

读偏好考虑tag的值

写主义只看tag值是不是唯一的

增加tags到复制集

conf = rs.conf()

conf.members[0].tags = { "dc": "east", "use": "production" }

conf.members[1].tags = { "dc": "east", "use": "reporting" }

conf.members[2].tags = { "use": "production" }

rs.reconfig(conf)

{

"_id":"rs0",

"version":2,

"members": [

             {

"_id":0,

"host":"mongodb0.example.net:27017",

"tags": {

"dc":"east",

"use":"production"

                     }},

             {

"_id":1,

"host":"mongodb1.example.net:27017",

"tags": {

"dc":"east",

"use":"reporting"

                     } },

             {

"_id":2,

"host":"mongodb2.example.net:27017",

"tags": {

"use":"production"

                     }} ]

}

创建写注意

5个成员在2个数据中心,VAGTO

1.创建复制集配置,conf = rs.conf()

2.增加tags

conf.members[0].tags = { "dc.va": "rack1"}

conf.members[1].tags = { "dc.va": "rack2"}

conf.members[2].tags = { "dc.gto": "rack1"}

conf.members[3].tags = { "dc.gto": "rack2"}

conf.members[4].tags = { "dc.va": "rack1"}

rs.reconfig(conf)

3.创建getLastErrorModes conf.settings = { getLastErrorModes: { MultipleDC : { "dc.va": 1, "dc.gto": 1}}

4.重新配置复制集rs.reconfig(conf)

这个写注意保证了至少写入到不同数据中心的一个成员。

db.runCommand( { getLastError: 1, w: "MultipleDC" } )

如果至少要写入不同数据中心的2个成员:

1.创建复制集配置,conf = rs.conf()

2.创建getLastErrorModes conf.settings = { getLastErrorModes: { MultipleDC : { "dc.va": 2, "dc.gto": 2}}

3.重新配置复制集rs.reconfig(conf)

配置Tag区分读写功能

{"dc.va": "rack1", disk:"ssd", ssd: "installed" }

{"dc.va": "rack2", disk:"raid"}

{"dc.gto": "rack1", disk:"ssd", ssd: "installed" }

{"dc.gto": "rack2", disk:"raid"}

{"dc.va": "rack1", disk:"ssd", ssd: "installed" }

1.创建复制集配置,conf = rs.conf()

2.创建getLastErrorModes

conf.settings = {

"getLastErrorModes": {

"ssd": {

"ssd":1

                         },

"MultipleDC": {

"dc.va":1,

"dc.gto":1

                         }

                 }

               }

3.重新配置复制集rs.reconfig(conf)

db.runCommand( { getLastError: 1, w: "MultipleDC" } ),也可以使用ssd作为写注意。

8.3.3.5有不可用成员时重新配置复制

重新配置配置文件

这个方法可以在大多数成员不可用情况下恢复复制。Rs.reconfigforce选项一般只用来灾难性的中断,不是每次都这么用。不要在控制脚本上这么用,任然有primary也这么用。

1.备份留下成员

2.连接到留下来的成员复制当前的配置

3.参数已经不可用的成员只设置留下来的成员

cfg.members = [cfg.members[0] , cfg.members[4] , cfg.members[7]]

4.强制重新配置

rs.reconfig(cfg, {force : true})

5.如果问题只是展示的应该马上关掉被删除成员。

通过复制重新配置

不再介绍因为只用于2.0之前的版本

8.3.3.6管理复制链

复制链可以让secondary从另外一个secondary上同步。能够减少primary的压力,但会增加复制的延迟。

使用chainingAllowed来启动和管理复制链

关闭复制链

1.创建复制集配置,conf = rs.conf()

2.若有settings就跳过,cfg.settings = { }

3.关闭复制链,重新配置

cfg.settings.chainingAllowed = false

rs.reconfig(cfg)

启动复制链

cfg = rs.config()

cfg.settings.chainingAllowed = true

rs.reconfig(cfg)

8.3.3.7修改复制集中的主机名

复制集中的主机名很少修改,不过也有可能在做迁移的时候需要修改。

概述

提供了2种修改主机名的方法:

1.修改主机名但是不破坏可用性,这个方法保证了应用程序的可以从复制集上读写数据,但是这个方法会花比较多的时间,可能会增加应用程序的下线时间。要修改应用程序的配置。

2.关闭所有老成员,这个方法维护时间短,但是期间复制集不可用。

配置

{

"_id":"rs",

"version":3,

"members": [

        {

"_id":0,

"host":"database0.example.com:27017"

        },

        {

"_id":1,

"host":"database1.example.com:27017"

        },

        {

"_id":2,

"host":"database2.example.com:27017"

        }

    ]

}

要修改为

mongodb0.example.net:27017 (the primary)

mongodb1.example.net:27017

mongodb2.example.net:27017

修改主机名保持复制集可用

1.对于每个secondary

         a.关闭实例

         b.启动新位置的实例

         c.使用mongo连接到primary

         d.使用rs.reconfig来重新配置复制集

         cfg = rs.conf()

cfg.members[1].host = "mongodb1.example.net:27017"

rs.reconfig(cfg)

         e.保证客户端可以连接到新的secondary并且要跟上其他secondary

2.step down,让primary变成secondary,和处理secondary一样处理。

3.rs.conf验证

同时修改所有主机名

1.关闭所有成员

2.使用别的端口启动

3.对于每个成员:

         a.mongo shell连接到成员

         b.编辑配置文件

         use local

cfg = db.system.replset.findOne( { "_id": "rs" } )

cfg.members[0].host = "mongodb0.example.net:27017"

cfg.members[1].host = "mongodb1.example.net:27017"

cfg.members[2].host = "mongodb2.example.net:27017"

db.system.replset.update( { "_id": "rs" } , cfg )

         c.关闭mongod

4.启动每个成员并设置上—replSet

5.mongo shell连接

6.rs.confg验证

8.3.3.8配置secondary的同步目标

可以使用rs.syncFrom()或者replSetSyncFrom命令来覆盖默认的同步对象。在初始化同步之前运行rs.syncFrom会影响初始化同步对象,如果已经在初始化了,再运行对象不会有变化。

Rs.syncFrom只是临时的修改默认行为,有这些状况下,还是会从默认的同步对象初始化:

1.mongod重启了

2.mongod和同步对象的连接被关闭。

当目标对象落后30s以上,会从默认同步对象同步。

8.3.4复制集故障排除

8.3.4.1检查复制状态

使用rs.status()来检查复制集和当前成员的状态。

8.3.4.2检查复制延迟

复制延迟是primarysecondary应用这个操作的oplog的时间差。延迟严重影响复制集的部署。

检查当前的延迟:

1.连接到primary调用db.printSlaveReplicationInfo(),返回syncedTo的值:

source: m1.example.net:30001

syncedTo: Tue Oct 02 2012 11:33:40 GMT-0400 (EDT)

= 7475 secs ago (2.08hrs)

source: m2.example.net:30002

syncedTo: Tue Oct 02 2012 11:33:40 GMT-0400 (EDT)

= 7475 secs ago (2.08hrs)

2.使用MMS来监控复制

可能照成延迟的原因:

网络延迟:保证成员之间的网络,是否存在丢包现象

磁盘吞吐量:如secondary上的磁盘速度不够快,导致secondary不能及时跟上。

并发:长时间运行的操作会堵塞在secondary上的复制,最好的办法配置写注意来保证写入到secondary

合适的写注意:当有大量的写入但是没有写注意可能会导致secondary无法跟上primary。为了防止这种情况,每100或者1000或者指定的间隔,使用写通知或者journal,让secondary能够跟上primary

8.3.4.3测试成员之间的连接

每个成员之间需要相互通信,不然会影响复制集。可以使用mongo shell是否能够连接上来看成员间是否可以通信。

8.3.4.4多个成员重启导致socket异常

当重启多个成员的时候,要保证复制集还是可以选取一个primary,也就是说大多数的vote成员可用。

当活动的成员不能成为大多数,primary step down变成secondary,没有成员变成primary。之前的primary关闭所有连接,导致写入异常。

8.3.4.5检查oplog大小

大的oplog可以容忍复制集更大的延迟。

可以使用db.printReplicationInfo()输出oplog大小:

configured oplog size: 10.10546875MB

log length start to end: 94400 (26.22hrs)

oplog first event time: Mon Mar 19 2012 13:50:38 GMT-0400 (EDT)

oplog last event time: Wed Oct 03 2012 14:59:10 GMT-0400 (EDT)

now: Wed Oct 03 2012 15:00:21 GMT-0400 (EDT)

oplog的大小确定了复制集的最大延迟。一般至少要保证oplog24小时的延迟。

8.3.4.6 Oplog文档时间戳错误

replSet error fatal couldn't query the local local.oplog.rs collection. Terminating mongod after 30 <timestamp> [rsStart] bad replSet oplog entry?

出现上面错误时,一般认为是时间戳错误。通过以下查询检查ts字段的类型是否真的有问题。

db = db.getSiblingDB("local")

db.oplog.rs.find().sort({$natural:-1}).limit(1)

db.oplog.rs.find({ts:{$type:17}}).sort({$natural:-1}).limit(1)

时间戳的类型在BSON17,如果2个查询返回不同的文档说明时间戳类型错误。

通过以下操作来纠正类型错误:

db.oplog.rs.update( { ts: { t:1347982456000, i:1 } },

                            { $set: { ts: new Timestamp(1347982456000, 1)}})

这个操作可能要花点时间因为会扫描所有的文档。

8.3.4.7重复键错误

local.slaves的重复键错误,这个错误一般会出现在secondary的主机名修改,然后primary试图修改local.slaves的时候出现。出现错误是因为保存了同一个_id。错误如下:

exception 11000 E11000 duplicate key error index: local.slaves.$_id_  dup key: { : ObjectId('<object ID>') } 0ms

这个操作不会影响secondary上的复制。为了防止这个问题可以删除primary上的local.servers

use local

db.slaves.drop()

然后secondary会把这个拉给primary,然后primary重建local.slaves即可。

8.4复制指南

8.4.1 mongo shell上的复制方法

名称

描述

rs.add()

增加成员

rs.addArb()

增加仲裁到复制集.

rs.conf()

查看复制集配置.

rs.freeze()

指定时间内,阻止当前节点变成primary

rs.help()

复制集函数帮助

rs.initiate()

初始化复制集

rs.reconfig()

重新配置复制集

rs.remove()

删除复制集的一个成员

rs.slaveOk()

设置当前连接的slaveOK,已弃用,使用readPref()或者Mongo.setReadPref()来设置读偏好

rs.status()

返回当前复制集的状态

rs.stepDown()

primary变成secondary并强制以后一场投票

rs.syncFrom()

配置当前成员的syncFrom,覆盖默认的syncFrom

 

8.4.2复制命令

Name

Description

replSetFreeze

指定时间内,防止当前成员变成primary

replSetGetStatus

返回当前复制集状态

replSetInitiate

初始化新复制集

replSetMaintenance

启动会在关闭维护模式,会让secondary变成RECONVERING状态

replSetReconfig

应用新的复制集设置.

replSetStepDown

强制当前primary step down变成secondary,强制一场投票

replSetSyncFrom

指定默认的syncfrom并覆盖默认syncfrom

resync

重新从master同步,只应用于主从复制

applyOps

内部命令应用oplog到当前数据集

isMaster

显示成员角色信息

getoptime

内部命令,返回optime

8.4.3复制集参考文档

8.4.3.1复制集命令

参考文档p467,在2.4.9中已经把reference放到了独立一章

8.4.3.2复制集配置

简介

rs.conf来获取复制集的配置

配置文档例子

{

  _id:<setname>,

  version:<int>,

  members:[

    {

      _id:<ordinal>,

      host:hostname<:port>,

      <arbiterOnly:<boolean>,>

      <buildIndexes:<boolean>,>

      <hidden:<boolean>,>

      <priority:<priority>,>

      <tags:{<document>},>

      <slaveDelay:<number>,>

      <votes:<number>>

    }

    ,...

  ],

  <settings:{

    <getLastErrorDefaults:<lasterrdefaults>,>

    <chainingAllowed:<boolean>,>

    <getLastErrorModes:<modes>>

  }>

}

配置值

http://docs.mongodb.org/manual/reference/replica-configuration/

8.4.3.3 local数据库

每个mongod都有自己的local数据库,保存了复制过程,和其他实例特殊数据,local数据库对复制不可见。

在复制中,local数据库为每个成员保存了内部复制数据。

具体请看:http://docs.mongodb.org/manual/reference/local-database/

local数据库中的collection

local.Statuplog

在启动的时候每个mongod实例插入一个文档到startup_log用来诊断

{

  "_id":"<string>",

  "hostname":"<string>",

  "startTime":ISODate("<date>"),

  "startTimeLocal":"<string>",

  "cmdLine":{

        "dbpath":"<path>",

        "<option>":<value>

  },

  "pid":<number>,

  "buildinfo":{

        "version":"<string>",

        "gitVersion":"<string>",

        "sysInfo":"<string>",

        "loaderFlags":"<string>",

        "compilerFlags":"<string>",

        "allocator":"<string>",

        "versionArray":[<num>,<num>,<...>],

        "javascriptEngine":"<string>",

        "bits":<number>,

        "debug":<boolean>,

        "maxBsonObjectSize":<number>

  }

}

复制集成员的collection

local.system.replset:保存了复制集配置对象

local.oplog.rs:保存了oplog

local.replset.minvalid:包含了一个说明复制集跟踪状态的一个对象内部使用

local.slaves:包含了复制集的每个成员,最后的同步时间

主从复制collection

local.oplog.$main:主从复制的oplog

local.slaves:每个slave信息

local.sources:master的信息

8.4.3.4复制集状态

详细请看:http://docs.mongodb.org/manual/reference/replica-states/

Number

Name

State Description

0

STARTUP

不能vote,所有成员从这个状态开始,在这个状态时解析复制集配置文档

1

PRIMARY

可以vote,复制集同一时间只能有一个primary支持读写

2

SECONDARY

可以vote,保存冗余数据

3

RECOVERING

可以vote,成员在执行自我检查,回滚或者resync时在这个状态

4

FATAL

不能vote,发生了一个不可恢复的错误

5

STARTUP2

不能vote,在变成secondary之前fork复制和投票线程

6

UNKNOWN

不能vote,不能连接到成员

7

ARBITER

可以vote,仲裁成员不保存数据只能投票

8

DOWN

不能vote,不可访问

9

ROLLBACK

可以vote,执行回滚中

10

SHUNNED

不能vote,是否被复制集删除

 

8.4.3.5读偏好

http://docs.mongodb.org/manual/reference/read-preference/

Read Preference Mode

Description

primary

默认方式,只从primary上读取

primaryPreferred

先读从primary读,不行从secondary上读

secondary

secondary上读

secondaryPreferred

先从secondary上读,不行从primary上读

nearest

从最近的一个节点上读

 

你可能感兴趣的:(mongodb)