关于mongodb:MongoDB-日常运维实践总结

4次阅读

共计 8376 个字符,预计需要花费 21 分钟才能阅读完成。

一、MongoDB 集群简介

MongoDB 是一个基于分布式文件存储的数据库,其目标在于为 WEB 利用提供可扩大的高性能数据存储解决方案。上面将以 3 台机器介绍最常见的集群计划。具体介绍,能够查看官网 https://docs.mongodb.com/v3.4…。

1、集群组件的介绍

mongos(路由解决):作为 Client 与 MongoDB 集群的申请入口,所有用户申请都会透过 Mongos 协调,它会将数据申请发到对应的 Shard(mongod)服务器上,再将数据合并后回传给用户。

config server(配置节点):即:配置服务器;次要保留数据库的元数据,蕴含数据的散布 (分片) 以及数据结构,mongos 收到 client 收回的需要后,会从 config server 加载配置信息并缓存于内存中。个别在生产环境会配置不只一台 config server,因为它保留的元数据极为重要,若损坏则影响整个集群运作。

shard(分片实例存储数据):shard 就是分片。MongoDB 利用分片的机制来实现数据分布存储与解决,达到横向扩容的目标。默认状况下,数据在分片之间会主动进行移转,以达到均衡,此动作是靠一个叫平衡器 (balancer) 的机制达成。

replica set(正本集):正本集实现了数据库高可用,若没做正本集,则一旦存放数据的服务器节点挂掉,数据就失落了,相同若配置了正本集,则同样的数据会保留在正本服务器中 (正本节点),个别正本集蕴含了一个主节点与多个正本节点,必要时还会配置 arbiter(仲裁节点) 作为节点挂掉时投票用。

arbiter(仲裁节点):仲裁服务器自身不蕴含数据,仅能在主节点故障时,检测所有正本服务器并选举出新的主节点,其实现形式是通过主节点、正本节点、仲裁服务器之间的心跳 (Heart beat) 实现。

2、MongoDB 利用场景

网站数据:适宜实时的插入,更新与查问,并具备网站实时数据存储所需的复制及高度伸缩性。

缓存:因为性能很高,也适宜作为信息基础设施的缓存层。在零碎重启之后,搭建的长久化缓存能够防止上层的数据源过载。

大尺寸、低价值的数据:应用传统的关系数据库存储一些数据时可能会比拟贵,在此之前,很多程序员往往会抉择传统的文件进行存储。

高伸缩性的场景:非常适合由数十或者数百台服务器组成的数据库。

用于对象及 JSON 数据的存储:MongoDB 的 BSON 数据格式非常适合文档格式化的存储及查问。

3、选用 MongoDB 的原因

选用 MongoDB 的数据是以 BSON 的数据格式,高度伸缩不便扩大,并且数据程度扩大非常简单,反对海量数据存储,性能强悍。

二、集群的监测

1、监测数据库存储统计信息

docker 中进入 mongos 或 shard 实例,执行以下命令:

docker exec -it mongos bash;
mongo --port 20001;
use admin;
db.auth("root","XXX");

阐明: 通过此命令,能够查问集群的成员的汇合数量、索引数量等相干数据。13 个 Mongodb GUI 可视化管理工具,总有一款适宜你

db.stats();

2、查看数据库的统计信息

阐明:通过此命令,能够查看操作数量、内存应用情况、网络 io 等

db.runCommand({ serverStatus: 1} );

3、查看复制集成员状态

rs.status();

三、根本的运维操作

1、设置和查看慢查问

# 设置慢查问
db.setProfilingLevel(1,200);
# 查看慢查问级别
db.getProfilingLevel();
# 查问慢查问日志,此命令是针对于某一库进行设置
db.system.profile.find({ns : 'dbName.collectionName'}).limit(10).sort({ ts : -1} ).pretty();

2、查看执行操作工夫较长的动作

db.currentOp({"active" : true,"secs_running" : { "$gt" : 2000}});

3、动静调整日志级别和设置缓存大小

# 设置日志级别参数
db.adminCommand({ "getParameter": 1, "logLevel":1});
# 设置 cache 大小参数
db.adminCommand({ "setParameter": 1, "wiredTigerEngineRuntimeConfig": "cache_size=4G"});

4、增加和移除复制集成员

# 查看复制集成员
rs.status().members;
# 增加成员
rs.add('127.0.0.1:20001');# 移除成员
rs.remove('127.0.0.1:20001');

5、设置数据库和汇合分片

# 在 mongos admin 库设置库容许分片
sh.enableSharding("dbName");
# 在 mongos 的 admin 库设置汇合分片片键
sh.shardCollection("dbName.collectionName", { filedName: 1} );

6、增加和移除分片

# 查看分片状态
sh.status();# 在 mongos 执行增加分片(能够为单个实例或复制集)db.runCommand({ removeShard: "shardName"} );db.runCommand({addshard:"rs1/ip-1:20001,ip-2:20001,ip-3:20001"});
# 在 mongos 执行移除分片
db.runCommand({ removeShard: "shard3"} );# 在 mongos 执行刷新 mongos 配置信息
db.runCommand("flushRouterConfig"));

阐明:移除分片命令至多执行两次能力胜利删除,执行到 state 为 completed 才真正删除,否则就是没用删除胜利,该分片处于 {“draining” : true} 状态,该状态下岂但该分片没用删除胜利,而且还影响接下来删除其余分片操作,遇到该状态再执行一次 removeshard 即可,最好就是删除分片时始终反复执行删除命令,直到 state 为 completed;还有一个须要留神的中央就是:被胜利删除的分片如果想要再退出集群时,必须将 data 数据目录清理洁净才能够再退出集群,否则即便能退出胜利也不会存储数据,汇合都不会被创立。

另外:在删除分片的时有可能整个过程呈现有限 {“draining” : true} 状态,等多久还是这样,而且分片下面的块一个都没有挪动到别的分片,解决办法是:在 config 的 config 数据库的 shard 汇合中找到该分片的信息,并将 draining 字段由 True 改为 False, 再持续试着删除操作”下面这句会立刻返回,理论在后盾执行。在数据移除的过程当中,肯定要留神实例的日志信息,可能呈现数据块在迁徙的过程中,始终找不到边界条件,导致始终数据迁徙不胜利,始终重试,解决方案是删除边界数据,重启实例。

如果此分片为主分片,须要先迁徙主分片。db.runCommand({ movePrimary: “XXX”, to: “other”});在实现删除后,所有 mongos 上运行上面命令,再对外提供服务,当然也能够重新启动所有 mongos 实例。

7、数据的导入导出

# 导出容许指定导出条件和字段
mongoexport -h 127.0.0.1 --port 20001 -uxxx -pxxx -d xxx -c mobileIndex -o XXX.txt 
mongoimport -h 127.0.0.1 --port 20001 -uxxx -pxxx -d xxx -c mobileIndex --file XXX.txt

四、MongoDB 数据迁徙

1、迁徙复制集当中的成员

  • 敞开 mongod 实例, 为了确保安全敞开, 应用 shutdown 命令;
  • 将数据目录 (即 dbPath) 转移到新机器上;
  • 在新机器上启动 mongod,其中节点的数据目录为 copy 的文件目录;
  • 连贯到复制集以后的主节点上;

如果新节点的地址发生变化, 应用 rs.reconfig() 更新 复制集配置文档;举例, 上面的命令过程将成员中位于第 2 位的地址进行更新:

cfg = rs.conf()
cfg.members[2].host = "127.0.0.1:27017"
rs.reconfig(cfg)

应用 rs.conf() 确认应用了新的配置. 期待所有成员恢复正常, 应用 rs.status() 检测成员状态。

2、迁徙复制集主节点

在迁徙主节点的时候, 须要复制集选举出一个新的主节点, 在进行选举的时候, 复制集将读写, 通常, 这只会继续很短的工夫, 不过, 应该尽可能在影响较小的时间段内迁徙主节点.

主节点降级, 以使得失常的 failover 开始. 要将主节点降级, 连贯到一个主节点, 应用 replSetStepDown 办法或者应用 rs.stepDown()办法, 上面的例子应用了 rs.stepDown()办法进行降级:

rs.stepDown()

等主节点降级为从节点, 另一个成员成为 PRIMARY 之后, 能够依照“迁徙复制集的一个成员”迁徙这个降级了的节点. 能够应用 rs.status()来确认状态的扭转。

3、从复制集其余节点复原数据

MongoDB 通过复制集能保障高牢靠的数据存储,通常生产环境倡议应用「3 节点复制集」,这样即便其中一个节点解体了无奈启动,咱们能够间接将其数据清掉,重新启动后,以全新的 Secondary 节点退出复制集,或者是将其余节点的数据复制过去,重新启动节点,它会主动的同步数据,这样也就达到了复原数据的目标。

敞开须要数据同步的节点

docker stop node;  # docker 环境中
db.shutdownServer({timeoutSecs: 60}); # 非 docker 环境

拷贝指标节点机器的数据存储目录 (/dbPath) 到以后机器的指定目录。

scp 指标节点 shard/data -> 以后节点 shard/data

以后节点以复制过去的数据文件启动节点

将新的节点增加到复制集

# 进入复制集的主节点,执行增加新的节点命令
rs.add("hostNameNew:portNew"); 
# 期待所有成员恢复正常, 检测成员状态
rs.status();
# 移除原来的节点
rs.remove("hostNameOld>:portOld"); 

五、MongoDB 线上问题场景解决

1、MongoDB 新建索引导致库被锁

问题阐明:某线上千万级别汇合,为优化业务,间接执行新建索引命令,导致整个库被锁,应用服务呈现不可用。

解决方案:找出此操作过程,并且杀死。改为后盾新建索引,速度会很慢,然而不会影响业务,该索引只会在新建实现之后,才会失效;

# 查问运行工夫超过 200ms 操作 
db.currentOp({"active" : true,"secs_running" : { "$gt" : 2000}});# 杀死执行工夫过长操作操作
db.killOp(opid)
# 后盾新建索引
db.collectionNmae.ensureIndex({filedName:1}, {background:true});

2、MongoDB 没有限度内存,导致实例退出

问题阐明:生产环境某台机器启动多个 mongod 实例,运行一段时间过后,过程莫名被杀死;

解决方案:当初 MongoDB 应用 WiredTiger 作为默认存储引擎,MongoDB 同时应用 WiredTiger 外部缓存和文件系统缓存。从 3.4 开始,WiredTiger 外部缓存默认应用较大的一个:50%(RAM – 1 GB),或 256 MB。例如,在总共 4GB RAM 的零碎上,WiredTiger 缓存将应用 1.5GB 的 RAM()。相同,具备总共 1.25 GB RAM 的零碎将为 WiredTiger 缓存调配 256 MB,因为这超过总 RAM 的一半减去 1 千兆字节()。

0.5 * (4 GB - 1GB) = 1.5 GB``0.5 * (1.25 GB - 1 GB) = 128 MB < 256 MB。如果一台机器存在多个实例,在内存不足的情景在,操作系统会杀死局部过程;# 要调整 WiredTiger 外部缓存的大小,调节 cache 规模不须要重启服务,咱们能够动静调整:db.adminCommand({ "setParameter": 1, "wiredTigerEngineRuntimeConfig": "cache_size=xxG"})

3、MongoDB 删除数据,不开释磁盘空间

问题阐明:在删除大量数据 (自己操作的数据量在 2000 万 +) 的情景下,并且在生产环境中申请量较大,此时机器的 cpu 负载会显得很高,甚至机器卡顿无奈操作,这样的操作应该审慎分批量操作;在删除命令执行完结之后,发现磁盘的数据量大小并没有扭转。

解决方案:

  • 计划一:咱们能够应用 MongoDB 提供的在线数据膨胀的性能,通过 Compact 命令 db.collectionName.runCommand(“compact”)进行 Collection 级别的数据膨胀,去除汇合所在文件碎片。此命令是以 Online 的形式提供膨胀,膨胀的同时会影响到线上的服务。为了解决这个问题,能够先在从节点执行磁盘整顿命令,操作完结后,再切换主节点,将原来的主节点变为从节点,从新执行 Compact 命令即可。
  • 计划二:应用从节点从新同步,secondary 节点重同步,删除 secondary 节点中指定数据,使之与 primary 从新开始数据同步。当正本集成员数据太过古老,也能够应用从新同步。数据的从新同步与间接复制数据文件不同,MongoDB 会只同步数据,因而重同步实现后的数据文件是没有空集合的,以此实现了磁盘空间的回收。

    针对一些非凡状况,不能下线 secondary 节点的,能够新增一个节点到正本集中,而后 secondary 就主动开始数据的同步了。总的来说,重同步的办法是比拟好的,第一根本不会阻塞正本集的读写,第二耗费的工夫绝对前两种比拟短。

  • 若是 primary 节点,先强制将之变为 secondary 节点,否则跳过此步骤:rs.stepdown(120);
  • 而后在 primary 上删除 secondary 节点:rs.remove(“IP:port”);
  • 删除 secondary 节点 dbpath 下的所有文件
  • 将节点重新加入集群,而后使之主动进行数据的同步:rs.add(“IP:port”);
  • 等数据同步实现后,循环 1 - 4 的步骤能够将集群中所有节点的磁盘空间开释

4、MongoDB 机器负载极高

问题阐明:此情景是在客户申请较大的情景性,因为部署 MongoDB 的机器蕴含一主一从,MongoDB 使得 IO100%,数据库阻塞,呈现大量慢查问,进而导致机器负载极高,应用服务齐全不可用。

解决方案:在没有机器及时扩容的情况下,首要任务便是减小机器的 IO,在一台机器呈现一主一从,在大量数据写入的状况下,会相互抢占 IO 资源。于是此时摒弃了 MongoDB 高可用的特点,摘掉了复制集当中的从节点,保障每台机器只有一个节点能够占用磁盘资源。之后,机器负载立马下来,服务变为失常可用状态,然而此时 MongoDB 无奈保证数据的完整性,一旦有主节点挂掉便会失落数据。

此计划只是长期办法,基本解决是能够减少机器的内存、应用固态硬盘,或者采纳减少分片集来缩小单个机器的读写压力。

# 进入主节点,执行移除成员的命令
rs.remove("127.0.0.1:20001");
# 留神:切勿间接关停实例

5、MongoDB 分片键抉择不当导致热读热写

问题阐明:生产环境中,某一汇合的片键应用了与_id 生成形式类似,含有工夫序列的字段作为升序片键,导致数据写入时都在一个数据块,随着数据量增大,会造成数据迁徙到后面的分区,造成系统资源的占用,偶然呈现慢查问。

解决方案:长期计划设置数据迁徙的窗口,放在在失常的工夫区段,对业务造成影响。基本解决是更换片键。

# 连贯 mongos 实例,执行以下命令
db.settings.update({_id : "balancer"}, {$set : { activeWindow : { start : "23:00", stop : "4:00"} } }, true );# 查看平衡窗口
sh.getBalancerWindow();

六、MongoDB 优化倡议

1、利用层面优化

查问优化:确认你的查问是否充分利用到了索引,用 explain 命令查看一下查问执行的状况,增加必要的索引,防止扫表操作。

正当设计分片键:

  • 增量 sharding-key:适宜于可划分范畴的字段,比方 integer、float、date 类型的,查问时比拟快。
  • 随机 sharding-key: 实用于写操作频繁的场景,而这种状况下如果在一个 shard 上进行会使得这个 shard 负载比其余高, 不够平衡,故而心愿能 hash 查问 key,将写散布在多个 shard 上进行, 思考复合 key 作为 sharding key,总的准则是查问快,尽量减少跨 shard 查问,balance 平衡次数少;
  • 繁多递增的 sharding key,可能会造成写数据全副在最初一片上,最初一片的写压力增大,数据量增大,会造成数据迁徙到后面的分区。MongoDB 默认是单条记录 16M,尤其在应用 GFS 的时候,肯定要留神 shrading-key 的设计。不合理的 sharding-key 会呈现,多个文档,在一个 chunks 上,同时,因为 GFS 中存贮的往往是大文件,导致 MongoDB 在做 balance 的时候无奈通过 sharding-key 来把这多个文档离开到不同的 shard 上,这时候 MongoDB 会一直报错最初导致 MongoDB 倒掉。解决办法:加大 chunks 大小(治本),设计正当的 sharding-key(治标)。

通过 profile 来监控数据:进行优化查看以后是否开启 profile 性能, 用命令 db.getProfilingLevel() 返回 level 等级,值为 0 |1|2,别离代表意思:0 代表敞开,1 代表记录慢命令,2 代表全副。开启 profile 性能命令为 db.setProfilingLevel(level); #level 等级,值 level 为 1 的时候,慢命令默认值为 100ms,更改为 db.setProfilingLevel(level,slowms)如 db.setProfilingLevel(1,50)这样就更改为 50 毫秒通过 db.system.profile.find() 查看以后的监控日志。

2、硬件层面优化

  • 2.1 确定热数据大小

可能你的数据集十分大,然而这并不那么重要,重要的是你的热数据集有多大,你常常拜访的数据有多大(包含常常拜访的数据和所有索引数据)。应用 MongoDB,你最好保障你的热数据在你机器的内存大小之下,保障内存能包容所有热数据;

  • 2.2 抉择正确的文件系统

MongoDB 的数据文件是采纳的预分配模式,并且在 Replication 外面,Master 和 Replica Sets 的非 Arbiter 节点都是会事后创立足够的空文件用以存储操作日志。这些文件调配操作在一些文件系统上可能会十分慢,导致过程被 Block。所以咱们应该抉择那些空间调配疾速的文件系统。这里的论断是尽量不要用 ext3,用 ext4 或 xfs;

3、架构上的优化

尽可能让主从节点摊派在不同的机器上,防止 IO 操作的与 MongoDB 在同一台机器;

七、总结

MongoDB 具备高性能、易扩大、易上手等特点,在正确应用的状况下,其自身性能还是十分强悍,在一些关键点如片键的抉择、内存的大小和磁盘 IO,往往是限度其性能的最大瓶颈。针对于片键,在业务零碎初期,能够先不对汇合进行数据分片,因为分片键一旦确定就无奈批改,前期可依据业务零碎的状况,认真筛选字段。

个别状况下,不倡议应用升序片键(是一种随着工夫稳定增长的字段, 自增长的主键是升序键),因为这个会导致部分的热读热写,不能施展分片集群的真正实力。倡议应用 hash 片键或者随机散发的片键,这样能够保证数据的平均散发在分片节点;针对于内存,倡议内存的大小可能蕴含热数据的大小加索引大小,保障内存能包容所有热数据。

针对于磁盘资源,MongoDB 的高速读写是以磁盘的 IO 作为根底,为了保障其性能,倡议将主从节点以及高 IO 的利用拆散,以保障 IO 资源尽可能不存在抢占。

原文链接:https://www.jianshu.com/p/f05…

正文完
 0