불완전한 시스템이 좋은 이유: Bluesky의 손실 타임라인
- 시스템 설계 시 데이터 일관성, 가용성, 지연 시간 등을 완벽하게 만들려고 노력하지만, 모든 요소를 동시에 완벽하게 구현하는 것은 어렵거나 불가능함. 따라서 각 요소를 균형 있게 조정하여 애플리케이션에 적합한 설계를 찾는 것이 중요함.
- Bluesky의 FollowingFeed/Timeline 설계에서 일관성을 희생하여 쓰기 성능을 향상시키는 주요 트레이드오프를 통해 사용자에게 부정적인 영향을 주지 않으면서 P99를 96% 이상 감소시킴.
타임라인 팬아웃
- 사용자가 Bluesky에 게시물을 올리면, 시스템에 의해 인덱싱되고 데이터베이스에 저장되어 API 응답으로 제공됨.
- 게시물은 팔로워들에게 "팬아웃"되어 그들의 타임라인에 표시됨.
- 타임라인 테이블은 사용자별로 샤딩되어 있으며, 고가용성을 위해 여러 샤드에 복제됨.
- 타임라인은 정기적으로 다듬어져 목표 길이에 가깝게 유지되고, 공간을 절약하기 위해 오래된 게시물 참조는 삭제됨.
핫 샤드 문제
- Bluesky는 약 3,200만 명의 사용자가 있으며, 타임라인 데이터베이스는 수백 개의 샤드로 나뉨.
- 일부 사용자가 비정상적으로 많은 수의 다른 사용자를 팔로우할 경우, 그들의 타임라인은 매우 높은 속도로 쓰기 및 다듬기 작업이 발생하여 문제를 일으킬 수 있음.
- "핫 샤드"는 특정 샤드의 데이터가 다른 데이터보다 훨씬 높은 속도로 읽히거나 쓰이는 상황을 의미함.
지연 시간 누적
- 팔로워가 200만 명인 사용자의 팬아웃을 고려할 때, 평균 쓰기 지연 시간은 약 600마이크로초임.
- 1,000개의 타임라인에 동시에 팬아웃하면 약 1.2초가 걸리지만, P99 지연 시간은 15밀리초까지 올라갈 수 있음.
- 최악의 경우, 팔로워가 많은 사용자의 게시물 팬아웃은 5분 이상 걸릴 수 있음.
손실 타임라인
- 많은 수의 사용자를 팔로우하는 사용자는 타임라인을 완벽하게 따라잡기 어려움.
- 합리적인 팔로우 수를 초과하는 사용자의 타임라인은 완벽한 연대기를 제공할 필요가 없으며, 항상 새로운 콘텐츠를 제공하는 것이 중요함.
-
loss_factor를 사용하여 타임라인의 쓰기를 확률적으로 줄여 핫 샤드를 방지할 수 있음.
캐싱에 대한 보충 설명
- 타임라인에 초당 백만 번 이상 쓰기 작업이 발생함.
- Redis 정렬 집합을 사용하여 높은 팔로우 계정을 캐싱하고, 팬아웃 서비스 인스턴스가 30초마다 업데이트된 버전을 메모리에 로드함.
결과
- 손실 타임라인을 도입한 후, 타임라인 데이터베이스 클러스터에서 핫 샤드가 크게 감소함.
- 팬아웃 작업의 P99가 90% 이상 감소하고, 전체 게시물 팬아웃의 P99 지속 시간이 96% 이상 감소함.
- 일관성을 희생하여 시스템의 다른 바람직한 측면을 얻고 확장성을 높일 수 있음.