SoundCloud의 백엔드는 손수 만든 REST/JSON 인터페이스를 갖춘 마이크로서비스 위에서 돌아갔다. 디버깅은 쉬웠지만, HTTP 메서드, JSON 필드 이름, 타임스탬프 형식, 오류 형태 등 모든 엔드포인트의 관례를 그것을 만든 팀이 각자 정해야 했다. 내부 가이드라인만으로는 역부족이었다. 한 클라이언트가 snake_case를 기대하는 서버에 camelCase 필드를 보내 장애를 일으킨 적이 있었고, 어떤 엔드포인트를 이해하려면 계약서가 아니라 애플리케이션 코드를 읽어야 했다.

SoundCloud는 Twitch의 Twirp RPC 프로토콜을 Scala/Finagle로 구현한 Twinagle을 만들었다. 이를 통해 엔지니어들은 API를 protobuf로 한 번 정의하고 그로부터 서버와 클라이언트 코드를 생성할 수 있었다. 그들은 트래픽이 많은 트랙 인가 서비스를 가장 먼저 마이그레이션했다. 곧바로 전환하는 대신, 비율 기반 플래그 뒤에서 REST와 Twirp를 나란히 실행했다. 낮은 롤아웃 비율에서는 두 엔드포인트를 모두 호출해 비교하되 REST 응답만 반환했기 때문에, 불일치는 사용자에게 보이는 버그가 아니라 로그로 기록된 불일치로 드러났다.

새 엔드포인트로 트래픽을 미러링하고, 비교(diff)한 뒤, 전환하다

하나의 protobuf 계약에서 서버와 클라이언트 코드를 생성함으로써, 팀들이 각자 JSON 필드 명명과 HTTP 관례를 만들어내면서 생기던 부류의 버그가 사라졌다.

전환하기 전에 작은 트래픽 비율로 두 엔드포인트를 병렬 실행함으로써, 팀은 사용자 누구도 잘못된 응답을 보지 않은 채 응답 불일치를 잡아낼 수 있었다.

단일 클라이언트의 고트래픽 서비스부터 시작함으로써 첫 마이그레이션의 통합 범위를 작게 유지하면서도 실제 부하에서 Twinagle을 입증할 수 있었다.

기존 비즈니스 로직은 그대로 두고 새 코드를 얇은 직렬화 계층에 국한시킴으로써 새 버그가 숨을 수 있는 곳을 제한했다.

작동하는 시스템을 폐기하기 전에, 대체 시스템이 모든 요청에 병렬로 응답하게 하고 그것을 기존 시스템과 비교(diff)하라. 그러면 기존 시스템이 여전히 응답을 제공하는 동안 버그가 드러난다.

섀도 비교 롤아웃은 여러 치명적인 버그가 사용자에게 도달하기 전에 잡아냈고, SoundCloud는 트랙 인가 서비스를 첫 시도에 장애도 버그도 없이 Twirp 트래픽 100%로 끌어올렸다. 두 서비스 간 대역폭은 JSON에서 바이너리 protobuf로 전환하면서 40% 이상 줄었고, 팀은 해당 서비스의 모든 자체 JSON 직렬화 코드를 삭제했다. SoundCloud는 이어서 다른 서비스들도 Twinagle로 전환했고, 앞으로 모든 신규 서비스의 기본값으로 삼았다.

근거 확인하기

출처

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