作者:来自 Elastic Jenny Pavlova

每个服务节点都会显示告警、 SLO 和异常健康状态,因此你可以仅筛选违反阈值的服务,并将结果嵌入到任何 Kibana 仪表板中,同时支持在整个拓扑中使用完整的键盘导航。
我们基于 React Flow 重构了 Elastic Observability 中的 Kibana APM 服务地图。在拥有 500 个服务时,渲染时间仅为 64ms,相比之前基于 Cytoscape.js 的实现快约 6 倍,同时 JavaScript 体积减少了 60%( 69 KiB 对比 172 KiB )。服务节点现在会显示告警、 SL 和异常健康状态,因此你可以仅筛选违反阈值的服务,并将结果嵌入到任何 Kibana 仪表板中,同时支持在整个拓扑中使用完整的键盘导航。从告警到定位失败的依赖项仅需四次点击: Elastic APM 的嵌入式服务地图更深入地介绍了告警面板、 SLO 徽章以及仪表板嵌入功能。
下面分别是这次重构之前和之后的服务地图:
以前:

现在:

为什么 APM 服务地图从 Cytoscape.js 图可视化迁移到 React Flow
迁移带来的收益非常直观: React Flow 将节点渲染为真正的 React 组件,而不是通过 Canvas 绘制循环,因此即使面对大型拓扑,平移和缩放依然保持流畅;我们的 Elastic UI ( EUI )节点和徽章能够原生渲染(不再需要每次更新时重新渲染整个 Canvas);此外,基于 DOM 的渲染使节点能够天然被屏幕阅读器识别,而基于 Canvas 的渲染则无法做到这一点。
它也更加轻量:图形库从 172.4 KiB( cytoscape.js )减少到 69 KiB( @xyflow/react ),减少了约 103 KiB 的 JavaScript 下载体积,#248470 。
使用 React Flow 后, APM 服务地图快了多少?
在决定将 APM 服务地图从 Cytoscape.js 迁移到 React Flow 之前,我们对两个图形库在 100、200 和 500 个服务规模下进行了基准测试(使用合成链式拓扑,通过 Lighthouse 和组件级耗时进行测量,并对多次运行结果取平均值, #248470 ):
| 服务数量 | Cytoscape.js 渲染 | React Flow 渲染 | 提升幅度 |
|---|---|---|---|
| 100 | 61.6 ms | 15.0 ms | 约 76% |
| 200 | 102.5 ms | 28.1 ms | 约 73% |
| 500 | 392.5 ms | 64.1 ms | 约 84% |
在拥有 500 个服务时, React Flow 仅需约 64 ms 即可完成地图渲染,而 Cytoscape.js 需要约 393 ms,速度约快 6 倍。仅图布局计算这一步就提升了约 70%--78% 的性能。主线程总阻塞时间减少了约 20%,尽管所有内容都作为真实 DOM 渲染,峰值内存占用也略有降低。更多结果可参考基准测试结果评论。
APM 服务地图中的键盘导航与无障碍支持
现在,当你在拓扑中导航时,服务地图会实时播报你当前所在的位置,并为每一次交互提供屏幕阅读器的实时上下文( #251444 )。
基于空间位置的方向键导航: 方向键会根据视觉上的相对位置进行导航,而不是按照文档的逻辑顺序。即使在复杂的蛇形布局中,焦点也会移动到你按下方向键所对应方向上最近的服务。
直接快捷键: 按下 Enter 或 Space 可打开详情面板( flyout ),按下 Escape 可关闭。
实时播报: 每一次交互都会通过屏幕阅读器进行播报,例如"已选择从 A 到 B 的连接"。

APM 服务地图布局算法如何工作
APM 服务地图使用 Dagre 进行层次化图布局,然后应用蛇形折叠( serpentine folding ),避免较长的依赖链生成难以阅读的超高宽高比长条布局:
1)Dagre 层次化布局: 我们使用图布局引擎 Dagre,并支持在水平和垂直布局方向之间切换,你可以在选项面板中进行修改。如果 Dagre 无法计算布局,服务地图会回退到确定性的网格布局,从而保持可交互性并避免出现错误。

2)针对长链的蛇形折叠( serpentine folding ): 较长的依赖流水线会形成狭长且难以阅读的条状布局,需要大量缩放才能查看。当宽高比变得过于极端时,我们会将各层( rank )折叠为上下堆叠、来回蛇形排列的带状结构,使"适应视图( fit view )"能够更紧密地缩放到实际的服务区域。如果拓扑本身已经足够紧凑,或者跨带状结构的边过多,则会跳过蛇形折叠。( #272900 )

服务依赖关系映射与 Kibana 仪表板嵌入背后的实现原理
视觉上的焕然一新最容易被注意到,而支撑重构后服务地图的一些架构变化包括:
使用统一资源节点,实现更简洁的服务依赖关系映射
我们现在会将外部依赖统一归并为资源节点( resource node ),从而减少视觉噪音。我们还修复了消息队列 span 的分组方式,使这类模式不再产生孤立节点( orphaned node )。( #252713)
基于 ES|QL 和 Lens 驱动的服务地图详情面板图表
服务详情面板( flyout )中的基础设施和 RED 指标图表现在基于 ES|QL 和 Kibana 核心的 Lens 可视化引擎构建,使服务地图能够提供与整个 Kibana 一致的图表使用体验。( #273713 )

将服务地图嵌入到任何 Kibana 仪表板
将服务地图添加到仪表板只需一次点击。在 APM 的任意服务地图视图中打开"复制到仪表板( Copy to dashboard )"菜单,当前的环境、服务过滤器、 KQL 查询以及过滤器标签( filter chips )都会一并带到仪表板中。像 now-15m 这样的相对时间范围会原样保留,而不会冻结为绝对时间戳,因此该面板会在仪表板中持续保持实时更新。(#272277)
嵌入后,面板会根据所在位置自动进行调整。它会根据当前视图模式显示或隐藏相应的控件,并遵循全局时间设置,同时不会覆盖你配置的相对时间范围。( #274551 )

APM 服务地图的下一步计划
服务地图重构是一个基础,而不是终点。除了 9.5 中已经提供的功能之外,后续的一些功能已经列入 APM 服务地图路线图。
贡献者
我负责领导这次迁移,并与一支优秀的团队一起构建了这些功能。感谢 Samuel Brito、Gonçalo Rica Pais da Silva、Irene Blanco Fabregat、Carlos Crespo、Miriam Aparicio Garcia、Sandra G 和 Nathan Smith 在工程方面的贡献,也感谢 Karolina Kurstak 和 Roshan Gonsalkorale 在设计和产品工作方面的支持。
原文:APM service map 6x faster: Kibana's React Flow migration --- Elastic Observability Labs