SoundCloudのバックエンドは、手作りのREST/JSONインターフェースを持つマイクロサービス上で稼働していた。デバッグは容易だったが、HTTPメソッド、JSONフィールド名、タイムスタンプ形式、エラーの形といった各エンドポイントの慣習は、それを構築したチームに委ねられていた。内部ガイドラインだけでは十分に機能しなかった。あるクライアントがsnake_caseを期待するサーバーにcamelCaseのフィールドを送信して障害を引き起こしたことがあり、また任意のエンドポイントを理解するには契約ではなくアプリケーションコードを読む必要があった。

SoundCloudは、TwitchのTwirp RPCプロトコルをScala/Finagleで実装したTwinagleを構築し、エンジニアがAPIをprotobufで一度定義すればサーバーとクライアントのコードをそこから生成できるようにした。彼らはまず高トラフィックのトラック認可サービスを移行した。直接切り替えるのではなく、RESTとTwirpをパーセンテージベースのフラグの背後で並行稼働させた。低いロールアウト率では両方のエンドポイントが呼び出されて比較され、返されるのはRESTのレスポンスのみだったため、不一致はユーザーに見えるバグではなく、ログに記録された差異として表面化した。

新しいエンドポイントにトラフィックをミラーリングし、差分を比較してから切り替える

単一のprotobuf契約からサーバーとクライアントのコードを生成することで、チームが独自のJSONフィールド命名やHTTPの慣習を考案することに起因する種類のバグが排除された。

切り替える前に少ないトラフィック率で両方のエンドポイントを並行稼働させることで、チームはユーザーに誤った回答を見せることなくレスポンスの不一致を捕捉できた。

単一クライアントの高トラフィックサービスから始めることで、最初の移行の統合範囲を小さく保ちながら、実際の負荷の下でTwinagleを実証できた。

既存のビジネスロジックを変更せず、新しいコードを薄いシリアライゼーション層に限定することで、新しいバグが潜む場所を限定できた。

稼働中のシステムを廃止する前に、置き換え側にすべてのリクエストを並行して応答させ、現行システムと差分比較する。そうすれば、旧システムがまだレスポンスを返している間にバグが表面化する。

このシャドウ比較によるロールアウトは、ユーザーに到達する前に複数の重大なバグを捕捉した。SoundCloudはトラック認可サービスを100% Twirpトラフィックに引き上げ、初回の試みで障害もバグも発生しなかった。2つのサービス間の帯域幅は、JSONからバイナリprotobufへの切り替えにより40%以上減少し、チームはこのサービスのカスタムJSONシリアライゼーションコードをすべて削除した。SoundCloudはその後、他のサービスもTwinagleに移行し、今後のすべての新規サービスでTwinagleをデフォルトとした。

出典をたどる

出典

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