mongo集群运维笔记 – 21运维
通知: .-...

mongo集群运维笔记

mongodb 21运维 377浏览

前面的文章介绍了MongoDB副本集和分片集群的做法,下面对MongoDB集群的日常维护操作进行小总结:

MongDB副本集故障转移功能得益于它的选举机制。选举机制采用了Bully算法,可以很方便从分布式节点中选出主节点。Bully算法是一种协调者(主节点)竞选算法,主要思想是集群的每个成员都可以声明它是主节点并通知其他节点。别的节点可以选择接受这个声称或是拒绝并进入主节点竞争。被其他所有节点接受的节点才能成为主节点。节点按照一些属性来判断谁应该胜出。这个属性可以是一个静态ID,也可以是更新的度量像最近一次事务ID(最新的节点会胜出)。

1)MongoDB集群的节点数量
官方推荐MongoDB副本集的成员数量最好为奇数,且选举要求参与的节点数量必须大于成员数的一半。假设MongoDB集群有3个节点,那么只要有2个节点活着就可以选举;如果有5个,那么活3个节点就可以选举;如果有7个节点,那么活4个就可以选举…..
MongoDB集群最多允许12个副本集节点,其中最多7个节点参与选举。这是为了减少心跳请求的网络流量和选举话费的时间,心跳每2秒发送一次。
MongoDB集群最多12个副本集节点,是因为没必要一份数据复制那么多份,备份太多反而增加了网络负载和拖慢了集群性能;而最多7个节点参与选举是因为内部选举机制
节点数量太多就会导致1分钟内还选不出主节点,凡事只要适当就好。

2)MongoDB心跳
整个MongoDB集群需要保持一定的通信才能知道哪些节点活着哪些节点挂掉。MongoDB节点会向副本集中的其他节点每两秒就会发送一次pings包,如果其他节点在10秒
钟之内没有返回就标示为不能访问。每个节点内部都会维护一个状态映射表,表明当前每个节点是什么角色、日志时间戳等关键信息。如果是主节点,除了维护映射
表外还需要检查自己能否和集群中内大部分节点通讯,如果不能则把自己降级为secondary只读节点。

3)MongoDB同步
MongoDB副本集同步分为初始化同步和keep复制。初始化同步指全量从主节点同步数据,如果主节点数据量比较大同步时间会比较长。而keep复制指初始化同步过后,
节点之间的实时同步一般是增量同步。初始化同步不只是在第一次才会被处罚,有以下两种情况会触发:
[1] secondary第一次加入,这个是肯定的。
[2] secondary落后的数据量超过了oplog的大小,这样也会被全量复制。

=============================================================================================
何为oplog?
oplog(应用日志)保存了数据的操作记录,oplog主要用于副本,secondary复制oplog并把里面的操作在secondary执行一遍。但是oplog也是mongodb的一个集合,保存在local.oplog.rs里;然而这个oplog是一个capped collection,也就是固定大小的集合,新数据加入超过集合的大小会覆盖,所以这里需要注意,跨IDC的复制要设置合适的oplogSize,避免在生产环境经常产生全量复制。oplogSize可以通过–oplogSize设置大小,对于Linux 和Windows 64位,oplog size默认为剩余磁盘空间的5%。

在mongodb主从结构中,主节点的操作记录成为oplog(operation log)。oplog存储在一个系统数据库local的集合oplog.$main中,这个集合的每个文档都代表主节点上执行的一个操作。从服务器会定期从主服务器中获取oplog记录,然后在本机上执行!对于存储oplog的集合,MongoDB采用的是固定集合,也就是说随着操作过多,新的操作会覆盖旧的操作!主节点通过–oplogSize设置oplog的大小(主节点操作记录存储到local的oplog中)
=============================================================================================

MongoDB同步也并非只能从主节点同步,假设集群中3个节点,节点1是主节点在IDC1,节点2、节点3在IDC2,初始化节点2、节点3会从节点1同步数据。后面节点2、节点3会使用就近原则从当前IDC的副本集中进行复制,只要有一个节点从IDC1的节点1复制数据。设置mongodb、同步还要注意以下几点:
[1] secondary不会从delayed(延迟)和hidden(隐藏)成员上复制数据。
[2] 要是需要同步,两个成员的buildindexes必须要相同无论是否是true和false。
[3] buildindexes主要用来设置是否这个节点的数据用于查询,默认为true。
[4] 如果同步操作30秒都没有反应,则会重新选择一个节点进行同步。

4)Mongodb主节点的读写压力过大如何解决?
在系统早期,数据量还小的时候不会引起太大的问题,但是随着数据量持续增多,后续迟早会出现一台机器硬件瓶颈问题的。而MongoDB主打的就是海量数据架构,它不能解决海量数据怎么行! mongodb的”分片”就是用来解决这个问题的。

传统数据库怎么做海量数据读写?其实一句话概括:分而治之。如下TaoBao早期的一个架构图:

上图中有个TDDL,是TaoBao的一个数据访问层组件,它主要的作用是SQL解析、路由处理。根据应用的请求的功能解析当前访问的sql判断是在哪个业务数据库、哪个表访问查询并返回数据结果。具体如图:

说了这么多传统数据库的架构,那NoSQL怎么去做到了这些呢?MySQL要做到自动扩展需要加一个数据访问层用程序去扩展,数据库的增加、删除、备份还需要程序去控制。一但数据库的节点一多,要维护起来也是非常头疼的。不过MongoDB所有的这一切通过它自己的内部机制就可以搞定的了。如下图看看MongoDB通过哪些机制实现路由、分片:

从图中可以看到有四个组件:mongos、config server、shard、replica set。
mongos,数据库集群请求的入口,所有的请求都通过mongos进行协调,不需要在应用程序添加一个路由选择器,mongos自己就是一个请求分发中心,它负责把对应的数据请求请求转发到对应的shard服务器上。在生产环境通常有多mongos作为请求的入口,防止其中一个挂掉所有的mongodb请求都没有办法操作。

config server,顾名思义为配置服务器,存储所有数据库元信息(路由、分片)的配置。mongos本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储这些数据。mongos第一次启动或者关掉重启就会从 config server 加载配置信息,以后如果配置服务器信息变化会通知到所有的 mongos 更新自己的状态,这样 mongos 就能继续准确路由。在生产环境通常有多个 config server 配置服务器,因为它存储了分片路由的元数据,这个可不能丢失!就算挂掉其中一台,只要还有存货, mongodb集群就不会挂掉。

shard,这就是传说中的分片了。上面提到一个机器就算能力再大也有天花板,就像军队打仗一样,一个人再厉害喝血瓶也拼不过对方的一个师。俗话说三个臭皮匠顶个诸葛亮,这个时候团队的力量就凸显出来了。在互联网也是这样,一台普通的机器做不了的多台机器来做,如下图:

一台机器的一个数据表 Collection1 存储了 1T 数据,压力太大了!在分给4个机器后,每个机器都是256G,则分摊了集中在一台机器的压力。也许有人问一台机器硬盘加大一点不就可以了,为什么要分给四台机器呢?不要光想到存储空间,实际运行的数据库还有硬盘的读写、网络的IO、CPU和内存的瓶颈。在mongodb集群只要设置好了分片规则,通过mongos操作数据库就能自动把对应的数据操作请求转发到对应的分片机器上。在生产环境中分片的片键可要好好设置,这个影响到了怎么把数据均匀分到多个分片机器上,不要出现其中一台机器分了1T,其他机器没有分到的情况,这样还不如不分片!

replica set(副本集),其实上图4个分片如果没有 replica set 是个不完整架构,假设其中的一个分片挂掉那四分之一的数据就丢失了,所以在高可用性的分片架构还需要对于每一个分片构建 replica set 副本集保证分片的可靠性。生产环境通常是 2个副本 + 1个仲裁(即一主一从一仲裁)。

5)MongoDB 复制集节点增加移除及节点属性配置
复制集(replica Set)或者副本集是MongoDB的核心高可用特性之一,它基于主节点的oplog日志持续传送到辅助节点,并重放得以实现主从节点一致。再结合心跳机制,当感知到主节点不可访问或宕机的情形下,辅助节点通过选举机制来从剩余的辅助节点中推选一个新的主节点从而实现自动切换。对于一个已经存在的MongoDB Replica Set集群,可以对其进行节点的增加,删除,以及修改节点属性等等。

1)查看当前版本环境
repSetTest:PRIMARY> db.version()
3.2.11

注意:利用rs.add和rs.remove是不用rs.reconfig来使用配置生效的。

2)删除节点
repSetTest:PRIMARY> rs.remove(“192.168.10.220:27000”)
{ “ok” : 1 }

移除节点后的状态信息
repSetTest:PRIMARY> rs.status()

移除后查看配置文件
repSetTest:PRIMARY> rs.config()
———————————————————————
repmore:PRIMARY> config = {_id:”repmore”,members:[{_id:0,host:’192.168.10.220:27017′,priority :2}]}; //删除节点
repmore:PRIMARY> rs.reconfig(config); //使配置生效
repmore:PRIMARY> rs.status(); //查看节点状态
———————————————————————

3)增加节点
repSetTest:PRIMARY> rs.add(“192.168.10.220:27000”)
repSetTest:PRIMARY> rs.status()
repSetTest:PRIMARY> rs.config()
———————————————————————
或者使用下面方法添加节点:
repmore:PRIMARY> config = {_id:”repmore”,members:[{_id:0,host:’192.168.10.220:27017′,priority :2},{_id:1,host:’192.168.10.220:27018′,priority:1}]}; //添加节点
repmore:PRIMARY> rs.reconfig(config); //使配置生效
repmore:PRIMARY> rs.status(); //查看节点状态

注意:新增节点的replSet要和其他节点要一样
———————————————————————

4)启用Arbiter节点
repSetTest:PRIMARY> rs.remove(“192.168.10.220:27000″)
repSetTest:PRIMARY> rs.add({host:”192.168.10.220:27000”,arbiterOnly:true})

对于Arbiter也可以使用rs.addArb函数来添加
> rs.addArb(“192.168.10.220:27000”)
6)MongoDB复制集状态查看

复制集状态查询命令
1)复制集状态查询:rs.status()
2)查看oplog状态: rs.printReplicationInfo()
3)查看复制延迟: rs.printSlaveReplicationInfo()
4)查看服务状态详情: db.serverStatus()

====================================================================
1)rs.status()
self:只会出现在执行rs.status()命令的成员里
uptime:从本节点 网络可达到当前所经历的时间
lastHeartbeat:当前服务器最后一次收到其心中的时间
Optime & optimeDate:命令发出时oplog所记录的操作时间戳
pingMs: 网络延迟
syncingTo: 复制源
stateStr:

可提供服务的状态:primary, secondary, arbiter
即将提供服务的状态:startup, startup2, recovering
不可提供服务状态:down,unknow,removed,rollback,fatal

2)rs.printReplicationInfo()
log length start to end: 当oplog写满时可以理解为时间窗口
oplog last event time: 最后一个操作发生的时间

3).rs.printSlaveReplicationInfo()
复制进度:synedTo
落后主库的时间:X secs(X hrs)behind the primary

4).db.serverStatus()
可以使用如下命令查找需要用到的信息
db.serverStatus.opcounterRepl
db.serverStatus.repl

5).常用监控项目:
QPS: 每秒查询数量
I/O: 读写性能
Memory: 内存使用
Connections: 连接数
Page Faults: 缺页中断
Index hit: 索引命中率
Bakground flush: 后台刷新
Queue: 队列
7)MongoDB复制集常用监控工具

1) mongostat
-h, –host 主机名或 主机名:端口
–port 端口号
-u ,–uername 用户名(验证)
-p ,–password 密码(验证)
–authenticationDatabase 从哪个库进行验证
–discover 发现集群某个其他节点

[[email protected] ~]# mongostat -h 192.168.10.220:27017
[[email protected] ~]# mongostat -h 192.168.10.220:27017 –discover

mongostat重点关注的字段:
getmore 大量的排序操作在进行
faults 需要的数据不在内存中
locked db 锁比例最高的库
index miss 索引未命中
qr|qw 读写产生队列,供求失衡

2) mongostop:与mongostat基本一样
-h, –host 主机名或 主机名:端口
–port 端口号
-u ,–uername 用户名(验证)
-p ,–password 密码(验证)
–authenticationDatabase 从哪个库进行验证

8)对于Secondary来说有几个比较重要的属性:Priority优先级、Vote投票节点、Hidden节点、Delayed节点

设定节点的优先级别(Priority)
Priority=0 即优先级为0的节点。字面上来说,权限为0。拥有最低的权限。已然是Secondary了,权限还最低,啥影响呢?之前说过,mongoDB的副本集中是有投票机制的,如果一个Primary不可达,那么所有的Secondary会联合起来投票选举,选出心目中的新的Primary。因为只有Primary才能接收Writes的操作,所以Primary在一个mongoDB的集群中是必须的。下图展示了一个在两个IDC中存放Primary,Secondary,以及一个Priority=0的Secondary的场景(关于这个存放方式以及奇数偶数。

优先级为0的节点的特点

1)此节点丧失了当选Primary的机会。永远不会上位。
2)此节点正常参与Primary产生的oplog的读取,进行数据备份和命令执行。
3)此节点正常参与客户端对于数据的读取,进行担当负载均衡的工作。
4)此节点虽然不能当选Primary但是却可以投票,很民主。
Priority=0在mongoDB中的解释就是一个Standby,可投票不可参选,又干活又负载。有点像日本议会党派中刚入党派的小喽啰,可以参与自己党派党首的选举,还要干好多活,外面民众开骂还得挡着,但就是不可能当选党首。

1)优先级用于确定一个倾向成为主节点的程度。取值范围为0-100
2)Priority 0节点的选举优先级为0,不会被选举为Primary,这样的成员称为被动成员
3)对于跨机房复制集的情形,如A,B机房,最好将『大多数』节点部署在首选机房,以确保能选择合适的Primary
4)对于Priority为0节点的情况,通常作为一个standby,或由于硬件配置较差,设置为0以使用不可能成为主

如下示例,在新增节点的时候设定该节点的优先级别
repSetTest:PRIMARY> rs.add({“_id”:3,”host”:”localhost:27000″,”priority”:1.5})

也可以通过下面的方式修改优先级别
repSetTest:PRIMARY> var config=rs.config()
repSetTest:PRIMARY> config.members[2].priority=2
2
repSetTest:PRIMARY> rs.reconfig(config)
{ “ok” : 1 }
投票节点(Vote)

1)投票节点不保存数据副本,不可能成为主节点。
2)Mongodb 3.0里,复制集成员最多50个,参与Primary选举投票的成员最多7个。
3)对于超出7个的其他成员(Vote0)的vote属性必须设置为0,即不参与投票。
隐藏节点(Hidden)
字面上来说,隐藏。这个隐藏式对客户端的隐藏,客户端如果要读取Secondary的数据,永远无法读取Hidden节点的数据,因为设置了Hidden的这个节点对于客户端是透明的,不可见。但是,对于自己的Secondary的群体和Primary来说都是可见的,所以,Hidden依然可以投票,依然要按照oplog进行命令的复制,只是,不参与负载了。Hidden属性的前提是必须是一个Priority=0的节点,所以会具备一些优先级=0的特点,具体如下。

Hidden节点的特点

1)此节点丧失了当选Primary的机会。永远不会上位。
2)此节点正常参与Primary产生的oplog的读取,进行数据备份和命令执行。
3)此节点正常参与客户端对于数据的读取,进行担当负载均衡的工作。
4)此节点不参与客户端对于数据的读取,不进行负载均衡
5)此节点虽然不能当选Primary但是却可以投票,也很民主。
第3条特征体现出它与Priority=0的不同地方,第4条特征表现出它比0优先级多出来的特性。如果节点是Hidden,它不参与负载,那么空闲出来的时间可以做一些赋予给它的特殊任务,比如数据备份等等。到应用场景的时候会有用处。

1)Hidden节点不能被选为主(Priority为0),并且对Driver不可见。
2)因Hidden节点不会接受Driver的请求,可使用Hidden节点做一些数据备份、离线计算的任务,不会影响复制集的服务
3)隐藏节点成员建议总是将其优先级设置为0(priority 0)
4)由于对Driver不可见,因此不会作为read preference节点,隐藏节点可以作为投票节点
5)在分片集群当中,mongos不会同隐藏节点交互

> cfg = rs.conf()
> cfg.members[2].priority = 0
> cfg.members[2].hidden = true
> rs.reconfig(cfg)

查看设置为隐藏阶段后的属性
repSetTest:SECONDARY> db.isMaster()
{
“hosts” : [
“localhost:27000”,
“localhost:27001”
],
“setName” : “repSetTest”,
“setVersion” : 2,
“ismaster” : false,
“secondary” : true,
“primary” : “localhost:27000”,
“passive” : true,
“hidden” : true, //此处表明当前节点为隐藏节点
“me” : “localhost:27002”,
“maxBsonObjectSize” : 16777216,
“maxMessageSizeBytes” : 48000000,
“maxWriteBatchSize” : 1000,
“localTime” : ISODate(“2017-03-06T10:15:48.257Z”),
“maxWireVersion” : 4,
“minWireVersion” : 0,
“ok” : 1
}
延迟节点(Delayed)
字面上来说,迟延。迟延代表此节点的数据与Primary的数据有一定的迟延,通过设定一个迟延的属性来确定。假设,Primary的数据是10:00的最新数据,我们设置了一个3600秒的迟延参数,那么这个带有迟延的节点的数据或者说命令执行情况(在oplog中)应该只到9:00为止。与主节点有1小时的迟延。有些人可能会问,我们设计分布式数据库要的就是数据能够尽量避免迟延来达到一致,这样才能更好的提供服务,为什么要刻意制造迟延呢?试想这个场景:一个猪一样的队友在mongoDB的Replica集群上面执行了一个Drop操作,这个操作干掉了你的Primary的Collection,这个Drop同时被记录到oplog中去,其他的Secondary看到这个oplog后争相执行,各自干掉了自己的Collection,你苦心存储的数据就这么消失了。。。再怎么抽这个队友没用啊。所以,主动的过失避免就显得格外重要。如果你有一个Delayed节点,有一个1000秒的迟延,那么在你发现这个miss之后还有足够的时间可以响应去不让这个Delayed节点执行错误的command,从而挽回你的损失。具体如下。

Delayed节点的特点

1)此节点必须是一个Priority=0且为Hidden的节点,因为Hidden必须是Priority=0的,所以此节点必须是Hidden的。
2)此节点虽然又迟延又Hidden但是还是可以投票,也很民主。
Delayed节点的最大作用是用来容人为的灾,猪一样的操作,驴一样的动作,在Delayed节点可以把损失降到最低。当然,如果你在Delayed时间经过后发现了错误,那么只能”呵呵”了。Delayed的时间设定一定要大于响应时间,比如从Primary的oplog写到Secondary需要1秒,那么Delayed必须大于等于1秒,小于1秒的的话只能是一个不可及状态。

延迟节点包含复制集的部分数据,是复制集数据的子集
延迟节点上的数据通常落后于Primary一段时间(可配置,比如1个小时)。
当人为错误或者无效的数据写入Primary时,可通过Delayed节点的数据进行回滚

延迟节点的要求:
1)优先级别为0(priority 0),避免参与primary选举
2)应当设置为隐藏节点(以避免应用程序查询延迟节点)
3)可以作为一个投票节点,设置 members[n].votes 值为1

延迟节点注意事项:
1)延迟时间应当等于和大于维护窗口持续期
2)应当小于oplog容纳数据的时间窗口

repSetTest:SECONDARY> cfg = rs.conf()
repSetTest:SECONDARY> cfg.members[2].priority = 0
repSetTest:SECONDARY> cfg.members[2].hidden = true
repSetTest:SECONDARY> cfg.members[2].slaveDelay = 3600
repSetTest:SECONDARY> rs.reconfig(cfg)

repSetTest:SECONDARY> db.isMaster()
{
“hosts” : [
“localhost:27000”,
“localhost:27001”
],
“setName” : “repSetTest”,
“setVersion” : 3,
“ismaster” : false,
“secondary” : true,
“primary” : “localhost:27000”,
“passive” : true,
“hidden” : true,
“slaveDelay” : 3600, //此处表面当前节点具有延迟属性,为延迟节点
“me” : “localhost:27002”,
“maxBsonObjectSize” : 16777216,
“maxMessageSizeBytes” : 48000000,
“maxWriteBatchSize” : 1000,
“localTime” : ISODate(“2017-03-06T10:19:57.148Z”),
“maxWireVersion” : 4,
“minWireVersion” : 0,
“ok” : 1
}
mongodb副本集修改配置问题

因ip地址被占用,需要重新设置ip地址,这时需要修改副本集中的IP地址配置:
1)查看配置rs.config();需要找到primary主机,在该主节点服务器上才有权限修改配置
2)rs.remove(“ip:port”) 移除原配置文件中的已经变更地址的主机
3)rs.add(“ip:port”) 添加新的地址主机
4)设置priority优先级
> var config = rs.config()
> config.members[2].priority=2
> rs.reconfig(config) //重新更新配置

 

 

原文转载于 https://cloud.tencent.com/developer/article/1027550

转载请注明:21运维 » mongo集群运维笔记