在 Jaeger UI 中如何定位一次慢查询的 Map 阶段耗时?

解读

面试官把“CouchDB 视图慢”与“Jaeger 分布式追踪”两个场景强行揉在一起,重点考察两点:

  1. 你是否真的理解 CouchDB Map 阶段发生在哪一段代码、哪一段进程;
  2. 你是否能把 Jaeger 的 span 语义与 CouchDB 内部耗时对应起来,而不是泛泛而谈“看耗时长的 span”。
    国内生产环境常见套路是:CouchDB 以 集群+反向代理 方式部署,前面挂 Nginx/OpenResty,旁边独立跑 Jaeger Collector;视图请求走 /_view/_design/ 路径,真正触发 Map 阶段的是 couch_index_updater 进程。
    因此,定位思路必须围绕“给索引更新打 span → 在 Jaeger UI 用 tag 过滤 → 下钻到 Map 函数耗时”三步展开,缺一步都会被认为是“没在生产排过障”。

知识点

  1. CouchDB 视图更新链路:
    HTTP → couch_mrview_http → couch_index_updater → JavaScript Map 函数 → 写 .view 文件。
  2. Jaeger 的 span 命名规范:
    国内落地时,团队一般会自定义 span.kind=server 的入口 span 叫 db.couchdb.view.query,内部再嵌套 span.kind=internalcouch_index_updater.map 子 span。
  3. 关键 tag:
    db.namedb.couchdb.design_documentdb.couchdb.view_namedb.couchdb.map_phase=true
  4. Jaeger UI 过滤语法:
    支持 key=value 精确匹配与 minDuration 阈值过滤,可把“>500 ms”的 Map 阶段一把抓出来。
  5. 国内排障经验:
    如果 Map 阶段无独立 span,99% 是因为 couch_index_updater 没插桩;此时需要改 couchdb.trace.module 配置并重启节点,否则只能在“大 span”里干瞪眼。

答案

  1. 在 Jaeger UI 顶部 Search 栏里,Service 选 CouchDB 对应的 serviceName(通常是 couchdbdb-couch)。
  2. Tags 输入框键入 db.couchdb.map_phase=true and db.couchdb.view_name=your_view,回车。
  3. Min Duration500ms,点“Find Traces”。
  4. 结果列表里找到耗时最长的 trace,点进去后,左侧时间轴会展开一条叫 couch_index_updater.map内部 span;该 span 的 Duration 就是一次慢查询的 Map 阶段耗时。
  5. 若未发现该 span,说明 CouchDB 未启用 细粒度追踪,需在每个节点 local.ini 追加:
    [tracing]
    enabled = true
    granularity = map_reduce
    
    重启节点后重试即可。

拓展思考

  1. 如果 Map 阶段耗时正常,但 Reduce 阶段突然飙高,如何在 Jaeger 区分?
    答:在代码层给 Reduce 函数再埋一个 span.name=couch_index_updater.reduce 的 internal span,并通过 db.couchdb.reduce_phase=true 过滤,即可与 Map 阶段并排对比。
  2. 国内云厂商托管版 CouchDB 往往屏蔽了 /_node/_local/_config,无法改 ini,怎么办?
    答:可退而求其次,在 Nginx 层用 OpenTracing C 模块,给 /_view 接口增加 x-trace-map-hint 头,把设计文档与视图名写进 baggage,再在 Jaeger 里用 baggage 字段过滤,虽不能精确到 Map 函数,也能把慢查询缩小到单视图级别。