해결책
SoundCloud의 JVMKit 라이브러리는 서비스 스캐폴딩, 데이터베이스 및 Kafka 통합, 메트릭 등 공유 JVM 패턴을 수백 개의 내부 Scala, Java, Clojure, JRuby 서비스에 제공했다. 채택이 늘어나면서 플랫폼 팀은 어떤 서비스가 JVMKit API의 어느 부분에 의존하는지에 대한 가시성을 잃었고, 이로 인해 모든 릴리스가 도박이 되었다. 일상적인 업데이트가 팀이 영향을 받는지조차 몰랐던 서비스를 조용히 망가뜨릴 수 있었다.
SoundCloud의 의존성은 각 저장소의 빌드 파일(JVM의 경우 sbt, Android의 경우 Gradle, 웹의 경우 npm)에 명시적으로 선언되었기 때문에, 팀은 5분마다 갱신되는 정규식 기반 코드 검색 엔진인 Zoekt로 모든 저장소를 인덱싱했다. JVMKit을 의존성으로 나열한 빌드 파일에 대한 간단한 쿼리는 JVMKit 변경으로 영향을 받을 모든 서비스를 자동으로 생성하는 실시간 역방향 의존성 그래프를 만들어냈다. 이는 수작업으로 추적하는 대신 자동으로 생성되었다.
그 그래프를 손에 넣은 팀은 검증 파이프라인을 구축했다. 각 의존 서비스에 대해 저장소를 복제하고, 수정 없이 컴파일 및 테스트하여 기준선을 설정한 다음, 후보 JVMKit 버전으로 교체하고, 알려진 호환성 깨짐 API 변경에 대한 스크립트 수정을 적용한 후 다시 컴파일 및 테스트했다. 기준선은 통과했지만 후보가 실패하면, JVMKit 변경이 원인이지 해당 서비스의 기존 문제가 아니었다. 이 검사는 전체 의존 서비스 집합에 대해 야간에 실행되었고, 더 빠른 허용 목록 하위 집합에 대해서는 모든 풀 리퀘스트에서 실행되었다.
달성한 것
라이브러리를 릴리스하기 전에 모든 호출자를 컴파일 및 테스트
수동적이고 오류가 발생하기 쉬운 프로세스(릴리스 후 팀이 불평하기를 기다림)를 릴리스 배포 전에 실행되는 자동적이고 반증 가능한 검사로 대체했다.
수정되지 않은 기준선을 먼저 실행함으로써 실패가 JVMKit 변경에서 비롯된 것인지 아니면 그날 이미 망가진 서비스에서 비롯된 것인지 분리할 수 있었다.
검증을 야간 전체 실행과 빠른 PR 범위 실행으로 분할하여 전체 범위를 건너뛰지 않으면서도 피드백을 신속하게 유지했다.
역방향 의존성 그래프는 수작업으로 유지되는 것이 아니라 코드에서 생성되었기 때문에 서비스가 추가되거나 제거되어도 정확성을 유지했다.
하나의 내부 라이브러리가 수백 개의 서비스 아래에 있을 때, 희망에 기대어 배포하지 말고 의존성 그래프를 쿼리 가능하게 만들고 CI가 모든 하위 호출자를 먼저 테스트하도록 하라.
그 후
JVMKit은 SoundCloud에서 수백 개의 서비스와 수천 개의 프로덕션 인스턴스를 계속 지원했다. 검증 파이프라인이 구축된 후 플랫폼 팀은 JVMKit을 더 자주 릴리스하게 되었고, 실패는 하위에서 설명되지 않는 장애로 나타나는 대신 특정 단계와 특정 원인으로 추적 가능했다고 보고했다.
근거 확인하기
출처
- Did I Break You? Reverse Dependency Verification SoundCloud Engineering · developers.soundcloud.com ·