事务生命周期需手动注入span,因mongodb驱动不自动捕获事务事件;currentop()不携带trace_id,需日志中关联lsid与txnnumber;分片集群下需mongos/shard多层埋点;提交延迟高因span未覆盖后台落盘阶段。

事务生命周期无法被链路追踪自动捕获,必须手动注入 span
OpenTracing / OpenTelemetry 的标准 SDK 不会自动识别 MongoDB 事务的开始、提交或回滚事件。驱动层只暴露 session.startTransaction()、commitTransaction()、abortTransaction() 这些同步调用,但不会自动创建 span 或关联 parent context。若不做干预,整个事务块在链路图中只会显示为一个扁平的数据库调用,看不到“事务内操作”与“事务状态跃迁”。
实操建议:
- 在调用
session.startTransaction()前,显式创建一个 type 为"mongo.transaction"的 span,并把当前 trace context 注入 session 标签(如session.options.tags = { trace_id: span.context().traceId };) - 事务内每个 CRUD 操作(如
collection.updateOne())应作为 child span 追加,且设置span.setAttribute("mongo.txn_number", session.transaction.txnNumber) - 在
commitTransaction()或abortTransaction()后,手动结束该事务 span,并标注span.setStatus({ code: SpanStatusCode.OK })或.setError() - 避免在异步重试逻辑(如
withTransaction()自动重试)中重复创建 span,需用txnNumber去重判断
为什么 currentOp() 查不到事务 span 关联的会话?
db.currentOp() 返回的是服务端运行时视图,它不携带任何 tracing header 或 span ID。即使你在应用层给 session 打了 trace_id 标签,MongoDB 本身不会将其写入 currentOp 输出字段。你看到的 lsid 和 txnNumber 是内部标识,和链路追踪的 trace_id 完全无关。
实操建议:
- 不要试图从
db.currentOp()反查 span;应在应用日志中同时输出trace_id+lsid+txnNumber,建立人工映射 - 在日志结构化字段中固定包含
"mongo_txn": true和"lsid": session.id,便于 ELK 或 Loki 聚合分析 - 若使用 OpenTelemetry Collector,可配置 processor 将日志中的
lsid提取为 attribute,再与 traces 关联(需日志与 trace 共享trace_id)
分片集群下事务 span 显示不完整,常见原因有哪些?
跨分片事务由 mongos 协调多个 shard 并行执行,每个 shard 上的操作是独立的 oplog 写入。OpenTelemetry 默认只在发起端(即应用连接的 mongos)生成一个 span,无法自动展开下游 shard 的子操作,导致链路“断层”。
实操建议:
- 在 mongos 层部署 OpenTelemetry instrumentation 代理(如 otel-collector sidecar),捕获其转发到各 shard 的请求,并打上
shard_id和coordination_role: "router"标签 - 对每个 shard 的 mongod 实例启用
net.snmp或自定义 metrics endpoint,导出transaction.prepare_time_ms、transaction.commit_wait_ms等指标,与 trace 时间轴对齐 - 禁用
readConcern: "snapshot"的自动 fallback 行为——如果某个 shard 不支持 snapshot,事务会降级为非 ACID 模式,但 span 仍显示 success,造成误导 - 检查
maxTransactionLockRequestTimeoutMillis是否被触发:超时后 mongos 会静默 abort,此时 span 应标记 error,但默认 SDK 不感知该事件,需监听 mongos 日志关键词"transaction timeout"
事务提交延迟高,但链路追踪显示 DB 调用耗时正常?
这是最典型的监控盲区:OpenTelemetry 测量的是 commitTransaction() 方法的执行时间,而该方法返回成功仅表示协调请求已发出,并不保证所有 shard 已真正落盘。真实延迟可能发生在 oplog 复制、多数派确认、WiredTiger checkpoint 等后台阶段,这些完全不在 span 覆盖范围内。
实操建议:
- 在
commitTransaction()后立即调用db.runCommand({ "getLastError": 1, "w": "majority", "wtimeout": 5000 }),并把这个命令包进同一个 span 的子 span 中 - 将
replSetGetStatus().members[n].lastAppliedWallTime与当前时间差作为 “post-commit lag”,上报为 metric(不是 span),并与 trace_id 关联 - 避免依赖单个 span duration 判断事务性能;必须结合
globalLock.currentQueue.writers、oplog.rs延迟、wt.cache.tracked_dirty_bytes三者交叉验证
db.currentOp()、serverStatus 和 oplog 分析的组合使用。











