暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

灵活运用$currentop管道符进行Mongodb会话管理

IT那活儿 2020-09-14
2170

在DBA的日常工作中,数据库的会话监控和管理是一项十分重要的工作,在关系型数据库中,有v$session、processlist、pg_stat_activity等表或者视图提供会话信息查询,但是在非关系型的mongodb中,除了local库的system.session集合中存了简单的用户信息外,并无其他集合存了会话信息,只能通过db.currentOp()命令来采集信息。

db.currentOp()输出的结果如下:

testrs:PRIMARY>db.currentOp();

{

       "inprog": [

{

"host": "standbydb:27017",---实例信息

"desc": "conn445", ---连接描述

"connectionId": 445,---连接ID

"client": "192.168.56.50:55029", ---客户端IP和端口号

"clientMetadata": { ---客户端信息,包括驱动、操作系统等

"driver": {

"name": "NetworkInterfaceASIO-RS",

"version": "3.6.4"

},

"os": {

"type": "Linux",

"name": "Red Hat Enterprise Linux Server release 6.5 (Santiago)",

"architecture": "x86_64",

"version": "Kernel 2.6.32-431.el6.x86_64"

}

},

"active": true, ---会话状态

"currentOpTime": "2020-09-05T20:58:13.747+0800", --操作时间

"opid": 68359, ---操作ID,可kill

"secs_running": NumberLong(3), --运行时间,单位为S

"microsecs_running": NumberLong(3256666),--运行时间,单位为MS

"op": "getmore",  ---操作类型

"ns": "local.oplog.rs", ---操作记得集合

"command": {  ---命令相关信息

"getMore": NumberLong("10120168314"),

"collection": "oplog.rs",

"batchSize": 13981010,

"maxTimeMS": NumberLong(5000),

"term": NumberLong(78),

"lastKnownCommittedOpTime": {

"ts": Timestamp(1599310685, 1),

"t": NumberLong(78)

},

"$replData": 1,

"$oplogQueryData": 1,

"$readPreference": {

"mode": "secondaryPreferred"

},

"$clusterTime": {

"clusterTime": Timestamp(1599310685, 1),

"signature": {

"hash": BinData(0,"b61IG+HtFykMKvbLnQqsgQBe9tQ="),

"keyId": NumberLong("6844403992496177153")

}

},

"$db": "local"

},

"planSummary": "COLLSCAN", ---执行计划

"numYields": 2,

"locks": { ---锁信息

},

"waitingForLock": false,---是否等待锁

"lockStats": {

"Global": {

"acquireCount": {

"r": NumberLong(4)

}

},

"Database": {

"acquireCount": {

"r": NumberLong(2)

}

},

"oplog": {

"acquireCount": {

"r": NumberLong(2)

}

}

}

}

],

"ok": 1,

"operationTime": Timestamp(1599310685, 1),

"$clusterTime": {

"clusterTime": Timestamp(1599310685, 1),

"signature": {

"hash": BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),

"keyId": NumberLong(0)

}

}

}

向上滑动查看更多内容

由上图可看出输出结果inprog是一个数组,在数组里面要实现统计和过滤等,比较困难,只能结合javascript脚本实现。而在Mongodb3.6中引入了$currentop聚合管道符,使Mongodb的会话管理变得更加容易。

该管道符只能在admin库执行,使用方法:

{$currentOp: { allUsers: <boolean>, idleConnections: <boolean>} }

示例:显示当前会话,按照客户端IP进行分组统计

--显示当前的会话中,以客户端IP(10网段)地址分组统计连接数

useadmin

db.aggregate([

{$currentOp: { allUsers: true ,idleConnections:true} },--取出所有会话

{$project:{IP:{$split:["$client",":"]}}},显示client字段,并按:拆分成数组

{$unwind:"$IP"},--将数组拆分成文档

{$match:{"IP":/^10\./}},--过滤符合条件的文档

{$group:{_id:"$IP",count:{$sum:1}}}—按IP地址分组统计

]);

以上为例,根据db.currentOp()的输出结果字段信息,结合Mongodb管道的使用,就可灵活的实现各种统计功能和问题定位。

--显示当前的活动会话信息

db.aggregate([

{$currentOp: { allUsers: true ,idleConnections:false} },

{$project:{opid:1,client:1,op:1,ns:1,microsecs_running:1}},

{$match:{client:{$exists:true}}},

{$sort:{microsecs_running:-1}}

]);

--查看当前是否有大量会话在等待锁

db.aggregate([

{$currentOp: { allUsers: true ,idleConnections:false} },

{$project:{opid:1,client:1,op:1,ns:1,microsecs_running:1,waitingForLock:1}},

{$match:{"waitingForLock":true}},

{$count:"waitfor locks"}

]);

如果存在大量锁等待,则首先检查是否存在表、库、全局锁:

db.aggregate([

{$currentOp: { allUsers: true ,idleConnections:false} }, {$match:{$or:[{"locks.Global":"W"},{"locks.Database":"W"},{"locks.Collection":"W"}]}}

])

如果发现有会话持有表级、库级或者全局锁,则可根据其opid,执行db.killOp(opid)释放锁资源。如果未发现表级以上的锁,则检查不处于等待状态的会话在做些什么操作,再进行具体处理:

db.aggregate([

{$currentOp: { allUsers: true ,idleConnections:false} },

{$project:{opid:1,client:1,op:1,ns:1,microsecs_running:1,waitingForLock:1}},

{$match:{$and:[{"waitingForLock":false},{client:{$exists:true}}]}},

{$sort:{microsecs_running:-1}}

]);

示例:前台索引创建导致库级锁

模拟在前台创建索引,同时其他会话在相同数据库做读写操作,通过下图可看到有两个会话在等待:

以上查询,均只能查询实时会话情况,如果要查询历史问题,在开启了慢日志的情况下,可以通过后台日志进行跟踪,但是如果在业务量较大的环境下,如果出现锁阻塞,可能会导致大量日志产生,建议使用mtools工具包进行日志分析。

文章转载自IT那活儿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论