MongoDB7.0一些有用的功能

摘要

  • 本文介绍MongoDB7.0的一些有用的功能,比如运行js,查看慢查询日志等等

  • MongoDB官方文档

  • 本文基于CentOS8(x86_64)

运行js

  • 运行js文件

insertMany.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var tags = ['nosql', 'mongodb', 'document', 'developer', 'popular']
var types = ['technology', 'sociality', 'travel', 'novel', 'literature']
var books = []
for (var i = 0; i < 50; i++) {
var typeIdx = Math.floor(Math.random() * types.length)
var tagIdx = Math.floor(Math.random() * tags.length)
var favCount = Math.floor(Math.random() * 100)
var book = {
title: 'book-' + i,
type: types[typeIdx],
tag: tags[tagIdx],
favCount: favCount,
author: 'xxx' + i
}
books.push(book)
}
db.books.insertMany(books)
1
2
# -f 运行js文件
mongosh "mongodb://user:password@10.1.2.26:27017,10.1.2.142:27017,10.1.2.41:27017/test?authSource=admin&replicaSet=rs0" -f insertMany.js
  • 运行js语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ---eval 运行js语句
mongosh "mongodb://user:password@10.1.2.26:27017,10.1.2.142:27017,10.1.2.41:27017/test?authSource=admin&replicaSet=rs0" --eval "db.books.find().limit(2)"
[
{
_id: ObjectId('660d0b05a8a6c09b0b1852b7'),
title: 'book-0',
type: 'novel',
tag: 'document',
favCount: 58,
author: 'xxx0'
},
{
_id: ObjectId('660d0b05a8a6c09b0b1852b8'),
title: 'book-1',
type: 'novel',
tag: 'popular',
favCount: 10,
author: 'xxx1'
}
]

Profiler模块

  • Profiler模块可以用来记录、分析MongoDB的详细操作日志,默认情况下该功能是关闭的。

  • Profiler模块开启对于每个业务库来说是独立的,对某个业务库开启Profiler模块之后,符合条件的慢操作日志会被写入该库的system.profile集合中。

  • Profiler模块的调试级别有:

1
2
3
0:关闭Profiler模块;
1:部分开启,仅符合条件(时长大于slowms)的操作日志会被记录;
2:日志全开,所有的操作日志都被记录;
  • 设置Profiler模块的调试级别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 设置Profiler模块的调试级别为2
> db.setProfilingLevel(2)

# 查看当的调试级别信息
> db.getProfilingStatus()
{
was: 2, # 当前的调试级别
slowms: 100, # 慢查询的阈值,单位是毫秒;
sampleRate: 1.0, # 日志随机采样率,1.0则表示满足条件的全部输出。
ok: 1, # 状态
'$clusterTime': { # 时间戳
clusterTime: Timestamp({ t: 1712471779, i: 1 }), # 时间戳
signature: { # 签名
hash: Binary.createFromBase64('GGCAjzJrW8arhfJX0Cn0VpvC5MA=', 0), # 签名
keyId: Long('7346062378896719877') # 签名
}
},
operationTime: Timestamp({ t: 1712471779, i: 1 }) # 操作时间
}

# 只记录时长超过500ms的操作
> db.setProfilingLevel(1,500)
# 同时加上采样率
> db.setProfilingLevel(1,{slowms:500,sampleRate:0.5})

# 关闭Profiler模块
> db.setProfilingLevel(2)
  • 查看日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 查看操作日志
> db.system.profile.find().limit(5).sort({ts:-1}).pretty()
[
{
op: 'query', # 操作类型,比如查询,更新,删除等
ns: 'admin.system.profile', # 操作的集合
command: { # 操作的命令
find: 'system.profile', # 操作的集合
filter: {}, # 查询条件
lsid: { id: UUID('2285d6a5-b2df-4b46-b9d2-5e556b0a7c7d') }, # 会话id
'$clusterTime': { # 时间戳
clusterTime: Timestamp({ t: 1712471018, i: 1 }),
signature: {
hash: Binary.createFromBase64('8YEsN+XUWO6EkoHEegKkG49eWPA=', 0),
keyId: Long('7346062378896719877')
}
},
'$db': 'admin', # 数据库
'$readPreference': { mode: 'primaryPreferred' } # 读偏好
},
keysExamined: 0, # 扫描索引条目数,如果比nreturned大出很多,则说明查询效率不高。
docsExamined: 3, # 扫描文档条目数,如果比nreturned大出很多,则说明查询效率不高。
nBatches: 1, # 批处理数量
cursorExhausted: true, # 是否游标已耗尽
numYield: 0, # 操作数,大于0表示等待锁或者是磁盘I/O操作
nreturned: 3, # 返回的文档数量
queryHash: '8880B5AF', # 查询哈希值
planCacheKey: '8880B5AF',
queryFramework: 'classic',
locks: { # 锁占用的情况。
FeatureCompatibilityVersion: { acquireCount: { r: Long('1') } },
Global: { acquireCount: { r: Long('1') } }
},
flowControl: {},
readConcern: { level: 'local', provenance: 'implicitDefault' }, # 读关注
responseLength: 3414, # 响应数据大小(字节数),一次性查询太多的数据会影响性能,可以使用limit、batchSize进行一些限制。
protocol: 'op_msg', # 协议类型,op_msg是mongodb 4.0+的协议,op_query是mongodb 3.2及以前版本的协议。
millis: 0, # 命令执行的时长,单位是毫秒。
planSummary: 'COLLSCAN', # 查询计划的概要,如IXSCAN表示使用了索引扫描。
planningTimeMicros: 79,
execStats: { # 执行过程统计信息。
stage: 'COLLSCAN',
nReturned: 3,
executionTimeMillisEstimate: 0,
works: 4,
advanced: 3,
needTime: 0,
needYield: 0,
saveState: 0,
restoreState: 0,
isEOF: 1,
direction: 'forward',
docsExamined: 3
},
ts: ISODate('2024-04-07T06:23:56.054Z'), # 命令执行的时间点。
client: '127.0.0.1', # 客户端地址。
appName: 'mongosh 2.1.5', # 客户端名称。
allUsers: [ { user: 'user', db: 'admin' } ], # 所有用户信息。
user: 'user@admin' # 当前用户信息。
}
………………………………
]


# 查看执行时长最大的10条操作记录
> db.system.profile.find().limit(10).sort({millis:-1}).pretty()

# 查看某个集合中的update操作日志
> db.system.profile.find({op:"update",ns:"shop.user"})
  • system.profile是一个1MB的固定大小的集合,随着记录日志的增多,一些旧的记录会被滚动删除。

  • Profiler模块的设置是内存级的,重启服务器后会自动恢复默认状态。

db.currentOp()

  • Profiler模块所记录的日志都是已经发生的事情,db.currentOp()命令则与此相反,它可以用来查看数据库当前正在执行的一些操作。

  • db.currentOp()读取的是当前数据库的命令快照,该命令可以返回许多有用的信息,比如:

1
2
3
操作的运行时长,快速发现耗时漫长的低效扫描操作。
执行计划信息,用于判断是否命中了索引,或者存在锁冲突的情况。
操作ID、时间、客户端等信息,方便定位出产生慢操作的源头
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
> db.currentOp()
{
inprog: [ # 当前正在执行的操作
{
type: 'op', # 操作类型,可以是op、idleSession、idleCursor的一种,一般的操作信息以op表示。其为MongoDB 4.2版本新增功能
host: 'localhost:27041', # 操作所在的主机
desc: 'conn474', # 操作的描述信息
connectionId: 474, # 操作的连接ID
client: '127.0.0.1:58103', # 操作的客户端信息
appName: 'mongosh 2.1.5', # 操作的客户端应用信息
clientMetadata: { # 关于客户端的附加信息,可以包含驱动的版本。
application: { name: 'mongosh 2.1.5' },
driver: { name: 'nodejs|mongosh', version: '6.3.0|2.1.5' },
platform: 'Node.js v20.11.1, LE',
os: {
name: 'darwin',
architecture: 'x64',
version: '22.6.0',
type: 'Darwin'
}
},
active: true, # 操作是否活跃。如果是空闲状态则为false
currentOpTime: '2024-04-07T14:54:02.994+08:00', # 操作的开始时间。MongoDB 3.6版本新增功能
threaded: true,
opid: 236247, # opid:当前操作在数据库进程中的唯一编号,如果已经发现该操作正在导致数据库系统响应缓慢,则可以考虑将其“杀”死 : db.killOp(236247)
secs_running: Long('3'), # 操作持续时间,单位:秒
microsecs_running: Long('3362378'), # 操作持续时间,单位:微秒
op: 'command', # 标识操作类型的字符串,如 command, insert, query, update, delete, getMore, killCursors
ns: 'admin.$cmd', # 操作的命名空间,格式为 db.collection
redacted: false, # 是否已脱敏
command: { # 操作命令参数
hello: 1,
maxAwaitTimeMS: 10000,
topologyVersion: {
processId: ObjectId('6611f8cd59f7cfaa5c8cd7e4'),
counter: Long('18')
},
'$clusterTime': {
clusterTime: Timestamp({ t: 1712470998, i: 1 }),
signature: {
hash: Binary.createFromBase64('gvgo03Wqi1AuOVqnrlhzKIK2NAU=', 0),
keyId: Long('7346062378896719877')
}
},
'$db': 'admin'
},
numYields: 0,
locks: {}, # 当前操作持有锁的类型和模式。
waitingForLock: false, # 是否在等待锁
lockStats: {}, # 当前操作持有锁的统计。
waitingForFlowControl: false,
flowControlStats: {}
}
………………………………
]
}


# 查看等待锁的增加、删除、修改、查询操作
> db.currentOp({
waitingForLock:true,
$or:[
{op:{$in:["insert","update","remove"]}},
{"query.findandmodify":{$exists:true}}
]
})

# 查看执行时间超过1s的操作
> db.currentOp({
secs_running:{$gt:1}
})


# 查看test数据库中的操作
> db.currentOp({
ns:/test/
})