Instacart의 Rails 및 PostgreSQL 데이터베이스 확장 여정: 단일 데이터베이스를 넘어

Mostafa Abdelraouf - Going beyond a Single Postgres Instance with Rails - Rails World 2024 - YouTube

3줄 요약

  • Instacart는 Rails와 PostgreSQL을 활용하여 단일 데이터베이스에서 수백 개의 인스턴스로 성공적으로 확장했습니다.
  • 초기에는 Makara를 통해 쿼리 라우팅과 부하 분산을 관리했으나, 성능 및 복잡성 문제로 자체 솔루션으로 전환했습니다.
  • 복제 지연 처리, 부하 분산, 그리고 수직/수평 샤딩 전략을 통해 시스템을 확장했으며, 쿼리 패턴 이해의 중요성을 강조합니다.

Instacart는 12년 전 Rails 3.1과 단일 PostgreSQL 인스턴스로 시작하여 현재 수십 개의 Rails 애플리케이션과 수백 개의 PostgreSQL 인스턴스를 운영하는 대규모 시스템으로 성장했습니다. 본 발표는 단일 데이터베이스 환경을 넘어 시스템을 확장하는 과정에서 겪었던 경험과 배운 점, 특히 데이터베이스 확장 시 발생하는 복잡성과 이를 해결하기 위한 Instacart의 접근 방식에 중점을 두어 설명합니다.

Instacart는 시스템 확장을 고려하기 전, 연결 풀링, 스케일업, 효과적인 캐싱, 인덱싱, 쿼리 리팩토링 등 단일 PostgreSQL 인스턴스에서 최대한의 성능을 끌어내는 데 집중했습니다. 이 과정에서 PG Hero와 같은 도구를 활용하여 쿼리 패턴을 분석하고 이해하는 것이 중요하다고 강조합니다. 이후 복제본을 추가하면서 쿼리 라우팅(스위칭)과 복제 지연이라는 새로운 복잡성에 직면했습니다. 초기에는 Makara라는 Ruby Gem을 사용하여 부하 분산, 장애 조치 및 자동 스위칭을 구현했습니다. 그러나 Makara는 연결 체크아웃 시 모든 연결에 대한 과도한 헬스 체크, 명시적 처리가 없는 쿼리의 주(Primary) 데이터베이스 강제 전송, 그리고 방대한 메서드 표면적(약 400개)으로 인한 유지보수 어려움 등의 문제로 인해 점차 페이즈 아웃되었습니다. Instacart는 주 데이터베이스에 대한 불필요한 연결을 피하고 PostgreSQL 연결 객체(PostgreSQL adapter가 아닌)를 래핑하는 방식으로 자체적인 ‘지연 재작성(lazy rewrite)’ 솔루션을 구현했습니다. 이는 훨씬 작은 표면적을 가지므로 관리가 용이합니다. Makara에서 상속받은 유용한 자동 스위칭 규칙들은 다음과 같습니다. 트랜잭션 외부의 읽기 쿼리는 기본적으로 복제본으로 라우팅하여 주 데이터베이스의 부하를 줄이고, 쓰기 및 트랜잭션은 주 데이터베이스로 보냅니다. 또한, 쓰기 작업 후에는 복제 지연을 피하기 위해 해당 요청의 끝까지 주 데이터베이스를 고수하는 전략을 사용합니다. 복제 지연이 허용되는 백그라운드 작업은 재시도 로직을 포함하여 복제본을 활용하고, 엄격한 일관성이 필요한 경우에만 주 데이터베이스를 사용하도록 합니다. 추가 복제본 도입 시 PG Bouncer와 PG Cat 같은 연결 풀러를 사용하여 부하 분산을 구현했습니다. 특히, PG Cat은 무작위(random) 및 최소 연결(least outstanding connections) 부하 분산 메커니즘을 지원하며, 장애 조치 시 부하 균형 회복에 더 효과적임을 강조합니다. 시스템은 장애 조치 시 지연 시간 증가 없이 트래픽을 재분배하고, 복구 후 부하 균형을 회복하는 것이 중요하며, 짧은 연결/쿼리 타임아웃 설정은 빠른 장애 감지에 필수적입니다. 마지막으로, 샤딩 전략으로 수직 샤딩과 수평 샤딩을 적용했습니다. 수직 샤딩은 특정 테이블 전체를 별도의 인스턴스로 분리하는 방식이며, 여러 데이터베이스에 걸친 트랜잭션이나 조인이 불가능하다는 제약이 있습니다. Instacart는 PG Query를 사용하여 이러한 조인 문제를 식별하고 해결했습니다. 수평 샤딩은 테이블의 특정 행(레코드)을 샤딩 키를 기준으로 여러 샤드로 분할하는 방식입니다. 이는 대부분의 워크로드에서 샤딩 키가 존재해야 효율적이며, 샤딩 키가 없는 쿼리는 모든 샤드를 조회해야 하므로 성능 저하가 발생할 수 있습니다. Instacart는 FDW(Foreign Data Wrappers)를 사용하여 이러한 교차 샤드 쿼리를 처리합니다.

Instacart의 데이터베이스 확장 여정은 단일 데이터베이스의 최적화부터 복제본 추가, Makara에서 자체 솔루션으로의 전환, 그리고 수직 및 수평 샤딩에 이르기까지 다양한 기술적 선택을 통해 시스템을 성공적으로 확장했습니다. 이 모든 과정에서 얻은 가장 중요한 교훈은 각 시스템의 고유한 쿼리 패턴을 깊이 이해하고, 이를 바탕으로 가장 적합한 확장 전략을 수립해야 한다는 점입니다. 모든 상황에 맞는 단일한 해결책은 없으며, 지속적인 모니터링과 분석을 통해 최적의 경로를 찾아야 합니다.