地图画不对,事故查不清

封面图

前几天看到Netflix的一篇技术博客,讲他们怎么重新设计Service Topology——实时服务依赖地图的流处理管道。说实话,这种话题在技术媒体上不太有流量,但我看得很认真。因为服务依赖图这个东西,几乎每个上了规模的团队都想搞,但真正搞得好的很少。

你以为你知道系统长什么样

每个团队在架构评审的时候都会画架构图。方框代表服务,箭头代表调用关系,清清楚楚。但这张图是"设计态"的——它描述的是系统应该长什么样,不是系统实际长什么样。

真实的生产环境里,流量经过负载均衡、NAT网关、API网关、Sidecar代理,一个看起来从A到B的调用,中间可能跳了四五层。更麻烦的是,这些跳转关系还在不断变化——扩缩容、灰度发布、故障切换,都会让实际的依赖关系偏离架构图。

Netflix的Service Topology就是想解决这个问题:用网络流数据(eBPF)、进程间通信指标和分布式追踪,自动构建出系统的"运行态"依赖图。不是人画的,是数据跑出来的。

难点不在数据采集,在数据关联

采集网络流量不新鲜,eBPF让这件事变得很轻量。真正的难点在于:你拿到的是一堆网络跳转记录,怎么把它们还原成应用级的调用关系?

Netflix的做法是把这个过程拆成三个阶段。第一阶段做数据清洗和初步聚合——消费多区域的Kafka流,过滤无效记录,按五分钟窗口做批处理。第二阶段做中间跳转解析,把网络层面的hop翻译成应用到应用的直接调用。第三阶段做数据丰富和持久化,给节点加上健康状态、归属团队、元数据等信息,然后写入图数据库。

这个三阶段设计不是拍脑袋出来的,是被生产环境的痛点逼出来的。早期设计把所有处理放在一起,结果热门服务的中间解析会把某些实例变成热点——有的实例流量达到平均值的100倍。把解析和丰富拆开之后,负载可以重新分配,热点就散了。

回压比丢数据重要

流处理系统最怕什么?不是慢,是丢数据。尤其是服务依赖图这种场景——你查事故的时候,恰恰需要那个时间点的完整依赖快照。如果因为处理不过来就丢数据,那这个工具在最关键的时刻就不可信了。

Netflix用Apache Pekko Streams做回压管理。当图数据库写入变慢,压力会沿处理链向上游传播,直到Kafka消费者暂停。记录留在Kafka里,等容量恢复再继续。代价是高负载时数据新鲜度下降,但至少不丢数据。Netflix认为这比"事故期间拿到一份过时的批量地图"要好得多。

这个取舍值得很多团队学习。我见过不少监控系统,平时跑得挺好,一到故障高峰就开始丢指标、断链路,等你事后复盘的时候发现最关键的那几分钟是空白。可观测性系统的价值恰恰体现在系统最不稳定时刻,如果那个时刻它掉链子了,那这个系统就是摆设。

SSE取代gRPC:一个反直觉的选择

Netflix还把管道内部的通信协议从gRPC换成了SSE(Server-Sent Events)。这个选择看起来有点反直觉——gRPC在微服务间通信中几乎是"标准答案",为什么要换成一个看起来更"前端"的方案?

原因是在Netflix的规模下,gRPC的序列化开销、连接池管理和流式响应的内存压力变得很显著。SSE更轻量,而且天然兼容反应式回压。当然,他们对外暴露给Service Topology客户端的API还是用gRPC,只是内部管道之间用了SSE。

这个细节说明一个道理:没有放之四海而皆准的技术选型,只有适合当前场景的技术选型。规模变了,原来的最优解可能变成负担。

对大部分团队的启示

大部分公司没有Netflix的规模,也不需要自建一套Service Topology。但这篇文章给了几个值得思考的角度:

第一,你的团队有没有一份"活的"服务依赖图?不是PPT里那张半年没更新的架构图,而是能反映当前实际调用关系的实时视图。如果没有,出了问题你怎么排查?靠猜?

第二,你的可观测性系统在故障期间还能正常工作吗?还是说它只在平时好用,最需要它的时候反而掉链子?这个区别决定了你花的钱到底是投资还是浪费。

第三,技术选型要不要随规模变化?很多团队在早期选了一套方案,然后一路用到底,中间从不重新评估。Netflix连gRPC都可以换掉,你有什么不能换的?

说到底,服务依赖地图不是一个技术问题,是一个认知问题。你以为你知道系统长什么样,但系统不这么认为。

You voted 2. Total votes: 23

添加新评论