mongo 连接二三事
如果你也被慢查询、CPU 打满、雪崩等问题困扰,盘它!
查看实例上的慢查询
查询语句说明
假设我们想查询实例上所有执行时间超过 1s
的慢语句。
db.currentOp(
{
"active": true,
"secs_running": {
"$gt": 1
}
}
)
如果想要查看指定 db 上的慢查询:
db.currentOp(
{
"active": true,
"secs_running": {
"$gt": 1
},
"ns": /^siber\./
}
)
查询结果分析
截取其中一条语句进行分析:
{
"host" : "a**2.cloud.nu29:3**9",
"desc" : "conn6603723",
"connectionId" : 6603723,
"client" : "172.16.10.108:58243",
"appName" : "MongoDB Shell",
"clientMetadata" : {
"application" : {
"name" : "MongoDB Shell"
},
"driver" : {
"name" : "MongoDB Internal Client",
"version" : "4.2.0"
},
"os" : {
"type" : "Darwin",
"name" : "Mac OS X",
"architecture" : "x86_64",
"version" : "20.3.0"
}
},
"active" : true,
"currentOpTime" : "2021-04-12T14:36:51.243+0800",
"opid" : 1210807065,
"lsid" : {
"id" : UUID("4494c815-cc94-42bf-88cf-45924faef935"),
"uid" : BinData(0,"3t2w+sv/3h3pGF2C4Y8XgsDXkmAm1lgwz8idwd27XZ0=")
},
"secs_running" : NumberLong(2),
"microsecs_running" : NumberLong(2946118),
"op" : "command",
"ns" : "siber.collection_log_case",
"command" : {
"count" : "collection_log_case",
"query" : {
"methodname" : "manage_user.ManageUserService.CreateUser"
},
"lsid" : {
"id" : UUID("4494c815-cc94-42bf-88cf-45924faef935")
},
"$clusterTime" : {
"clusterTime" : Timestamp(1618209403, 2),
"signature" : {
"hash" : BinData(0,"4LE8FiDFhAU84meQOSn/vVRaoTg="),
"keyId" : NumberLong("6909073628604661763")
}
},
"$db" : "siber"
},
"planSummary" : "COLLSCAN",
"numYields" : 3449,
"locks" : {
"Global" : "r",
"Database" : "r",
"Collection" : "r"
},
"waitingForLock" : false,
"lockStats" : {
"Global" : {
"acquireCount" : {
"r" : NumberLong(3450)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(3450)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(3450)
}
}
}
},
所有输出的这些字段,都可以用于查询条件,常用的有:
字段名
说明
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 提供如下方法,可以杀掉任意执行中的操作:
db.killOp(opid)
其中 opid
为上文所述 db.currentOp()
中展示的 opid
。
killOp 原理
每个连接对应的服务线程存储了一个killPending的字段,当发送killOp时,会将该字段置1;请求在执行过程中,可以通过不断的调用OperationContext::checkForInterrupt()来检查killPending是否被设置,如果被设置,则线程退出。
一个请求要支持 killOp,必须在请求的处理逻辑里加上 checkForInterrupt() 检查点才行,否则即使发送了 killOp,也只能等待请求完全处理完毕线程才会退出。
比如 createIndex 的处理逻辑里包含了类似如下的代码,在 createIndex 的循环过程中,一旦 killPending 被置1了,createIndex 的执行可以在当前循环结束时退出。
while (!createIndexFinished) {
createIndexForOneElement();
checkForInterupt();
}
所以发送 killOp 后,请求要执行到下一个『检查点』线程才会退出,MongoDB 在很多可能耗时长的请求中,都加入了checkForInterrupt()检查点,如创建索引,repair database,mapreduce、aggregation等。
ctrl + c 是否可立即终止操作?
Ctrl + C
会关闭 client
到 server
的连接,但后端的线程不会立即结束(MongoDB每个连接的请求由一个对应的线程来处理),而是会一直执行下去。
直到执行结束后,给 client
端发送通知,会发现连接已经断开,这时线程才会退出。
这个时候就需要使用 killOp
去实现真正的“终止”,操作点会在下个检查点
结束执行,整个线程退出。
最后更新于
这有帮助吗?