服务依赖图是怎么从 span 里算出来的?数据库和外部服务怎么出现在图上?丢了一部分 span 图会变成什么样?采样之后图上的请求量还能直接用吗?这篇用 OpenTelemetry Collector 的 servicegraph 连接器和已知调用次数的模拟流量逐项量出来。
边(客户端 → 服务端) | 真实调用次数 | 我从父子关系算的 | servicegraph 的 request_total | servicegraph 的 connection_type -------------------+--------+----------+------------------------------+------------------------------- frontend → orders | 2000 | 2000 | 2000 | unset frontend → users | 2000 | 2000 | 2000 | unset orders → inventory | 2000 | 2000 | 2000 | unset orders → notifier | 628 | 628 | 628 | messaging_system orders → orders-db | 2000 | 2000 | 2000 | database orders → payments | 1218 | 1218 | 1218 | unset payments → bank | 1218 | 1218 | 1218 | virtual_node user → frontend | 0 | 0 | 2000 | virtual_node servicegraph 其他计数:无 服务图的边由配对的两个 span 得出:客户端(或生产者)span 和它的子 span(服务端 / 消费者 span)属于不同的服务,配成 “client → server” 的一次请求;数据库、外部服务这类没有对端 span 的调用,靠客户端 span 上的 peer 属性(peer.service、db.name、db.system、messaging.system)变成“虚拟节点”(上表里 orders-db 的 connection_type 是 database,bank 是 virtual_node,notifier 是 messaging_system)。表里还多了一条真实调用次数是 0 的 user → frontend,共 2000 次:frontend 的根 span 是服务端 span、没有客户端一侧的父 span,连接器把它记成来自虚拟节点 user 的请求
客户端或生产者 span 与它的子 span(服务端或消费者 span)属于不同服务,就配成一条边;没有对端的调用靠 peer 属性变成虚拟节点。
边 | 真实调用次数 | servicegraph 的 request_total | 相对真实值的差 -------------------+--------+------------------------------+-------- frontend → orders | 2000 | 1589 | -21% frontend → unknown | 0 | 411 | - frontend → users | 2000 | 2000 | +0% orders → inventory | 2000 | 2000 | +0% orders → notifier | 628 | 628 | +0% orders → orders-db | 2000 | 2000 | +0% orders → payments | 1218 | 949 | -22% orders → unknown | 0 | 269 | - payments → bank | 1218 | 1218 | +0% user → frontend | 0 | 2000 | - servicegraph 其他计数:无。丢了服务端 span 的那些客户端 span 在 store.ttl(2 s)到期后找不到配对,没有被忽略,而是被记成指向虚拟节点 unknown 的边:frontend → orders 比真实值少 411 次,frontend → unknown 有 411 次;orders → payments 少 269 次,orders → unknown 有 269 次(少的和 unknown 的数量一致,总数守恒)。所以丢 span 的后果是图上出现 unknown 节点,而不是边上的数字消失
丢了服务端 span 的客户端 span 到期后变成指向 unknown 的边,总数守恒。
边 | 真实调用次数 | servicegraph 的 request_total | 占真实调用次数的比例
-------------------+--------+------------------------------+-----------
frontend → orders | 2000 | 206 | 10.3%
frontend → users | 2000 | 206 | 10.3%
orders → inventory | 2000 | 206 | 10.3%
orders → notifier | 628 | 70 | 11.1%
orders → orders-db | 2000 | 206 | 10.3%
orders → payments | 1218 | 131 | 10.8%
payments → bank | 1218 | 131 | 10.8%
user → frontend | 0 | 206 | -
服务图的计数来自被采样的 span,采样率 10% 时每条边的计数只有真实调用的十分之一左右;所以请求速率不能直接用采样后的服务图计数,要么按采样率放大,要么用在采样之前统计的指标(例如 SDK 的指标或 Collector 上游的 spanmetrics)
ERRORS {}服务图的计数来自被采样的 span,不能直接当请求量用。