• 通过Mongo Shell连接实例。
    详情请参见、Mongo Shell连接副本集实例、。

  • 执行命令,查看数据库当前正在执行的操作。
    该命令的输出示例如下。

您需要重点关注以下几个字段。

通过db.currentOp()查看正在执行的操作,分析是否有不正常耗时的请求正在执行。例如您的业务平时CPU使用率不高,运维管理人员连到MongoDB数据库执行了一些需要全表扫描的操作导致CPU使用率非常高,业务响应缓慢,此时需要重点关注执行时间非常耗时的操作。

说明 如果发现有异常的请求,您可以找到该请求对应的opid,执行db.killOp(opid)终止该请求。

如果您的应用刚刚上线,MongoDB实例的CPU使用率马上处于持续很高的状态,执行db.currentOp(),在输出结果中未发现异常请求,您可参见下述小节分析数据库慢请求。

云数据库MongoDB默认开启了慢请求Profiling ,系统自动地将请求时间超过100ms的执行情况记录到对应数据库下的system.profile集合里。

  • 通过use <database>命令进入指定数据库。

  1. use mongodbtest
  • 执行如下命令,查看该数据下的慢请求日志。
  • 分析慢请求日志,查找引起MongoDB CPU使用率升高的原因。
    以下为某个慢请求日志示例,可查看到该请求进行了全表扫描,扫描了11000000个文档,没有通过索引进行查询。
  1. {
  2. "op" : "query",
  3. "ns" : "123.testCollection",
  4. "command" : {
  5. "find" : "testCollection",
  6. "filter" : {
  7. "name" : "zhangsan"
  8. },
  9. "$db" : "123"
  10. },
  11. "keysExamined" : 0,
  12. "docsExamined" : 11000000,
  13. "cursorExhausted" : true,
  14. "numYield" : 85977,
  15. "nreturned" : 0,
  16. "locks" : {
  17. "acquireCount" : {
  18. "r" : NumberLong(85978)
  19. }
  20. },
  21. "Database" : {
  22. "acquireCount" : {
  23. "r" : NumberLong(85978)
  24. }
  25. },
  26. "Collection" : {
  27. "acquireCount" : {
  28. "r" : NumberLong(85978)
  29. }
  30. }
  31. },
  32. "responseLength" : 232,
  33. "protocol" : "op_command",
  34. "millis" : 19428,
  35. "planSummary" : "COLLSCAN",
  36. "execStats" : {
  37. "stage" : "COLLSCAN",
  38. "filter" : {
  39. "$eq" : "zhangsan"
  40. }
  41. "nReturned" : 0,
  42. "executionTimeMillisEstimate" : 18233,
  43. "works" : 11000002,
  44. "advanced" : 0,
  45. "needTime" : 11000001,
  46. "needYield" : 0,
  47. "saveState" : 85977,
  48. "restoreState" : 85977,
  49. "isEOF" : 1,
  50. "invalidates" : 0,
  51. "direction" : "forward",
  52. ....in"
  53. }
  54. ],
  55. "user" : "root@admin"
  56. }

通常在慢请求日志中,您需要重点关注以下几点。

  • 全表扫描(关键字: COLLSCAN、 docsExamined )
    • 全集合(表)扫描COLLSCAN 。
      当一个操作请求(如查询、更新、删除等)需要全表扫描时,将非常占用CPU资源。在查看慢请求日志时发现COLLSCAN关键字,很可能是这些查询占用了CPU资源。

说明 如果这种请求比较频繁,建议对查询的字段建立索引的方式来优化。

  • 通过查看docsExamined的值,可以查看到一个查询扫描了多少文档。该值越大,请求所占用的CPU开销越大。
    • 不合理的索引(关键字: IXSCAN、keysExamined )

说明

  • 索引不是越多越好,索引过多会影响写入、更新的性能。
  • 如果您的应用偏向于写操作,索引可能会影响性能。

通过查看keysExamined字段,可以查看到一个使用了索引的查询,扫描了多少条索引。该值越大,CPU开销越大。

如果索引建立的不太合理,或者是匹配的结果很多。这样即使使用索引,请求开销也不会优化很多,执行的速度也会很慢。

如下所示,假设某个集合的数据,x字段取值的重复率很高(假设只有1、2),而y字段取值的重复率很低。

  1. db.createIndex( {x: 1} ) 效果不好,因为x相同取值太多
  2. db.createIndex( {x: 1, y: 1} ) 效果不好,因为x相同取值太多
  3. db.createIndex( {y: 1 } ) 效果好,因为y相同取值很少

关于{y: 1} 与 {y: 1, x: 1} 的区别,可参见MongoDB索引原理及。

  • 大量数据排序(关键字: SORT、hasSortStage )
    当查询请求里包含排序的时候, system.profile 集合里的hasSortStage字段会为 true 。如果排序无法通过索引满足,MongoDB会在查询结果中进行排序。而排序这个动作将非常消耗CPU资源,这种情况需要对经常排序的字段建立索引的方式进行优化。

说明 当您在system.profile集合里发现SORT关键字时,可以考虑通过索引来优化排序。

其他还有诸如建立索引、aggregation(遍历、查询、更新、排序等动作的组合) 等操作也可能非常耗CPU资源,但本质上也是上述几种场景。更多profiling的设置请参见profiling官方文档

您也可以将MongoDB实例接入至混合云数据库管理HDM(Hybrid Cloud Database Management)。在HDM控制台中,您可以对MongoDB实例的实时性能、实时会话、慢日志、磁盘空间等信息进行监控和管理,详情请参见。

经过上述分析数据库正在执行的请求和分析数据库慢请求两轮优化之后,整个数据库的查询相对合理,所有的请求都高效地使用了索引。

此时在业务环境使用中还经常遇到CPU资源被占满,那么可能是实例的服务能力已经达到上限了。这种情况下您应当查看监控信息以分析实例资源使用状态;同时对MongoDB数据库进行测试,以便了解在您的业务场景下,当前实例是否满足所需要的设备性能和服务能力。

如您需要升级实例,可以参见或变更副本集实例节点数进行操作。