Failed Distributed Tracing
관찰가능성에 대한 많은 글들을 읽다보면 분산 트레이싱은 “모든 MSA의 흐름을 한눈에 보여주는 필살기” 같은 느낌으로 소개된다. 최초로 이 개념이 도입된 Dapper나 유명하게 알려진 트위터의 사례들도 성공적인 사례로 많이 알려져있고, 현재는 Jaeger나 Zipkin, OTEL 같은 오픈소스 도구는 물론이며 이 분산 추적이 포함되지 않은 관찰가능성 도구를 찾는게 사실상 불가능해진 시기다. 그래서 서비스를 운영하는 조직이라면 이 트레이싱을 항상 고민하게 된다. 당연히 이 분산 트레이싱은 마법의 도구가 아니고, 모든 조직이 항상 알맞은 Silver Bullet이 아니다.
그런데 오히려 내가 오늘 이야기하고 싶은 내용은 사실 정 반대이다. “이건 Silver Bullet이 아니야” 같이 뻔한 기술 부정적 사고가 아니라, 오히려 그와 반대로 이를 도입해야하는 이유와 어떻게 이를 어떤 스케일에서도 성공할 수 있을지 가능한 행복 회로를 최대한 굴리면서 글을 써보고싶다.
꼭 강조하고 싶은 내용이 있다. 이 글은 절대로 “모든 경우에 분산 트레이싱을 적용해야하는 개쩌는 솔루션이다” 라고 말하고 싶은 것이 절대로 아니다. 오히려 내가 하고 싶은 말은 왜 은총알이 될 수 없는지를 다시 한번 살펴보고, 어떻게 하면 이를 은총알에 가깝게 만들어볼 수 있을까? 하는 사고 회로를 거쳐보자는 것이다. 모두가 알듯 은총알은 없다. 허나 은총알이 없다고하여 모든 기술을 부정하는 현상이 최근 많이 보인다고 생각한다. 내가 바라는 것은 한번 더 생각해보자는 것이다.
환상
바로 위 서론처럼 말했지만, 일단 우리가 가진 환상부터 파악해봐야 더 객관적인 사고를 할 수 있을 것이다. 트레이싱에 대한 가장 큰 착각은 “트레이싱만 있다면 시스템과 장애를 한눈에 파악할 수 있다”라는 환상이다. 물론 충분한 설계와 준비가 뒷받침 된다면 이게 잘못된 사고라고는 생각하지 않는다. 문제는 그 충분한 설계와 준비가 생각보다 훨씬 복잡하고 장기적인 노력을 요구한다는 점이 문제인 것 같다.
트레이싱은 전형적인 중앙화된 로그 수집과 달리, 각 요청이 거치는 다양한 서비스와 Span으로 추상화되는 서비스 호출을 모두 연결해서 하나의 그래프로 만든다. 이 떄 어느 서비스는 API 호출마다 새 트레이스를 생성하기도 하고, 또 다른 서비스는 아예 스팬을 보내지도 않을 수도 있고, 어느 구간에는 샘플링이 1%이며 어떤 구간은 100%로 잡혀있을 수도 있다. 모든 서비스가 동일한 샘플링 로직을 따르면서 동일한 Clock Sync 기준을 가지고 동일한 스팬 스키마를 유지해야지 진짜로 도움이 되는 트레이스가 만들어질 수 있다. 그런데 문제는 도입 과정에서 이런 사소해보이는 설정 하나하나가 통일되지 않아 스팬이 누락되거나, 시간이 싱크가 안되어 이상해지거나, 스팬이 누락되거나 스키마가 충돌하는 등의 다양하고 복잡한 문제들이 발생한다. 이 결과는 결국에 트레이싱이 최고의 관찰 가능성 도구라는 기대를 산산조각 낸다. 그리고 “우리 정도의 규모 서비스에는 트레이싱은 적합하지 않아”라는 단순하고 무책임한 결론으로 일을 마무리 지어버릴 수 있다.
데이터
또 트레이싱이 제대로 동작하기 시작하면 바로 다음 문제가 생긴다. 스팬의 양이 너무 많아진다는 문제다. 단순한 예로 몇개 안되는 마이크로서비스를 운영하더라도 한 요청당 여러 한 요청 당 여러 내부 프로시저 호출과 DB 쿼리가 연결되면 스팬의 수가 금방 수십, 수백배로 늘어난다. 보통 이런 스팬들은 많은 기업들에서 시계열DB에 저장하기도 하지만, 전용 파이프라인으로 전처리를 거쳐서 인덱싱 테이블을 만들어서 운영하기도 한다. 예를 들어서 trace라는 테이블에는 트레이스 단위로 핵심 정보들을 요약해서 저장하고 span에는 주요 필드를 빠르게 검색할 수 있도록 하는 방식으로 운영한다는 의미다. 또 메트릭화가 가능한 항목들은 별도의 집계 테이블로 만들어서 운영하기도 한다.
결론적으로 이렇게 잘 정의되고 정리된 스키마와 파이프라인이 없다면 “특정 서비스의 최근 한 시간동안의 평균 지연 시간을 알려주세요” 같은 아주 단순한 질문에 답하기 위한 쿼리도 긴 시간을 기다려야 할 수 있다. 그리고 그 뒤에는 “트레이싱 보기 너무 느려요”라고 팀원들은 말하기 시작하며 “그냥 로그나 볼게요”하고 트레이싱을 무용하게 생각하게 할 수 있을 것이다. 이를 해결하기 위해서는 결국 집계 성능을 높혀야하는데, 이건 성능 이슈고 이를 해결하기 위해서는 결코 단순한 작업으로는 해결하기 어려울 것이다.
트레이스 뷰어
우리가 트레이스를 생각할 가장 먼저 떠오르는건 모든 서비스의 호출이 유기적으로 연결된 기다란 트레이스 뷰어를 떠올릴 것 같다. 스팬들이 타임라인으로 펼쳐져있고, 언제 RPC가 시작했으며 언제 끝났는지, 어떤 서비스의 어떤 트레이스가 자식 스팬을 생성하는지 등을 매우 선명하게 볼 수 있다.
그리고 당신도, 나도 이런 데모를 보고 “이것만 있으면 디버깅 한눈에 끝낼 수 있겠다”라고 눈이 돌아간다. 그런데 당신도 알것이다. 실제로 적용한 이후에 트레이스 뷰어를 켜보면 생각한 것 처럼 정말 한눈에 원일을 파악할 수 있는 일은 없다는 것을 말이다. 가령 원인은 DB 인덱스 설계를 잘못해서 특정한 시점에서 쿼리들이 폭발하기 시작한건데, 트레이스 뷰에는 단순히 “DB 쿼리의 시간이 길어짐” 정도로만 보이니 이걸로 어떻게 원인을 파악할 수 있겠는가. 그래서 결국에는 이 디버깅을 하기 위해서는 로그나 메트릭을 다시 뒤져봐야한다.
결론적으로 트레이싱이 “맥락을 한눈에 보여준다”라는 장점은 있으나, 그것만으로 모든 문제를 해결하게 하지는 못한다. 특히 서비스를 이루고있는 서버들이 아주 조금만 많아져도 “어떤 트레이스를 먼저 봐야하는가”라는 새로운 문제도 발생하게 된다. 전체 요청 중 대표성을 가지는 트레이스나 실제 장애 상황을 보여주는 트레이스를 자동으로 골라주는 추가 로직이 없다면 쌓이는 스팬 중 어디를 봐야할지 감도 못잡게 된다. 결국 우리가 반했던 트레이스 뷰어는 만능이 아니고 적절한 검색, 필터링, 통계 기능이 뒤따라 주어야하며 이게 없다면 트레이싱 뷰어는 “개쩔게 멋있는 데모”로 끝나게 될 것이다.
문화
트레이싱은 개발팀에서 개인이 취미 삼아서 붙여볼 수 있는 단순한 라이브러리 작업이 아니다. 전사적으로, 최소한 여러팀간의 합의가 이뤄져야하고 한 두명이 아닌 사실상 모든 엔지니어들이 스팬의 구조를 숙지하고 이 기술을 이해해야한다. 그렇게 하지 않으면 어떤 팀은 1%만 샘플링하고, 다른 팀은 100%를 샘플링하고, ㄹ어떤 서비스는 처음에 트레이싱을 다 지원했다가 나중에 코드를 리팩토링하면서 하나 하나 빠뜨리는 일이 벌어질 수 있다. 또한 트레이스를 수집하는 시스템도 준비해야하고, 서비스의 부하가 튈 때 그 배수보다더 더 기하급수적으로 늘어나는 스팬의 수를 감당할 수 있는 스팬 큐잉 로직도 준비해둬야 한다. 그래서 이것들을 담당할 전문 팀을 따로 운영하지 않으면 시간이 지날수록 스팬은 점점 더 누락되고 트레이싱 시스템의 신뢰도도 점점 더 떨어지게 될 것이다. 그럼 이 결과는 엔지니어들이 “트레이싱은 정보가 정확하지 않다”라고 생각하게 되어 다시 로그나 메트릭만 보게된다. 분산 시스템이 성공적으로 정착하는 조직이나 사례들을 잘 살펴보면 보통 샘플링부터 시작해서 시각화, 스키마 등등의 필요한 구성 요소들을 모두 한 묶음으로 만들어 문화를 만든다. 이게 없으면 트레이싱은 실패할 것이다.
마무리
분산 트레이싱이 실패한다고 하는 말은 사실 “아무 준비도 없이 시도했다가는 실패한다”라는 뜻에 가깝다. 트레이싱은 단순 로그나 메트릭보다 훨씬 더 복잡한 시스템이고 전사적인 관점에서 훨신 더 치밀하게 설계하고 운용할 수 있어야 그 진짜 가치를 보일 수 있을 것이다. 스팬 데이터가 무분별하게 커지는걸 막고, 일관된 샘플링 정책을 가지고 시스템에서 원하는 질문에 대한 답을 얻을 수 있는 인프라를 이미 갖추고 있으며, 트레이스 뷰어를 단순히 뷰어가 아니라 “분석 플랫폼”으로 사용할 수 있게하며 이를 전사적인 문화로 까지 만드는 과정도 필요하다. 이 중 한 두계라도 소홀히 하면 “우리는 왜 이거 했지”라는 회의감이 번지기 시작한다. 실제로 많은 팀이 트레이싱을 붙였다가 별로 쓰지도 않고 버리게되는 이유는 “분산 트레이싱이라는 기술이 우리 조직과 맞지 않아서”라기 보다도, 이를 제대로 운영할 만큼의 준비가 부족해쏙 관심이 부족했기 때문일 것이다.
결국 트레이싱 도입의 핵심은 “지금 우리에게 꼭 필요한 인사이트를 제공할 수 있을까?”라는 질문에 대답할 수 있어야 할 것이다. 정말 비지니스적으로 중요한 요청들의 경로를 골라서 필요한 스팬하고 애트리뷰터들으 엄선하고, 그 데이터를 어떻게 집계하고 분석해서 의사결정에 반영할건지 미리 생각해 두어야 할 것이다. 그렇게 시나리오하고 활용 목적이 분명해야지 트레이싱이 장기적인 가치를 유지할 수 있을 것이다. 무턱대고 “오픈소스 하나 깔면 되겠지”라는 단기적인 접근으로는 그냥 화려한 PoC로 끝나게 될 것이다.