SoundCloud 的后端运行在微服务之上,接口是手工搭建的 REST/JSON 接口,调试方便,但每个端点的约定——HTTP 方法、JSON 字段名、时间戳格式、错误结构——都取决于构建它的团队。内部规范能起的作用有限:曾有客户端向期望 snake_case 的服务器发送 camelCase 字段,导致了一次故障;而要理解任何一个端点,都得去读应用代码,而不是看一份契约。

SoundCloud 构建了 Twinagle,这是 Twitch 的 Twirp RPC 协议在 Scala/Finagle 上的实现,让工程师可以用 protobuf 一次性定义 API,并据此生成服务端和客户端代码。他们最先迁移的是高流量的曲目授权服务。他们没有直接切换,而是让 REST 和 Twirp 在一个按百分比控制的开关后面并行运行:在较低的放量比例下,两个端点都会被调用并比对,但只返回 REST 的响应,因此不一致会以记录在日志中的差异形式暴露出来,而不是变成用户可见的缺陷。

将流量镜像到新端点,进行差异比对,然后完成切换

从同一份 protobuf 契约生成服务端和客户端代码,消除了团队各自发明 JSON 字段命名和 HTTP 约定所导致的那一类缺陷。

在切换前以较小的流量比例并行运行两个端点,让团队能够在没有任何用户看到错误答案的情况下发现响应不一致。

从单个客户端的高流量服务入手,使首次迁移的集成面保持较小,同时仍在真实负载下验证了 Twinagle。

保持现有业务逻辑不变,把新代码限制在薄薄的一层序列化层中,从而限制了新缺陷可能藏身的地方。

在淘汰一个仍在运行的系统之前,让替代系统并行应答每一个请求,并与现有系统做差异比对——这样缺陷会在旧系统仍负责返回响应时暴露出来。

这种影子对比式的放量在缺陷到达用户之前就捕获了若干关键缺陷,SoundCloud 将曲目授权服务提升到 100% 的 Twirp 流量,首次尝试即无故障、无缺陷。两个服务之间的带宽因从 JSON 切换到二进制 protobuf 而下降超过 40%,团队还删除了该服务所有自定义的 JSON 序列化代码。SoundCloud 随后将其余服务也迁移到 Twinagle,并使其成为所有新服务的默认方案。

从这里,追溯依据

参考来源

  1. Announcing Twinagle: Twirp and Protobuf for Finagle SoundCloud Engineering · developers.soundcloud.com ·