현대 분산 아키텍처에서 팬아웃과 직렬 연쇄가 꼬리 지연을 어떻게 증폭시키는지, 그리고 어떤 지표를 모니터링해야 하는지에 대한 직관적 설명.
짜증날 정도로 정성적인 접근.
꼬리 지연(tail latency), 또는 높은 백분위수 지연은 클라이언트가 비교적 드물게 겪는 높은 지연을 말합니다. 예컨대 “내 서비스는 대부분 약 10ms에 응답하지만, 때때로 약 100ms가 걸린다” 같은 것입니다. 세상에는 꼬리 지연의 원인이 많습니다. 경합(contention), 가비지 컬렉션, 패킷 손실, 호스트 장애, 운영체제가 백그라운드에서 하는 별난 일 등이 그 예입니다. 99.9번째 백분위를 보고서는, ‘그거 별로 중요하지 않네’라고 느끼기 쉽습니다. 어쨌든 1000번 중 999번의 호출은 그보다 낮은 지연을 보이니까요.
불행히도, 그렇게 간단하지 않습니다. 이유 중 하나는 현대 아키텍처(마이크로서비스와 SOA 같은)가 구성 요소가 많다는 점입니다. 그래서 한 번의 사용자 상호작용이 아주 많은 서비스 호출로 번역되곤 합니다. 이런 시스템에서 흔한 패턴은 어떤 프런트엔드(서비스일 수도, 자바스크립트나 앱일 수도 있음)가 필요를 충족하기 위해 여러 백엔드 서비스를 호출하는 것입니다. 그 서비스들은 다시 다른 서비스를 호출하고, 또 그다음 서비스를 호출합니다. 이렇게 해서 두 가지 상호작용 유형이 생깁니다. 바로, 여러 백엔드를 병렬로 호출해 모두 완료될 때까지 기다리는 병렬 팬아웃과, 한 서비스가 다른 서비스를 호출하고 또 그 다음을 호출하는 식의 직렬 체인입니다.

이런 패턴은 꼬리 지연을 당신이 생각하는 것보다 더 중요하게 만듭니다.
왜 그런지 이해하기 위해 간단한 수치 실험을 해봅시다. 모든 서비스가 동일한 지연을 보이고, 그 지연은 아주 단순한 이봉분포를 따른다고 가정해 세상을 단순화하겠습니다. 즉 99%의 경우 평균 10ms(표준편차 2ms를 갖는 정규분포)이고, 1%의 경우 평균 100ms(표준편차 10ms)를 갖습니다. 현실 세계에서도 서비스 지연은 거의 항상 이런 식으로 다봉(modal)이며, 보통 단순한 정규분포의 합은 아니지만(여기서는 중요하지 않습니다) 말이죠.
병렬 호출
먼저 병렬 호출을 생각해 봅시다. 논리는 단순합니다. N개의 서비스를 병렬로 호출하고, 가장 느린 것 하나를 기다립니다. 직관적으로는 N이 커질수록 약 100ms짜리 느린 호출을 기다릴 가능성이 점점 더 커진다고 예상할 수 있습니다. N=1이면 그런 일이 약 1%의 확률로 일어납니다. N=10이면 대략 10%쯤이죠. 이 단순한 모델에서는 그 기본 직관이 맞습니다. 모양은 다음과 같습니다:
꼬리 모드(tail mode)는 예전에는 꽤 드물었지만 N이 커질수록 지배적이 됩니다. 드문 사건이 이제는 평범해집니다. 거의 모든 사람이 안 좋은 경험을 하게 됩니다.
직렬 체인
직렬 체인은 좀 더 흥미롭습니다. 이 모델에서는 서비스가 체인을 따라 서비스를 호출합니다. 최종 지연은 체인 아래의 모든 서비스 지연의 합이므로, 생각해야 할 경우의 수가 훨씬 많습니다. 느린 서비스가 하나, 두 개, 등등. 따라서 N이 증가함에 따라 분포의 전체적인 형태가 달라질 수 있다고 예상할 수 있습니다. 중심극한정리 덕분에 N이 커질수록 어떤 모습으로 수렴할지 계산할 수 있지만, 거기로 가는 과정 또한 흥미롭습니다.
여기서는 체인 길이가 지연에 미치는 영향을 두 가지 세계에서 시뮬레이션합니다. 하나는 앞서 설명한 이봉분포를 갖는 꼬리 세계이고, 다른 하나는 10ms 주변의 기본 분포만 가지는 꼬리 없음 세계입니다.
여기서도 꼬리 지연이 더 두드러집니다. 비교적 드문 그 꼬리가, 우리가 수렴해 가는 분포의 분산을 25배나 늘립니다. 시작할 때는 별로 중요해 보이지 않았던 것이 만들어낸 엄청난 차이입니다.
요약 통계 선택하기 이것이 사고방식에 영향을 주어야 하는 한 가지는, 어떤 지연 통계를 모니터링할지 선택하는 방식입니다. 사실 어떤 요약 통계도 전체 그림을 완전히 보여주지는 못합니다. 히스토그램을 보는 건 멋지지만, 시간 요소를 놓치곤 합니다. 윈도우를 둔 히스토그램 히트맵 같은 것을 볼 수도 있겠지만, 아마 그렇게 하진 않을 겁니다. 대신 서비스 지연의 높은 백분위를 인지하고, 흔한 고객 또는 클라이언트 사용 사례를 정해 그들의 엔드 투 엔드 지연 경험을 모니터링하는 것을 고려하세요.
절사평균(trimmed mean), 윈저화 평균(winsorized mean), 절단평균(truncated mean), 사분위 범위(interquartile range), 그리고 분포의 꼬리를 일부 잘라내는 다른 통계들이 인기를 얻는 듯합니다. 절사평균과 그 친구들에는 좋아할 점이 많지만, 오른쪽 꼬리를 잘라내면 그 꼬리가 매우 중요하고 클라이언트가 서비스를 호출하는 방식에 따라 지배적이 되기도 하는 효과를 놓치게 됩니다.
저는 여전히 단 한 가지만 측정해야 한다면 평균이라고 믿습니다. 다만, 아마 한 가지만 측정하고 싶지는 않을 겁니다.