记录我常用的 mongodb 命令,以备后查。
快速启动服务
docker run -d -p 27017:27017 --name mongo mongo:8.2
$ docker exec -it mongo bash
$ mongosh --host 127.0.0.1 --port 27017
mongo shell
mongo cli
mongosh "mongodb+srv://mycluster.abcd1.mongodb.net/myFirstDatabase" --apiVersion 1 --username <username>
# 获取所有参数
> db.adminCommand( { getParameter : "*" } )
> db.adminCommand( "getCmdLineOpts" )
> db.adminCommand( { getParameter:1, syncdelay:1 } )
# 设置参数
mongod --setParameter <parameter>=<value>
mongos --setParameter <parameter>=<value>
db.adminCommand( { setParameter: 1, tcmallocReleaseRate: 5.0 } )
mongod --setParameter "tcmallocReleaseRate=5.0"
mongos --setParameter connPoolMaxShardedInUseConnsPerHost=100
# 获取当前连接数,等价于 exporter 的 mongodb_ss_logicalSessionRecordCache_activeSessionsCount
mongos> db.serverStatus().connections;
{ "current" : 256, "available" : 1024, "totalCreated" : 102400 }
逻辑会话(Logical Sessions)
- 服务端会话(server sessions)或者逻辑会话(logical sessions)是一种机制,用于在服务端维护和管理客户端的操作状态
- 应用程序使用客户端会话与服务端会话进行交互
- 服务端可以缓存的最大会话数默认为 1000000,当会话数大于该值时,将无法显式或者隐式创建会话
- PyMongo 支持 Python multiprocessing 模块(参考)
角色
dbAdmin 角色包含执行某些管理任务(与 schema 相关、索引、收集统计信息)的权限,该角色不包含用户和角色管理的权限
dbOwner 角色包含对数据所有的管理操作权限。即包含角色 readWrite、dbAdmin 和 userAdmin 的权限
userAdmin 角色包含对当前数据库创建和修改角色和用户的权限
clusterManager 角色包含对集群监控和管理操作的权限。拥有此角色的用户能够访问集群中的 config 数据库和 local 数据库
clusterMonitor 角色包含针对监控工具具有只读操作的权限。如工具 MongoDB Cloud Manager 和工具 Ops Manager
hostManager 角色包含针对数据库服务器的监控和管理操作权限
clusterAdmin 角色包含 MongoDB 集群管理最高的操作权限。该角色包含 clusterManager、clusterMonitor 和 hostManager 三个角色的所有权限,并且还拥有 dropDatabase 操作命令的权限
创建用户
# 创建 test 数据库,用户名为 admin/admin
use test
db.createUser(
{
user: "admin",
pwd: "admin",
roles: [{ role: "dbOwner", db: "test" }, { role: "readWrite", db: "test" }]
}
)
# 使用新用户登录
mongosh 127.0.0.1:27017 -u admin -p admin --authenticationDatabase test
# 查看权限
use test
db.runCommand({ connectionStatus: 1 })
# 查看数据库的用户
db.getUsers()
# 查看用户的权限
> use test
> db.getUser("admin", { showPrivileges: true })
# 添加权限
> use test
> db.grantRolesToUser(
"user",
[
{ role: "readWrite", db: "test" },
{ role: "dbabd", db: "test" }
]
)
# 更新权限
> use test
> db.updateUser(
"user",
{
customData: { info: "user for dbabd" },
roles: [
{ role: "dbabd", db: "admin" },
{ role: "read", db: "admin" }
]
}
)
主备切换
cfg = rs.conf()
cfg.members[0].priority = 30
cfg.members[1].priority = 20
cfg.members[2].priority = 10
cfg
rs.reconfig(cfg)
添加/删除节点
replica set 多服务器主从,添加,删除节点
利用 rs.reconfig 添加/删除节点
repmore:PRIMARY> config = {_id:"repmore",members:[{_id:0,host:'127.0.0.1:27017',priority :2},{_id:1,host:'127.0.0.1:27018',priority:1}]}; //添加节点
repmore:PRIMARY> rs.reconfig(config); //使配置生效
repmore:PRIMARY> rs.status(); //查看节点状态
节点添加成功。
注意:新增节点的 replSet 要和其他节点要一样
- 删除节点(删除节点前最好是先关闭需要删除的节点,之后通过命令 rs.remove 来删除)
repmore:PRIMARY> config = {_id:"repmore",members:[{_id:0,host:'127.0.0.1:27017',priority :2}]}; //删除节点
repmore:PRIMARY> rs.reconfig(config); //使配置生效
repmore:PRIMARY> rs.status(); //查看节点状态
利用 rs.add 和 rs.remove 来添加删除节点
repmore:PRIMARY> rs.add("127.0.0.1:27018"); //添加节点
repmore:PRIMARY> rs.remove("127.0.0.1:27018"); //删除节
注意:利用 rs.add 和 rs.remove 是不用 rs.reconfig 来使用配置生效的。
常用命令
db.meter.findOne( {counter_name: "ip.floating.incoming.bytes.rate"})
db.meter.count( {counter_name: "ip.floating.incoming.bytes.rate", recorded_at: {$lt: ISODate("2017-10-22T03:19:14.293Z")}})
mongoexport --host 127.0.0.1 --port 27017 -d ceilometer -c meter -q '{counter_name: "ip.floating.incoming.bytes.rate", recorded_at: {$lt: ISODate("2017-10-22T03:19:14.293Z")}}' --fields=resource_id,resource_metadata.fixed_ips.0.ip_address,counter_volume,counter_unit,recorded_at,resource_metadata.tenant_id --type=csv -o eip.csv
mongoexport --host 127.0.0.1 --port 27017 -d ceilometer -c meter -q '{counter_name: "ip.floating.incoming.bytes.rate", recorded_at: {$lt: ISODate("2017-07-02T00:00:00.000Z")}}' --fields=resource_id,resource_metadata.fixed_ips.0.ip_address,counter_volume,counter_unit,recorded_at,resource_metadata.tenant_id --type=csv -o eip.csv >> export_eip.log
mongoexport --host 127.0.0.1 --port 27017 -d ceilometer -c meter -q '{counter_name: "ip.floating.incoming.bytes.rate", recorded_at: {$lt: ISODate("2017-07-02T00:00:00.000Z")}}' --fields=resource_id,resource_metadata.fixed_ips.0.ip_address,counter_volume,counter_unit,recorded_at,resource_metadata.tenant_id --type=csv -o /mongodb-export/eip-20170622-0702.csv >> /mongodb-export/export_eip.log 2>&1
db.meter.find({counter_name: "memory", "resource_id" : "45103dbe-a77f-40dc-a1da-7813e8ce7092"}).limit(10).pretty()
db.meter.find({ resource_id: "a93c5387-a5ac-4ac3-9e01-37a309b04ee0"}).sort({"recorded_at":1}).limit(1)
db.resource.findOne({ metadata."instance_id" : "a93c5387-a5ac-4ac3-9e01-37a309b04ee0"}).limit(1)
db.meter.find({ resource_id: "a93c5387-a5ac-4ac3-9e01-37a309b04ee0"}).sort({"recorded_at":1}).limit(1)
db.resource.findOne({ "metadata.instance_id" : "a93c5387-a5ac-4ac3-9e01-37a309b04ee0"})
db.resource.find({ "metadata.instance_id" : "a93c5387-a5ac-4ac3-9e01-37a309b04ee0"}).sort({"last_sample_timestamp":1}).limit(1)
find
db.resource.find({ "metadata.instance_id" : "6d94e545-209a-4ea3-87a7-f5b237fd11c0"}).sort({"last_sample_timestamp":-1}).limit(1);
db.resource.find({ "metadata.instance_id" : "ce9416c9-2ff9-4a50-bcfa-82b7fb0a8110"}).sort({"last_sample_timestamp":-1}).limit(1);
db.resource.find({ "metadata.instance_id" : "6d94e545-209a-4ea3-87a7-f5b237fd11c0"}).sort({"last_sample_timestamp":-1}).limit(1);
db.resource.find({ "metadata.instance_id" : "6d94e545-209a-4ea3-87a7-f5b237fd11c0"}).sort({"last_sample_timestamp":-1}).limit(1);
update
db.getCollection('cc_ObjDes').update({'bk_obj_id':'listeners'},{$set:{'bk_classification_id':'load_balance'}})
mongodump -h 127.0.0.1 -p 27017 --db db_name --out cc_TopoGraphics-2018-06-22
mongorestore --host 127.0.0.1:27017 -udb_user -ppwd --db db_name cc_TopoGraphics.bson
oplog 调整
MongoDB 的 Oplog 是一个固定大小的集合(Capped Collection)。新数据写入时,如果空间满了,最旧的数据就会被覆盖。这就形成了一个“时间窗口”(Oplog Window)。
修改顺序:Secondary -> Primary
primary 切换 secondary 命令:
rs.stepDown()
涉及到 Replication Set 的服务:
27018 mongod-config-svr.service
27019 mongod-rs-1.service
27020 mongod-rs-2.service
27021 mongod-rs-3.service
修改一个 Secondary oplog 的步骤:
登录 Secondary 将其从集群剔除
mongo --host 10.0.0.1 --port 27018
use admin
db.shutdownServer()
实际执行
systemctl status mongod-config-svr.service
停止对应的服务
修改配置
注释掉:replication.replSetName
针对 shard (和 config replica set),注释:sharding.clusterRole
修改 net.port 为其他端口: 27022
启动
mongod --port 27022 --dbpath /data-01/mongo-conf-svr
mongod --port 27022 --dbpath /data-01/mongo-rs-1
mongod --port 27022 --dbpath /data-01/mongo-rs-2
mongod --port 27022 --dbpath /data-01/mongo-rs-3
备份 oplog
mongodump --db local --collection 'oplog.rs' --host 10.3.13.61 --port 27022 --out bak/mongo-conf-svr.oplog.rs
mongodump --db local --collection 'oplog.rs' --host 10.3.13.61 --port 27022 --out bak/mongo-rs-1.oplog.rs
mongodump --db local --collection 'oplog.rs' --host 10.3.13.61 --port 27022 --out bak/mongo-rs-2.oplog.rs
mongodump --db local --collection 'oplog.rs' --host 10.3.13.61 --port 27022 --out bak/mongo-rs-3.oplog.rs
重建 oplog
思路:确认 temp 表不存在,将 oplog.rs 旧数据放到 temp 表中,删除 oplog.rs 并新建,将 temp 表插入新的 oplog.rs ,删除 temp。
mongo --host 10.3.13.61 --port 27022
确认 temp 表不存在:
db = db.getSiblingDB('local')
Ensure that the temp temporary collection is empty by dropping the collection
show collections;
db.temp.drop()
将 oplog.rs 旧数据放到 temp 表中:
db.temp.save( db.oplog.rs.find( { }, { ts: 1, h: 1 } ).sort( {$natural : -1} ).limit(1).next() )
db.temp.find()
删除 oplog.rs:
db = db.getSiblingDB('local')
db.oplog.rs.drop()
并新建(100G):
db.runCommand( { create: "oplog.rs", capped: true, size: (40 * 1024 * 1024 * 1024) } )
db.runCommand( { create: "oplog.rs", capped: true, size: (100 * 1024 * 1024 * 1024) } )
将 temp 表插入新的 oplog.rs:
db.oplog.rs.save( db.temp.findOne() )
db.oplog.rs.find()
删除 temp:
db.temp.drop()
停止
db.shutdownServer()
修改配置文件
replication:
oplogSizeMB: 40960
replication:
oplogSizeMB: 102400
启动服务
systemctl start mongod-rs-1.service
参考:https://docs.mongodb.com/v3.2/core/replica-set-oplog/
mongostat
mongostat 是 MongoDB 自带的监控工具,其可以提供数据库节点或者整个集群当前的状态视图
mongostat --help
mongostat -h 127.0.0.1 --port 27017 -uroot -proot --authenticationDatabase=admin --discover -n 300 2
# 等价的命令
db.serverStatus()
参数说明:
-h:监听的主机
--port:监听的端口,默认 27017
-u、--user:登录用户名
-p、--password:登录密码
--authenticationDatabase:鉴权数据库
--discover:启用自动发现,可展示集群中所有分片节点的状态
-n 300 2:输出 300 次,每次间隔 2s
查询客户端命令
按 IP 统计已建立的 TCP 连接数量
ss -t state established | grep -v 'Local Address' | awk '{print $NF}' | cut -d: -f1 | sort | uniq -c | sort -nr
netstat -nt | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr
查看当前 activeSessions
# 查看当前所有正在运行的操作
db.currentOp()
# 查找运行超过 60 秒的操作
db.currentOp({ "secs_running": { "$gt": 60 } })
# 根据客户端版本 (clientMetadata.driver.version) 查询
db.currentOp({
"active": true, // 仅查询活跃操作
"clientMetadata.driver.version": "4.11.0"
})
# 查找所有 4.x 版本的驱动
db.currentOp({
"active": true,
"clientMetadata.driver.version": /^4\./ // 以 "4." 开头的版本
})
# 根据客户端 IP 地址/连接 (client) 查询
db.currentOp({
"active": true, // 仅查询活跃操作
"client": /^192\.168\.1\.100:/ // 使用正则表达式匹配 IP 开头
})
# 同时根据客户端版本和 IP 地址查询
db.currentOp({
"active": true,
"clientMetadata.driver.version": "4.11.0",
"client": /^192\.168\.1\.100:/
})
根据客户端 IP 统计和排序
use admin
db.aggregate([
// 1. 获取所有当前操作的文档流
{
$currentOp: {
"allUsers": true, // 包含所有用户的操作
"idleSessions": false // 排除空闲的会话,只看活跃/正在工作的操作
}
},
// 2. 筛选活跃的操作并处理 IP 地址
{
$match: {
"active": true,
"client": { "$exists": true } // 确保 client 字段存在 (即非内部操作)
}
},
// 3. 提取客户端 IP 地址
// client 字段格式为 "IP地址:端口号" (e.g., "192.168.1.100:54321")
{
$addFields: {
// 使用 $split 将 "IP:Port" 分割,取第一部分作为 IP
clientIP: { $arrayElemAt: [{ $split: ["$client", ":"] }, 0] }
}
},
// 4. 按 clientIP 分组并统计数量
{
$group: {
_id: "$clientIP",
operationCount: { $sum: 1 }
}
},
// 5. 按数量 (operationCount) 倒序排列
{
$sort: {
operationCount: -1
}
}
])
根据客户端版本统计和排序
use admin
db.aggregate([
// 1. 获取所有当前操作的文档流
{
$currentOp: {
"allUsers": true, // 包含所有用户的操作
"idleSessions": false // 排除空闲的会话
}
},
// 2. 筛选出具有客户端元数据(即客户端驱动程序信息)的操作
{
$match: {
"active": true, // 仅统计活跃操作
"clientMetadata.driver.version": { "$exists": true } // 确保客户端版本信息存在
}
},
// 3. 按客户端驱动版本进行分组和统计数量
{
$group: {
_id: "$clientMetadata.driver.version",
versionCount: { $sum: 1 }
}
},
// 4. 按数量 (versionCount) 倒序排列
{
$sort: {
versionCount: -1
}
}
])
Client 软件
F&Q
mongodb ReadConcernMajorityNotAvailableYet: Read concern majority reads are currently not possible.
容器间网络不通
into the cache because the number of active sessions is too hight
session 没有管理好,导致泄露,可参考:
Resume of change stream was not possible, as the resume point may no longer be in the oplog
应用程序试图监听(Watch)数据库变更,并尝试从一个 旧的时间点(Resume Token)恢复监听,但是这个时间点的数据已经在 MongoDB 的 Oplog(操作日志)中被覆盖并清理掉了
在 Primary 节点执行:
rs.printReplicationInfo()
重点关注输出中的:
- log length start to end: 当前 Oplog 能保存多久的数据(例如:24.5 hours)
- used MB: Oplog 的总大小
如果在 MongoDB 4.0+,可以在线调整 Oplog 大小(无需重启)。例如,调整为 50GB:
// 在 Primary 节点执行,单位是 MB
db.adminCommand({replSetResizeOplog: 1, size: 51200})