生产事故(MongoDB数据分布不均解决方案)
可以很明显可以看到我们这个集合的数据严重分布不均匀。
一共有8个分片,面对这个情况我首先想到的是手动拆分数据块,但这不是解决此问题的根本办法。
造成此次生产事故的首要原因就是片键选择上的问题,由于片键选择失误,在数据量级不大的时候数据看起来还是很健康的,但随着数据量的暴涨,问题就慢慢浮出了水面,我们使用的组合片键并不是无规律的,片键内容是线性增长的,这就导致了数据的不正常聚集。由于数据分布不均匀,我们有两个分片的磁盘使用率接近80%,数据还在持续增长,这个问题必须尽快解决。
涉及到此次事故的集合一共有三个,总数据量加起来接近30T,数据总量300亿左右。
下面是我解决此问题的解决方案:
方案一:
第一步:创建一个新的分片表,片键我选择_id做hashed分片,并提前分好了数据块,降低在恢复期间频繁切割数据造成的服务器压力。
sh.shardCollection("loan_his.collection",{_id:"hashed"}www.zheshengjpt.com,false,{numInitialChunks:1024})
第二步:单独连接各个分片将8个分片的数据全量备份:
nohup mongodump -u loan_his -p loan_his --authenticationDatabase loan_his -h ${replset} --db loan_his --collection ${collectionName} --query '{"txdt": { $lte: "2019-07-09"} }' -o ${bak_dir} &>> ${log} &
你可能会问为什么不连接mongos,因为我在连接mongos做数据备份时出现了以下异常:
2019-07-08T16:10:03.886+0800 Failed: error writing data for collection `loan_his.ods_cus_trad` to disk: error reading collection: operation was interrupted
可能是因为集合内的数据坏块吧,此异常信息是我备份了将近70%的数据后突然抛出的异常信息。
除了这个原因,单独备份各个分片的数据后你能够自由控制恢复数据的时间窗口,不会因为恢复单个数据文件时间较长,突发意外情况导致恢复中断从头再来的窘境。能够根据服务器的状态避开高峰期来进行数据恢复。
备份期间我发现了有时候备份出来的总文档数和 db.collection.getShardDistribution() 查看的文档数不一致,我还以为是备份期间出了问题,但我删除当前备份文件后重新备份出来的文档数还是和之前一样。目前不知道是怎么回事,怀疑是坏的数据块引发的我问题,备份出来的数据一般会比原数据量多几万条数据,有时候会少一些。
第三步:恢复数据:
mongorestore -u loan_his -p loan_his --authenticationDatabase loan_his -h 10.0.156.9:27017 --db loan_his --collection ${collectionName_two} /mongodb/${collectionName}/replset_sh2/loan_his/${collectionName}.bson &>> ${log}
在恢复数据前千万要记得不要创建索引!否则性能极差,速度非常非常慢!在使用mongodump工具备份时,在数据文件的同级目录下会有一个 XXXXX.metadata.json 索引文件,默认会在数据恢复完毕后执行创建索引的操作。
此处有坑需要注意:因为备份出来的数据是由原表备份出来的,那这个索引文件也是原表的索引,由于原表我使用的是组合片键做的分片,所以在原表内会存在一个由片键组成的组合索引,并且不是后台创建的组合索引!!!这意味着如果你使用此索引文件来给新表创建索引,会造成这个集群处于阻塞状态,无法响应任何操作!!直至索引创建完毕。所以你可以将这个索引文件备份到其它目录以作参考,然后将原文件删除就可以了,恢复数据时不会有其它的问题。
如果恢复期间出现了意外情况导致恢复失败,比如节点宕机什么的,不需要担心,重新执行恢复程序,数据文件不会重复增加,因为备份出来的数据文件包含mongodb自带的 Objectld对象_id ,导入时,如果已存在此ID,将不会插入数据。注意:在不同集合是允许出现相同ID的,所以在使用方案二恢复数据时,新产生的数据不能通过新表A备份出来汇入新表C,需要通过原始数据文件重新导入。
第四步:创建索引:
待所有数据恢复完毕后再创建索引,一定要记得后台创建!!!你也可以将索引拆分,一个一个的来。如果觉得此操作对业务影响较大,请看本文最后的解决方案。
mongo 10.0.156.2:27017/loan_his -uloan_his -ploan_his -eval 'db.getSiblingDB("loan_his").runCommand({createIndexes: "collection",indexes: [{"v":2,"key":{"_id":1},"name":"_id_","ns":"loan_his.collection"},{"v":2,"key":{"opnode":1.0,"txdt":1.0,"acct":1.0,"crdno":1.0},"name":"opnode_1_txdt_1_acct_1_crdno_1","ns":"loan_his.collection"},{"v":2,"key":{"txdt":1.0,"opnode":1.0,"acct":1.0,"crdno":1.0,"pbknum":1.0},"name":"txdt_1_opnode_1_acct_1_crdno_1_pbknum_1","ns":"loan_his.collection","background":true},{"v":2,"key":{"acct":1.0,"txdt":1.0,"opnode":1.0},"name":"acct_1_txdt_1_opnode_1","ns":"loan_his.collection","background":true},{"v":2,"key":{"crdno":1.0,"txdt":1.0,"opnode":1.0},"name":"crdno_1_txdt_1_opnode_1","ns":"loan_his.collection","background":true},{"v":2,"key":{"pbknum":1.0,"txdt":1.0,"opnode":1.0},"name":"pbknum_1_txdt_1_opnode_1","ns":"loan_his.collection","background":true}]})'
停止失控索引:
一旦你触发一个索引,简单的重启服务并不能解决这个问题,因为MongoDB会继续重启前的建索引的工作。如果之前你运行后台建索引任务,在服务重启后它会变成前台运行的任务。在这种情况下,重启会让问题变得更糟糕。MongoDB提供了选项“noIndexBuildRetry”,它会指示MongoDB重启后不再继续没建完的索引。如果不小心在前台创建了索引导致集群不可用,可以使用--noIndexBuildRetry 参数重启各个分片来停止索引的创建过程,只用重启主节点就可以了。如果是在后台创建索引,重启时记得加上--noIndexBuildRetry,否则重启后创建索引的线程会重新被唤醒,并由后台创建变为前台创建,导致整个集群不可用。
mongod -f $CONFIGFILE --noIndexBuildRetry
此方案迁移期间不用通知业务系统做变更,把数据迁移完毕后,通知业务系统将表名变更,弊端就是在你迁移的过程中数据还是会持续增长的,问题分片的磁盘容量会越来越少。
方案二:
为了避免在迁移期间数据仍在增长,导致数据还没迁移完毕磁盘就爆满的情况,可以选择停止往旧表B内写入数据,创建一个健康的新表A,新的数据往新表A内写,具体的查询方案需要应用系统的配合。然后将旧表B的数据迁移至新表C中,最终将新表A的数据汇入新表C , 完成数据迁移。此次迁移数据耗时共9个月!!!片键一定要慎重选择,因为我们使用的MongoDB是3.4.7版本的,不支持修改片键,最新版本支持片键的修改。
接下来介绍数据量较大时如何构建索引--减少业务最少影响
在数据量较大或请求量较大,直接建立索引对性能有显著影响时,可以利用复制集(数据量较大时一般为线上环境,使用复制集为必然选择或者使用分片.)中部分机器宕机不影响复制集工作的特性,继而建立索引。
(1)首先把 secondary server 停止,再注释 --replSet 参数,并且更改 MongoDB port 之后重新启动 MongoDB,这时候 MongoDB 将进入 standalone 模式;
(2).在 standalone 模式下运行命令 ensureIndex 建立索引,使用 foreground 方式运行也可以,建议使用background方式运行;
(3)建立索引完毕之后关闭 secondary server 按正常方式启动;
4.根据上述 1~3 的步骤轮流为 secondary 建立索引,最后把 primary server 临时转换为 secondary server,同样按 1~3 的方法建立索引,再把其转换为 primary server。
日志内容大致如下:
2019-09-24T18:51:39.003+0800 I - [www.tongyayule.com conn33] Index Build: 838416900/876543270 95%
2019-09-24T20:10:08.360+0800 I INDEX [www.jiuyueguojizc.cn conn33] done building bottom layer, going to commit
2019-09-24T20:10:26.001+0800 I - [www.wuji5pingtai.cn conn33] Index: (2/3) BTree Bottom Up Progress: 11684400/876543270 1%
done building bottom layer, going to commit
生产事故(MongoDB数据分布不均解决方案)的更多相关文章
- 一次 select for update 的悲观锁使用引发的生产事故
1.事故描述 本月 8 日上午十点多,我们的基础应用发生生产事故.具体表象为系统出现假死无响应.查看事发时间段的基础应用 error 日志,没发现明显异常.查看基础应用业务日志,银行结果处理的部分普遍 ...
- MySQL--eq_range_index_dive_limit参数学习,MYSQL 5.6 5.7处理数据分布不均的问题
官方文档如下描述:This variable indicates the number of equality ranges in an equality comparison condition w ...
- 「生产事故」MongoDB复合索引引发的灾难
前情提要 11月末我司商品服务的MongoDB主库曾出现过严重抖动.频繁锁库等情况. 由于诸多业务存在插入MongoDB.然后立即查询等逻辑,因此项目并未开启读写分离. 最终定位问题是由于:服务器自身 ...
- 记一次重大生产事故,在那 0.1s 我想辞职不干了!
一.发生了什么? 1.那是一个阳光明媚的下午,老婆和她的闺蜜正在美丽的湖边公园闲逛(我是拎包拍照的). 2.突然接到甲方运营小妹的微信:有个顾客线上付款了,但是没有到账,后台卡在微信支付成功(正常状态 ...
- Insert into select语句引发的生产事故
前言 Insert into select请慎用.这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份.本想通过程序先查询查出来然后批量插入.但xxx觉得这样有点慢,需要耗费大量的网络 ...
- 一次 Redis 事务使用不当引发的生产事故
这是悟空的第 170 篇原创文章 官网:http://www.passjava.cn 你好,我是悟空. 本文主要内容如下: 一.前言 最近项目的生产环境遇到一个奇怪的问题: 现象:每天早上客服人员在后 ...
- 在Windows7下启动MongoDB服务的解决方案
1:首先去官网下载程序,我用的是1.4.3版本,地址: http://downloads.mongodb.org/win32/mongodb-win32-i386-1.4.3.zip 2:创建一个DB ...
- linux日志审计项目案例实战(生产环境日志审计项目解决方案)
所谓日志审计,就是记录所有系统及相关用户行为的信息,并且可以自动分析.处理.展示(包括文本或者录像) 推荐方法:sudo配合syslog服务,进行日志审计(信息较少,效果不错) 1.安装sudo命令. ...
- 从一次生产事故说起——linux的单用户模式,救援模式等等
伴随着今年linux上面最大一个安全漏洞bash漏洞的出现,我们公司也開始了风风火火的漏洞修复工作,机器一多,也就easy出问题,有台64位的linuxserver一不小心就升级了32位 bash 的 ...
随机推荐
- Oracle 组函数count()
1.count() 函数的参数除了可以是字段值和表达式外,还可以是“ * ”.如果是字段值或表达式,则忽略空值且考虑重复值:如果是“ * ”,则计算所有的行,也包括空值.如果要查询某字段非重复值的个数 ...
- [LeetCode] 928. Minimize Malware Spread II 最大程度上减少恶意软件的传播之二
(This problem is the same as Minimize Malware Spread, with the differences bolded.) In a network of ...
- Java IO流学习总结(转)
原文地址:http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 ...
- Web.config中executionTimeout的单位
executionTimeout:表示允许执行请求的最大时间限制,单位为秒
- vant库在vue全局引入toast组件
第一步: 在config中引入 // 全局引入vant的提示框 import { Toast } from "vant"; Vue.use(Toast); 第二步: 在组要的.vu ...
- DRF源码-fields.py
https://www.cnblogs.com/pyspark/p/8607801.html https://www.cnblogs.com/LYliangying/articles/9896548. ...
- UVA - 12113 Overlapping Squares(重叠的正方形)
题意:给定一个4*4的棋盘和棋盘上所呈现出来的纸张边缘,问用不超过6张2*2的纸能否摆出指定的形状. 分析:2*2的纸在4*4的棋盘上总共有9种放置位置,枚举所有的放置位置即可.枚举情况总共种. #p ...
- javascript如何获取复选框中的值?
思路:获取checkbox对象→循环checkbox数组,根据checked属性判断是否选中→使用value属性获取选中项的值.实例演示如下: 1.HTML结构 <form> <in ...
- IDEA控制台输出中文乱码日志文件正常
控制台中文输出乱码但输出的日志文件正常 idea.exe.vmoptions与idea64.exe.vmoptions已经配置 -Dfile.encoding=UTF-8 logback.xml中也配 ...
- 每天一点点之数据结构与算法 - 应用 - 分别用链表和数组实现LRU缓冲淘汰策略
一.基本概念: 1.什么是缓存? 缓存是一种提高数据读取性能的技术,在硬件设计.软件开发中都有着非广泛的应用,比如常见的CPU缓存.数据库缓存.浏览器缓存等等. 2.为什么使用缓存?即缓存的特点缓 ...