云数据库 MongoDB 版提供了Opcounters和Repl Opcounters相关的指标,本文将为您介绍Opcounters指标和Repl Opcounters指标以及相关的常见问题。
Opcounters指标和Repl Opcounters指标支持的实例类型,请参见监控项说明。
Opcounters指标
云数据库 MongoDB 版的监控信息和性能趋势功能中均提供了Opcounters指标的相关参数:
Opcounters指标由insert、query、update、delete、getmore和command几个操作类型组成,该指标展示了mongod或mongos自上次启动以来运行的不同数据库操作类型的数量统计。
指标 | 单位 | 说明 |
insert | 个/每秒 | MongoDB每秒插入操作的数量。 |
query | 个/每秒 | MongoDB每秒查询操作的数量。 |
update | 个/每秒 | MongoDB每秒更新操作的数量。 |
delete | 个/每秒 | MongoDB每秒删除操作的数量。 |
getmore | 个/每秒 | MongoDB每秒获取更多操作的数量。 |
command | 个/每秒 | MongoDB每秒命令操作的数量。 |
Opcounters除了会记录客户端侧发起的操作外,同时也会记录一些数据库内部的操作。
指标 | 说明 |
insert |
|
query |
|
update | 与 |
delete |
|
getmore | 主从同步时,数据库对 |
command |
更多命令请参见Command。 |
Repl Opcounters指标
云数据库 MongoDB 版的监控信息中提供了Repl Opcounters指标的相关参数,通常情况下,你仅需要关注从节点上的Repl Opcounters指标。
您也可以在从节点上查看Opcounters指标,该指标主要由以下两个部分组成:
在从节点上执行的客户端查询操作(通过指定相应的readPreference)。
在local库执行的所有写入操作(通过主从同步获得的操作)。
与Opcounters指标类似,Repl Opcounters指标也由insert、query、update、delete、getMore和Command几个操作类型组成,该指标展示了mongod自上次启动以来按不同类型汇总的数据库复制操作。
指标 | 单位 | 说明 |
insert | 个/每秒 | MongoDB每秒插入操作的数量。 |
query | 个/每秒 | MongoDB每秒查询操作的数量。 |
update | 个/每秒 | MongoDB每秒更新操作的数量。 |
delete | 个/每秒 | MongoDB每秒删除操作的数量。 |
getmore | 个/每秒 | MongoDB每秒获取更多操作的数量。 |
command | 个/每秒 | MongoDB每秒命令操作的数量。 |
Repl Opcounters指标会计算应用在从节点上的所有写操作,除了Opcounters指标中提及的操作外,还包括以下操作:
会话(session)刷新触发的insert和update操作。
TTL索引带来的删除操作。
删除孤立文档触发的删除操作(通常延迟发生在Chunk迁移后)。
写入系统集合的相关操作,例如可重试写入(Retryable Writes)会有对
config.transactions
的写入操作。
由于MongoDB在主从复制过程中序列化操作的方式不同,因此,从节点上的Repl Opcounters指标值与主节点上的Opcounters指标值不一样也是符合预期的。
常见问题
为什么从节点的Repl Opcounters指标值比主节点的Opcounters指标值高很多?
影响多个文档的操作(如批量插入、多次更新或多次删除操作)会被解释为单个操作。当影响多个文档的操作复制到从节点时,由于主从复制是基于每个文档进行的,从节点上的相关Repl Opcounters指标值可能大于在主节点上观察到的Opcounters指标值。
示例如下:
更新前检查Opcounters计数器。
主节点的Opcounters计数器数量显示为13。
> db.serverStatus().opcounters.update NumberLong(13)
从节点的Repl Opcounters计数器数量显示为11。
> db.serverStatus().opcountersRepl.update NumberLong(11)
主节点执行一次批量更新。通过返回的
modifiedCount
字段可以看到本次批量更新修改了4条文档。> db.coll.updateMany({x:2},{$set:{x:3}}) { "acknowledged" : true, "matchedCount" : 4, "modifiedCount" : 4 }
更新后再次检查Opcounters计数器。
主节点的Opcounters计数器数量显示为14。
> db.serverStatus().opcounters.update NumberLong(14)
从节点的Repl Opcounters计数器数量显示为15。
> db.serverStatus().opcountersRepl.update NumberLong(15)
为什么执行的都是update操作,但从节点的Repl Opcounters指标中却显示了不少insert类操作?
可能是因为您的update操作指定了{upsert:true}
选项,当期望update
的文档不存在时,会转为insert
操作执行。当oplog里记录的是insert
操作时,通过主从复制同步到从节点的也将是insert
操作,因此Repl Opcounters里记录的也就是相应insert
操作。
示例如下:
更新前检查Opcounters计数器。
主节点的Opcounters计数器中,update数量显示为33;insert数量显示为1516。
> db.serverStatus().opcounters { "insert" : NumberLong(1516), "query" : NumberLong(70), "update" : NumberLong(33), "delete" : NumberLong(1043), "getmore" : NumberLong(2662), "command" : NumberLong(4000) }
从节点的Repl Opcounters计数器,update数量显示为24;insert数量显示为1539。
> db.serverStatus().opcountersRepl { "insert" : NumberLong(1539), "query" : NumberLong(0), "update" : NumberLong(24), "delete" : NumberLong(6), "getmore" : NumberLong(0), "command" : NumberLong(26) }
在主节点上执行带
{upsert:true}
选项的update操作,通过返回的upsertedId
字段可以看到成功插入了1条文档。> db.coll.updateOne({x:"a"}, {$set:{x:"b"}}, {upsert:true}) { "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0, "upsertedId" : ObjectId("64bf72b829907f52b4b363ea") }
更新后再次检查Opcounters计数器。
主节点的Opcounters计数器中,update数量显示为34;insert数量依旧显示为1516。
> db.serverStatus().opcounters { "insert" : NumberLong(1516), "query" : NumberLong(70), "update" : NumberLong(34), // 注意这里计数器的变化 "delete" : NumberLong(1043), "getmore" : NumberLong(2706), "command" : NumberLong(4286) }
从节点的Repl Opcounters计数器,update数量依旧显示为24;insert数量显示为1540。
> db.serverStatus().opcountersRepl { "insert" : NumberLong(1540), // 注意这里计数器的变化 "query" : NumberLong(0), "update" : NumberLong(24), "delete" : NumberLong(6), "getmore" : NumberLong(0), "command" : NumberLong(26) }
为什么主节点上的update操作那么多,但从节点复制的update操作那么少?
可能是因为您的业务逻辑里包含了重复的update
操作。重复的update
操作由于并没有发生实际的改动,并不会被复制到从节点上。因此从节点上看到的update
操作数量会更少。
示例如下:
更新前检查Opcounters计数器。
主节点的Opcounters计数器中update数量显示为34。
> db.serverStatus().opcounters { "insert" : NumberLong(1516), "query" : NumberLong(70), "update" : NumberLong(34), "delete" : NumberLong(1043), "getmore" : NumberLong(2760), "command" : NumberLong(4609) }
从节点的Repl Opcounters计数器中update数量显示为24。
> db.serverStatus().opcountersRepl { "insert" : NumberLong(1540), "query" : NumberLong(0), "update" : NumberLong(24), "delete" : NumberLong(6), "getmore" : NumberLong(0), "command" : NumberLong(26) }
在主节点上执行update操作,通过返回信息可以看到并未发生实际修改。
> db.coll.updateMany({x:"ab"},{$set:{x:"cd"}}) { "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0 }
更新后再次检查Opcounters计数器。
主节点的Opcounters计数器中update数量显示为35。
> db.serverStatus().opcounters { "insert" : NumberLong(1516), "query" : NumberLong(70), "update" : NumberLong(35), // 注意这里计数器的变化 "delete" : NumberLong(1043), "getmore" : NumberLong(2778), "command" : NumberLong(4729) }
从节点的Repl Opcounters计数器中update数量依旧显示为24。
> db.serverStatus().opcountersRepl { "insert" : NumberLong(1540), "query" : NumberLong(0), "update" : NumberLong(24), "delete" : NumberLong(6), "getmore" : NumberLong(0), "command" : NumberLong(26) }
为什么没有使用数据库,但监控上依然能看到一些Opcounters各种类型的操作?
无业务访问情况下,监控上呈现的少量操作主要由以下几部分组成:
为了维持MongoDB数据库正常运转的一些内部基本操作,比如副本集心跳、主从同步、会话刷新等。
云数据库 MongoDB 版数据库周边管控组件的一些日常操作,比如探活、监控、监听等。
为什么Opcounters里的指标和实例oplog里按op聚合得到的结果不一样?
在oplog中,您可以通过op
字段来区分具体的操作类型。常见的取值范围如下:
kCommand: "c"
kInsert: "i"
kUpdate: "u"
kDelete: "d"
kNoop: "n"
事务都是op:c
的操作类型,仅在内部的o.applyOps
中存储了事务内包含的所有insert
、update
、delete
操作。如果您仅按oplog的op
字段来进行聚合分析的话,在有事务的场景中,得出的结果会和Opcounters中显示的结果不一致。更多关于oplog格式的介绍,请参见oplog各字段的解析。
如您期望统计事务内的具体操作类型数量,可以通过mongo shell客户端连接MongoDB后执行如下命令。
use local
db.oplog.rs.aggregate([{$match:{"op":"c","ts":{"$gte": Timestamp(1733849400,0)},"o.applyOps":{$exists:true},"o.applyOps.0.op":"u"}},{$count:"count"}])
参数说明如下:
Timestamp(1733849400,0)
:一个查询oplog格式中的ts时间戳的下边界,您需要替换为期望查询的时间。该时间戳您可以从local.oplog.rs
里读取或直接使用UNIX时间戳。"o.applyOps.0.op":"u"
:事务oplog中的第一条操作为update,您可以替换为其他操作类型,例如第一条操作为insert时,您可以替换为"o.applyOps.0.op":"i"
。{$count:"count"}
:仅统计符合要求的oplog条数,您可以使用聚合语句的其他操作符来进行其他分析。
如果您需要查看事务相关的监控指标,可以在云数据库 MongoDB 版控制台的监控信息中查看事务操作数指标,具体指标,请参见监控项说明。
示例如下:
更新前检查Opcounters计数器。
> db.serverStatus().opcounters { "insert" : NumberLong(4), "query" : NumberLong(6723), "update" : NumberLong(110489), "delete" : NumberLong(3065), "getmore" : NumberLong(222670), "command" : NumberLong(1917525) }
在主节点上执行一个仅事务内的写操作。
// 开启一个会话 session = db.getMongo().startSession( { readPreference: { mode: "primary" } } ); coll1 = session.getDatabase("mydb1").foo; coll2 = session.getDatabase("mydb2").bar; // 开启一个事务 session.startTransaction( { readConcern: { level: "local" }, writeConcern: { w: "majority" } } ); // 在事务中执行2个insert操作 try { coll1.insertOne( { abc: 1 } ); coll2.insertOne( { xyz: 999 } ); } catch (error) { // 遇到问题时中止事务 session.abortTransaction(); throw error; } // 提交事务 session.commitTransaction(); session.endSession();
更新后再次检查Opcounters计数器。Opcounters计数器中insert数量由4变成了6。
> db.serverStatus().opcounters { "insert" : NumberLong(6), // 注意这里计数器的变化 "query" : NumberLong(6728), "update" : NumberLong(110532), "delete" : NumberLong(3067), "getmore" : NumberLong(222823), "command" : NumberLong(1918887) }