偏离的数据

某个部署在圣保罗🇧🇷的地域的服务 svc-a,需要调用部署在 加拿大🇨🇦 的一个子系统 svc-b。按照物理直线距离来说,渥太华和圣保罗之间有 8000 公里,光速跑个来回也得要 53ms。但是,在业务部署上线后,监控面板显示 P99 只有 10ms。

指标面板

问题排查

这明显是是反直觉了。进入业务部署容器,使用 curl 的 -write-out 参数打印请求详细流水,可以看到如下结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
root@svc-a-5fd47c6c68-l7cbj:/# curl -w "@./curl.fmt" svc-b:port
....

time_namelookup:  0.000025s
        time_connect:  0.135633s
     time_appconnect:  0.000000s
    time_pretransfer:  0.135666s
       time_redirect:  0.000000s
  time_starttransfer:  0.271480s
                     ----------
          time_total:  0.271512s
root@svc-a-5fd47c6c68-l7cbj:/#

curl write out 格式文件 curl.fmt 内容如下:

1
2
3
4
5
6
7
8
time_namelookup:  %{time_namelookup}s\n
        time_connect:  %{time_connect}s\n
     time_appconnect:  %{time_appconnect}s\n
    time_pretransfer:  %{time_pretransfer}s\n
       time_redirect:  %{time_redirect}s\n
  time_starttransfer:  %{time_starttransfer}s\n
                     ----------\n
          time_total:  %{time_total}s\n

从请求流水看出,跨洲际的服务调用延迟确实很高,符合认知和物理极限。可以肯定的是指标埋点代码出了问题。

结论

检查对应的代码,发现该指标使用了 prometheus.DefBuckets 作为 prometheus.Histogram 的默认 Buckets 参数,这个参数的取值范围是 []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}。而埋点的代码这是格式化 time.Duration 成了 Milliseconds。 结果,可想而知。P99 能够看到的最大值也就是 10ms 了。最后,通过修改代码发布上线解决。