- 단일 SaaS 애플리케이션의 Postgres 병목이 심해져 CPU 사용률이 60~80%에 머물렀고, 한때 100%까지 올라 짧은 장애로 이어짐
- 더 큰 DB 인스턴스로 바꾸는 수직 확장은 이미 한계에 도달해, 같은 방식으로는 부하 증가를 더 흡수하기 어려웠음
- 쓰기 샤딩과 마이크로서비스는 용량과 운영 탄력성을 높일 수 있지만, 백업·모니터링·마이그레이션·ORM·네트워크 토폴로지까지 복잡성 비용을 계속 남김
- 실제로는 3개월간 무거운 쿼리 제거, Rails 코드 최적화, Postgres 튜닝을 진행하고 일부 비싼 읽기 전용 쿼리를 복제 DB로 분리함
- 그 결과 주간 최대 DB CPU 사용률이 90%에서 30%로 줄어, 차세대 아키텍처로 넘어가기 전에 현재 시스템을 더 오래 활용할 여지가 생김
Postgres 병목과 수직 확장의 끝
- 단일 SaaS 애플리케이션의 부하가 커지면서 Postgres 성능이 핵심 병목이 됨
- CPU 사용률은 60~80% 구간에 머물렀음
- 적어도 한 번은 100%까지 치솟아 짧은 장애가 발생함
- 이전에는 DB가 바빠질 때마다 더 큰 인스턴스로 교체해 시간을 벌었음
- 이 방식 덕분에 기능 개발 같은 다른 일에 집중할 수 있었음
- 당시에는 이미 가장 큰 인스턴스를 사용 중이라 더 이상 수직 확장이 불가능했음
매력적이지만 비싼 차세대 아키텍처
- 논의된 주요 선택지는 쓰기 샤딩과 마이크로서비스였음
- 쓰기 샤딩은 독립 DB 클러스터를 두고, 파티셔닝 전략에 따라 데이터를 특정 DB에 쓰는 방식임
- 잠재적으로 용량을 2~3자릿수까지 늘릴 수 있음
- 마이크로서비스는 모놀리스를 여러 서비스로 나누고, 각 서비스가 자체 데이터 저장소를 갖도록 함
- 서비스별 워크로드에 맞춰 데이터 저장소를 고를 수 있음
- 두 방식 모두 장애 허용성과 운영 회복력 측면에서 선택지를 넓히지만, 당장의 목표는 DB 성능을 통제 가능한 상태로 되돌리는 것이었음
복잡성은 한 번 도입하면 계속 비용을 만든다
- 복잡성 증가는 새 구조를 구현하는 비용을 넘어 이후의 주의력 비용으로 이어짐
- DB 샤딩을 선택하면 앞으로의 기술 결정마다 새 복잡성을 함께 다뤄야 함
- 백업
- 모니터링
- 마이그레이션
- ORM
- 네트워크 토폴로지
- 마이크로서비스도 비슷한 부담을 만들며, 추가 아키텍처를 유지하느라 기능 전달이 늦어지거나 포기될 수 있음
먼저 현재 시스템에서 여유를 찾기
- 큰 아키텍처 전환이 필요해 보일 때도 기존 시스템에는 추가 여유가 남아 있는 경우가 많음
- 워크로드 조정, 성능 튜닝, 보조 시스템 추가만으로 몇 달 또는 몇 년의 시간을 벌 수 있음
- 이런 선택지가 실행 가능하다면 차세대 시스템을 새로 구축하기 전에 먼저 시도할 만함
실제로 수행한 최적화
- 첫 번째 작업에서는 두 엔지니어가 약 3개월 동안 주로 DB 성능 문제를 다룸
- 단일한 묘책은 없었음
- 텔레메트리로 무거운 쿼리를 찾음
- Rails 코드베이스에서 쿼리 발생 지점을 파악함
- 쿼리를 최적화하거나 제거함
- 여러 Postgres 설정을 튜닝함
- 두 번째 작업에서는 다른 두 엔지니어가 코드베이스를 수정해 일부 비싼 읽기 전용 쿼리를 복제 DB에서 실행하게 함
- 웹 클라이언트의 폴링이 유발하는 가장 빈번한
SELECT쿼리를 주 DB에서 분리함
- 웹 클라이언트의 폴링이 유발하는 가장 빈번한
결과와 운영 원칙
- 두 작업을 합쳐 DB의 주간 최대 CPU 사용률이 90%에서 30% 로 줄어듦
- 주간 최대 CPU 사용률: {l:90,30}
- CPU 여유가 크게 생겼고, 주 DB에서 부하를 덜어낼 수 있는 능력도 커짐
- 코드베이스 여러 부분을 건드리고 여러 개발자가 협업하면서 기존 시스템에 대한 분산 지식도 쌓임
- 복잡성이 항상 나쁜 것은 아니며, 언젠가는 DB 아키텍처의 근본 한계에 도달하기 전에 더 복잡한 구조로 넘어가야 함
- 그 전까지는 현재 시스템을 먼저 짜내면 가능한 한 지루하고 단순한 시스템으로 더 오래 일할 수 있고, 비용과 실용성 면에서도 유리함