外卖服务稳定性热力图:找不到现成方案,打算用 D3 自己画

2 分钟阅读
·

最近外卖那边服务出过几次问题,排查起来很费劲:一个下单接口超时,值班同学得先看是不是自己服务的问题,再一层层查是不是下游某个依赖顶不住了。现在看这些指标全靠翻监控平台里一条条的曲线,服务多起来之后没人能一眼看出问题出在调用链的哪一环。

组里提了个想法:做一个大盘,把服务之间的调用关系画成一张图,谁的 QPS 高、谁调用谁、调用量多大,全在一张图上看完。具体要求是这样:

  • 每个服务是一个节点,颜色按当前 QPS 高低变化,QPS 越高越红
  • 服务之间的调用画成连线,线的颜色和粗细按调用 QPS 变化,调用越多线越红越粗
  • 连线上要有沿调用方向移动的小白点,一眼能看出谁调用了谁,不是一条看不出方向的线
  • 整体是一张有向图,节点位置不需要人工摆,能自动排布就行

这四条里最后一条最麻烦,前三条本质上是给数值找一个视觉映射,第四条要求的是一个能自动布局的有向拓扑图,还要在上面跑动画。

找了一圈,没有直接能用的

先看了公司里现成的图表方案,之前云盘用 echarts 做过点击热力图,echarts 的图表类型挺全,但热力图那一档是给地图或者矩阵用的,不是给拓扑图用的,它没有”节点+连线+自动布局”这种图。

又找了几个开源的图表库,大多分两类。一类是柱状图、饼图、折线图这些”数据图表”库,根本没有拓扑图的概念。另一类是流程图/组织架构图工具,节点和连线有了,但布局基本是手动摆或者树形层级摆,不支持像力学模拟那样自动把节点铺开,更不用说线上跑动画点这种效果。

看到几个提到”力导向图”(force-directed graph)的例子,画的效果跟我们要的很像,几个都是基于 D3.js 做的。查了一下 D3,官网例子里正好有一个多对多关系的力导向布局 demo,节点会自动散开,连线会自动排布,不会挤在一起。这个方向是对的,但这些 demo 都是静态的,没有方向箭头,也没有沿线跑动的点,颜色映射也只是演示用的固定几档,QPS 这种连续数值要自己接比例尺进去。

调研的结论是:没有现成的东西能直接拿来用,D3 提供的是画图的底层能力(数据绑定、坐标计算、图形生成),具体这张热力图长什么样,节点颜色怎么算、方向动画怎么做,得自己在 D3 上面搭一层。

之前没系统学过 D3,先补课

D3 之前只是零散用过,知道 d3.select 能选元素,没有认真学过它的数据绑定模式、比例尺和布局算法这几块。既然要拿它写一整个大盘,不如趁这个机会把 D3 系统学一遍,边学边记笔记,学完直接把代码搬进项目里,省得后面缺哪块再回去现查。

学习顺序是按大盘需要的能力反推的:

  1. 选择集与数据绑定:D3 最基础的部分,d3.select/selectAll 怎么和 jQuery 的”选中元素改属性”区分开,数据条数变化时增删节点的 enter/update/exit 模式是怎么回事。这是后面所有内容的地基,节点和连线本质上都是数据绑定出来的 DOM 元素。
  2. 比例尺与 SVG 图形基础d3.scale.linear() 怎么把 QPS 的数值范围映射到像素或者颜色,d3.scale.ordinal() 怎么给分类数据分配位置,顺带确认一下 SVG 的坐标系和常见的画反坑点。
  3. 力导向布局与方向动画d3.layout.force() 具体怎么配置,节点位置是怎么”模拟”出来的而不是算出来的,箭头怎么用 SVG 的 <marker> 画,沿线移动的小白点怎么用定时器手写插值实现。

这三块笔记我分别整理成了三篇文章,放在这篇后面,感兴趣的话可以按顺序看:

大盘大致会长什么样

三篇笔记学完之后,手上已经有能拼起来用的代码片段:数据怎么绑到节点和连线上、QPS 怎么映射成颜色和半径、调用关系怎么用力导向布局摆开、方向怎么用箭头和跑动的点表示。画了张示意图,是这几块拼在一起之后大概的效果:

外卖服务调用拓扑热力图示意

图里”订单核心”这个节点最红,因为它的 QPS 最高,也是被调用最多的一个;从”下单”到”订单核心”这条线又粗又红,代表这条调用链路走的量最大,线上那几个白点就是顺着这个方向跑的。用户、对账这些节点调用量小,颜色偏蓝,线也细,一眼能看出这张图上哪条链路是真正的压力所在,不用再去翻监控曲线一条条对。

接下来要做的事

三篇 D3 笔记里写的都是孤立的小例子,节点数量、数据格式都是我自己编的,接下来要把它们拼到一起,还有几件事没定下来:

  • 数据从哪来:QPS 和调用关系现在都能从监控平台查到,但监控平台给的是原始指标,得自己写一层转换,把它整理成 nodes/links 这种 D3 布局能直接吃的数组格式,这块转换逻辑还没写。
  • 刷新频率怎么定:监控数据不是毫秒级的,大盘要多久拉一次新数据,拉到新数据之后是整个重新跑一次力导向布局,还是只更新颜色和线宽、节点位置不动,这两种做法给人的感觉完全不同,得实际跑一下再定。
  • 节点数量上来之后会不会卡:现在笔记里试的都是十几个节点,外卖真实的服务数量比这个多不少,tick 回调里每帧都要重算所有节点和连线的坐标,节点一多会不会跟不上,这个只能拿真实数据量实测。

这几块等接口和数据都理清楚了,再写一篇记录大盘落地之后的实际效果和踩的坑。


241 字 · 32 段落
xi ming

Written by xi ming You should follow him on Github

评论与讨论