mongo 连接二三事

如果你也被慢查询、CPU 打满、雪崩等问题困扰,盘它!

查看实例上的慢查询

查询语句说明

假设我们想查询实例上所有执行时间超过 1s 的慢语句。

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

如果想要查看指定 db 上的慢查询:

db.currentOp(
  {
    "active": true,
    "secs_running": {
        "$gt": 1
    },
    "ns": /^siber\./
  }
)

查询结果分析

截取其中一条语句进行分析:

所有输出的这些字段,都可以用于查询条件,常用的有:

字段名

说明

client

该语句来自于哪个客户端

可用于查询指定客户端的请求

opid

该操作的唯一标识

db.killOp()时使用此字段的值

active

操作是否已启动

空闲连接或者内部线程该字段为false

某些已经让步的操作,状态仍可能为 true

secs_running

操作已开始多长时间(秒)

当 active 为 true 时,该字段有值

microsecs_running

操作已开始多长时间(微秒)

当 active 为 true 时,该字段有值

op

操作类型,query、insert、command……

ns

namespace, db.collection 的形式

command

语句具体的执行信息

planSummary

执行计划,可用于慢语句分析

locks

操作对哪些模块加什么类型的锁

模块:

Global

MMAPV1Journal

Database

Collection

Metadata

oplog

锁类型:

R-读锁 W-写锁

r-读意向锁 w-写意向锁

waitingForLock

true:正在等锁

false:已经获得锁

连接处理

kill 指定操作

当慢查询严重,异常连接数过多(或者正常连接数过多),为了保证大局稳定,我们需要“牺牲”部分连接。

MongoDB​ 提供如下方法,可以杀掉任意执行中的操作:

其中 opid 为上文所述 db.currentOp() 中展示的 opid

killOp 原理

每个连接对应的服务线程存储了一个killPending的字段,当发送killOp时,会将该字段置1;请求在执行过程中,可以通过不断的调用OperationContext::checkForInterrupt()来检查killPending是否被设置,如果被设置,则线程退出。

一个请求要支持 killOp,必须在请求的处理逻辑里加上 checkForInterrupt() 检查点才行,否则即使发送了 killOp,也只能等待请求完全处理完毕线程才会退出。

比如 createIndex 的处理逻辑里包含了类似如下的代码,在 createIndex 的循环过程中,一旦 killPending 被置1了,createIndex 的执行可以在当前循环结束时退出。

所以发送 killOp 后,请求要执行到下一个『检查点』线程才会退出,MongoDB 在很多可能耗时长的请求中,都加入了checkForInterrupt()检查点,如创建索引,repair database,mapreduce、aggregation等。

ctrl + c 是否可立即终止操作?

Ctrl + C 会关闭 clientserver 的连接,但后端的线程不会立即结束(MongoDB每个连接的请求由一个对应的线程来处理),而是会一直执行下去。

直到执行结束后,给 client 端发送通知,会发现连接已经断开,这时线程才会退出。

这个时候就需要使用 killOp 去实现真正的“终止”,操作点会在下个检查点结束执行,整个线程退出。

最后更新于

这有帮助吗?