记一次 MongoDB 占用 CPU 过高问题的排查

本文介绍如何通过分析 MongoDB 的当前操作、启用慢请求日志及优化索引,来解决 CPU 占用率异常升高的问题。文章详细解释了全表扫描、索引设置不合理及大量数据排序对 CPU 消耗的影响,并提供了具体的解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 引言

今天查看监控无意间突然发现自己的服务器上,CPU 占用率飙升到 100%,load 升到 10 以上,登录的响应已经达到半分钟。
马上运行 top,发现主要是 mongodb 占用了大量的 CPU,这是为什么呢?又该如何解决呢?

#此处有图片

2. 分析正在执行的请求

通过运行命令:

db.currentOp()

我们可以看到数据库当前正在执行的操作:

#此处有图片

2.1. 官方文档

https://docs.mongodb.com/manual/reference/method/db.currentOp/?spm=a2c4e.11153940.blogcont73389.10.2c402b90x4iad1。

2.2. 包含信息

主要有以下信息:

  • client – 请求是由哪个客户端发起的
  • opid – 操作的opid,有需要的话,可以通过 db.killOp(opid) 杀死操作
  • secs_running/microsecs_running – 请求运行的时间,如果这个值特别大就非常值得注意
  • query/ns: 对集合进行的具体操作
  • lock*:锁相关参数

3. 开启慢请求日志

MongoDB 支持 profiling 功能,将请求的执行情况记录到同DB下的 system.profile 集合里,profiling 有3种模式:

  1.  0 – 关闭 profiling
  2.  1 – 针对慢请求 profiling,将超过一定阈值的请求,记录到system.profile 集合
  3.  2 – 针对所有请求开启 profiling,将所有请求的执行都记录到 system.profile 集合

3.1. 通过命令开启

推荐在生产环境中设置为 1,开启慢请求日志,方便问题的暴露和排查,可以通过下面命令设置 profiling 级别:

db.setProfilingLevel(1, { slowms: 20 })

{ slowms: 20 } 参数就是慢请求执行阈值,单位是毫秒。

3.2. 通过配置文件开启

也可以通过配置文件开启:

operationProfiling:
  mode: slowOp
  slowOpThresholdMs: 100

3.3. 查看慢请求记录

下面的命令中我们获取了最近的3条慢请求记录:

db.system.profile.find().sort({$natrual: -1}).limit(3)

4. 慢请求分析 – 全表扫描 COLLSCAN

如果在日志中看到关键字 COLLSCAN,说明该查询在进行全表扫描,通常这就是 CPU 异常飙高的主要原因。

4.1. 查看扫描文档数

system.profile 里 docsExamined 的值显示了本次查询的扫描文档数。

4.2. 解决办法 – 添加索引

最好针对查询语句建立索引:

db.col.createIndex({"title":1})

我们也可以在添加索引时增加传入可选参数,例如,在生产环境我们通常不希望索引添加的操作阻塞其他数据库操作,这时就需要务必添加 background 参数:

db.col.createIndex({"title":1}, {'background', true})

5. 慢请求分析 – 索引设置不合理

有的时候,请求即使查询走了索引,执行也很慢,通常是因为索引建立不太合理或者匹配结果太多。
索引通常应该建立在区分度大的字段上。
在 system.profile 中,可以通过 keysExamined 字段查看查询扫描了多少条索引,如果该值过大,要考虑建立新的索引或优化查询了。

6. 慢请求分析 – 大量数据排序

当查询请求里包含排序的时候,如果排序无法通过索引满足,MongoDB 会在内存中对结果进行排序。
大家都知道,排序是非常消耗 CPU 的一项操作,最好在需要排序的字段上建立索引。

system.profile 中的 SORT 关键字反映了查询需要排序。

7. 服务能力评估

有时 CPU 消耗过高仅仅是单纯的因为服务器达到了上限。
如果上面的措施都无法让 CPU 占用率下降到合理的指标内,就要考虑扩容、升级来提升服务能力的上限。
但切忌将这个方法作为首要考虑的解决方案,合理的设置索引,建立资源预警,而不是盲目提升配置或在业务已经达到上限时再考虑优化。

8. 参考资料

https://docs.mongodb.com/manual/reference/method/db.currentOp/?spm=a2c4e.11153940.blogcont73389.10.2c402b90x4iad1。
https://docs.mongodb.com/manual/tutorial/manage-the-database-profiler/?spm=a2c4e.11153940.blogcont73389.11.2c402b90x4iad1。
https://docs.mongodb.com/manual/reference/database-profiler/?spm=a2c4e.11153940.blogcont73389.13.2c402b90WPcbsr。
https://yq.aliyun.com/articles/73389。
http://www.runoob.com/mongodb/mongodb-indexing.html。

我们业务目前使用的是阿里云的云资源,关于云资源我配置了如下告警规则,请根据我的告警规则帮我设计一套基于规则的故障检测联合规则 ES-宕机【紧急】 ES-磁盘使用率 ES-内存使用率 ES-节点CPU使用率 ES-集群不健康 ES load kafka-消息堆积 kafka-消息生产量 kafka-消费量 kafka-磁盘使用率 mongodb-磁盘使用率 mongodb-内存使用率 mongodb-CPU使用率 mongodb-连接数 mongodb-实例重启 mysql-数据库宕机【紧急】 mysql-磁盘使用率 mysql-内存使用率【紧急】 mysql-数据库CPU使用率于70% mysql-IOPS使用率 mysql-连接池使用率 mysql-行锁时间长 mysql-慢查询过 mysql-拒绝连接数 prometheus宕机 redis-内存使用率 redis-CPU使用率【紧急】 redis-实例发生重启 redis-连接率 redis-redis_averager_duration_high redis - 分片CPU使用率 redis BPS持续【紧急】 线程池活跃线程数 线程池队列占用 node-宕机【紧急】 node-节点CPU使用率过 node-节点inode使用率过 node-节点内存使用率过 node-节点磁盘使用率过 节点池CPU request过 节点池CPU request于100%【紧急】 节点池CPU Limit于150% node-节点CPU iowait使用率过 node-cat-节点内存使用率过 核心EIP 流入带宽超150MB node 节点starcharge-prod 命名空间下pod超过11个 node 节点starcharge-prod 命名空间下L0应用超过6个 node-新加坡nginx节点CPU使用率过 coredns 解析超时 Kafka Broker 异常
最新发布
04-01
<think>嗯,用户需要设计一套基于他们现有告警规则的故障检测联合规则。首先,我需要仔细看看他们配置的告警有哪些。他们用了阿里云,涉及ES、Kafka、MongoDB、MySQL、Redis、Node、线程池、Prometheus、EIP、CoreDNS等服务,每个服务都有不同的指标告警,有的标为紧急。 首先,用户的需求是联合规则,也就是当个告警同时触发时,能够更准确地判断故障根源。比如,ES宕机是紧急的,可能需要结合磁盘、内存、CPU的告警来判断是否因为资源不足导致的。或者,MySQL的宕机可能和磁盘使用率、IOPS有关联。所以,联合规则需要考虑不同服务之间的依赖关系和资源竞争情况。 接下来,需要分类处理这些告警。可能分成基础设施层、中间件层、数据库层、应用层等。比如,节点(node)的问题会影响上面运行的Pod和中间件,所以当节点宕机时,可能连带影响ES、Kafka等。这时候需要优先处理节点的问题,再检查其他服务。 然后,标为紧急的告警需要优先处理。例如,ES-宕机、MySQL-数据库宕机、redis-CPU使用率紧急、节点池CPU request于100%紧急等。这些紧急告警可能需要立即响应,甚至自动触发某些恢复操作,比如扩容或重启实例。 另外,有些告警可能存在因果关系。比如,Kafka消息堆积可能是因为生产者消息量突然激增,或者消费者处理能力下降。这时候需要同时监控生产量、消费量和磁盘使用率,判断是源头问题还是处理端的问题。 还需要考虑资源瓶颈的连锁反应。例如,节点磁盘使用率可能导致Pod被驱逐,进而影响中间件如MySQL或Redis的运行,引发它们的告警。这时候需要从底层资源开始排查。 对于数据库类,比如MySQL,连接数、慢查询、行锁时间长可能共同导致数据库响应变慢,甚至宕机。需要将这些关联指标结合起来,分析是否是同一问题导致的指标异常。 此外,像CoreDNS解析超时可能会影响整个集群的服务发现,导致服务无法通信,这时候需要检查CoreDNS本身的资源使用情况,或者网络配置问题。 可能还需要考虑地域因素,比如用户提到的新加坡nginx节点CPU,可能需要单独处理,或者检查该区域的流量是否异常,比如EIP流入带宽是否超限。 最后,设计联合规则时,需要设定优先级,紧急告警优先,然后根据依赖关系层层递进。同时,可能需要设置抑制规则,避免重复告警,比如节点宕机导致的其他服务告警可以被抑制,直到节点恢复。 总结来说,联合规则需要从基础设施到应用层,按依赖关系分层,识别关键路径,关联相关指标,设定优先级和抑制策略,确保快速定位根本原因,避免告警风暴,提故障处理效率。</think>我将基于您列出的告警规则,设计一个分层级联的故障检测联合规则体系,分为三个层级:基础设施层、中间件层、应用层。以下是具体设计方案: 一、基础设施层优先检测(直接影响全局) ------------------------------------- $$ \text{紧急规则} = \text{节点宕机} \vee \text{EIP带宽超限} \vee \text{节点池CPU Request>100\%} $$ 1. **节点宕机联检**: - 当 `node-宕机【紧急】` 触发时 - 立即关联检查: $$ \text{节点存活率} = \frac{\text{存活节点数}}{\text{总节点数}} < 80\% $$ 若成立则触发集群级故障 2. **资源超限联检**: ```python if (节点池CPU Request >100%) or (EIP流入带宽 >150MB): 强制检查对应节点的CPU iowait、磁盘IOPS if 节点磁盘使用率 >85%: 标为存储瓶颈型故障 ``` 二、中间件层联合检测(服务依赖关系) ----------------------------------- 1. **ES集群故障树**: $$ \text{ES故障} = \text{集群不健康} \wedge (\text{磁盘使用率}>85\% \vee \text{内存}>90\%) $$ - 当 `ES-磁盘使用率` + `ES load ` 同时触发时 - 自动检查 JVM 内存压力指标: $$ \text{内存压力指数} = \frac{\text{Young GC次数}}{\text{Old GC次数}} > 10:1 $$ 2. **Kafka消息堆积根因分析**: ``` WHEN (消息堆积量 > 1万条/秒) THEN IF 生产量突增 >300% → 标为流量激增型故障 ELSE IF 消费量下降 >50% → 检查消费者线程池状态 ELSE IF 磁盘使用率 >90% → 标为存储瓶颈 ``` 三、数据库层关键路径检测 ----------------------- 1. **MySQL紧急故障矩阵**: | 触发条件 | 关联指标 | 处置策略 | |-------------------------|----------------------------|-----------------------| | 数据库宕机 | 最后5分钟IOPS>基础值200% | 优先恢复主库 | | 行锁时间>30s + 慢查询>50 | 连接池使用率>90% | 触发SQL限流 | 2. **Redis级联检测模型**: $$ \text{Redis危机} = \left(\frac{\text{内存使用率}}{\text{连接率}} > 1.2\right) \wedge \left(\text{分片CPU} > 80\%\right) $$ - 当 `BPS持续` 触发时 - 自动关联检查: $$ \frac{\text{网络带宽使用量}}{\text{实例规格上限}} > 75\% $$ 四、应用层异常关联规则 --------------------- 1. **线程池雪崩预测**: $$ \text{风险系数} = \left(\frac{\text{活跃线程}}{\text{最大线程}}\right) \times \left(\frac{\text{队列占用率}}{100}\right) > 0.8 $$ - 当风险系数超标时: $$ \text{自动关联检查} = \text{慢查询数量} + \text{Redis响应时间} $$ 2. **Pod密度异常检测**: ``` IF (starcharge-prod Pod数量 >11) THEN 检查: 节点CPU使用率是否>80% 节点内存是否>85% IF 同时触发L0应用>6 → 标为调度异常 ``` 五、全局抑制规则(避免告警风暴) ------------------------------- 1. 当 `节点宕机` 触发时: - 自动抑制该节点上所有中间件告警(ES/Kafka等) - 抑制时长为故障恢复时间+10分钟 2. 当 `CoreDNS解析超时` 触发时: $$ \text{抑制范围} = \text{所有依赖服务发现的应用告警} $$ 六、推荐配置的响应策略 --------------------- 1. **自动扩容规则**: ``` WHEN (CPU使用率 >85%持续5分钟) AND (节点池CPU Request <90%) AND (非突发流量) THEN 触发节点池自动扩容 ``` 2. **紧急熔断阈值**: | 服务 | 熔断条件 | 动作 | |------------|----------------------------------|--------------------------| | MySQL | 连接拒绝率>30%持续2分钟 | 切断非核心业务连接 | | Redis | 分片CPU>95%持续3分钟 | 启用只读模式 | 建议配合阿里云ARMS服务配置告警流水线,将以上规则划分为: - P0级(需立即人工介入):红色标的【紧急】类告警 - P1级(自动处置+通知):黄色标的资源类告警 - P2级(仅录):蓝色标的辅助指标告警
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值