figma

사후 분석: 202 (새 탭에서 열림)

2020년 1월 21~22일 Figma 장애는 장시간 실행된 고비용 쿼리와 PostgreSQL의 잘못된 쿼리 실행 계획, 그리고 이로 인해 누적된 공격적 autovacuum이 복합적으로 발생한 사건이었다. 1월 21일에는 문제 쿼리를 취소해 복구했지만, 그 여파로 데이터베이스 정리 작업이 밀리면서 다음 날 쓰기 IOPS와 잠금 경합이 급증했다. Figma는 PostgreSQL 11로 업그레이드해 문제를 안정화했고, 이후 고비용 쿼리 모니터링과 실행 시간 제한을 강화하기로 했다.

장애 발생 경과

1월 21일: 장시간 실행 쿼리

  • 오전 6시 11분, 자동 모니터링에서 오류율 증가를 감지했다.
  • 조사 결과, 데이터베이스 CPU를 과도하게 사용하는 장시간 실행 쿼리가 발견됐다.
  • 오전 6시 54분 해당 쿼리를 취소하자 성능이 정상으로 돌아왔다.
  • 그러나 쿼리 취소 과정에서 데이터베이스 내부에 정리해야 할 작업이 누적되었고, 이것이 다음 날 장애의 배경이 됐다.

1월 22일: 쓰기 부하와 잠금 경합

  • 데이터베이스 CPU는 평소보다 낮았지만 쓰기 IOPS와 잠금 경합이 증가했다.
  • 오전 11시 42분에는 API 요청이 대기열에 쌓이며 일부 사용자가 서비스를 이용할 수 없게 됐다.
  • 불필요한 쿼리를 취소하고 할당된 IOPS를 늘려 일시적으로 안정화했지만, 오후 2시경 다시 성능이 악화됐다.
  • 데이터베이스를 재시작해 문제를 일으킨 것으로 추정한 백그라운드 프로세스를 임시 비활성화했다.
  • 오후 7시부터 긴급 점검을 진행하며 PostgreSQL을 업그레이드했고, 오후 8시 15분 서비스와 데이터베이스 지표가 정상화됐다.

공격적 autovacuum의 영향

  • PostgreSQL의 autovacuum은 오래된 행 버전을 정리하고 트랜잭션 ID 고갈을 방지하는 자동 유지보수 작업이다.
  • 1월 21일 장시간 쿼리가 종료된 뒤 정리 대상 데이터가 대량으로 쌓였다.
  • 이 backlog가 임계치를 넘으면서 트랜잭션 ID 래핑을 막기 위한 더 공격적인 autovacuum이 실행됐다.
  • 당시 사용하던 PostgreSQL 버전에서는 이 작업이 테이블 잠금과 쓰기 작업에 큰 영향을 줬다.
  • Figma가 대형 테이블에서 실행 중인 autovacuum을 취소하자 지표가 일시적으로 개선됐지만, 작업은 다시 재개됐다.
  • autovacuum_freeze_max_age 값을 조정하고 데이터베이스를 재시작해야 공격적 autovacuum을 완전히 억제할 수 있었다.
  • 다만 autovacuum을 비활성화한 뒤에도 쓰기 지연과 잠금 경합이 계속되어, 이것만이 유일한 원인은 아니라고 판단했다.

잘못된 쿼리 실행 계획

  • 문제의 핵심 쿼리는 복잡한 서브쿼리를 포함하고 있었고, 잠금 경합에 반복적으로 관여했다.
  • PostgreSQL 9의 통계 정보가 변경된 뒤 쿼리 플래너가 비효율적인 실행 계획을 선택한 것으로 분석됐다.
  • 실행 계획은 실제 결과가 3개 행뿐인데도 2천만 개 이상의 행을 반환할 것으로 잘못 추정했다.
  • 그 결과 인덱스를 사용하지 않고 전체 테이블 스캔을 수행했다.
  • 처리 과정에서 임시 버퍼에 대량의 데이터를 기록해 높은 쓰기 IOPS와 임시 데이터 사용량을 유발했다.
  • 즉, 낮은 CPU 사용률만으로 데이터베이스 상태가 양호하다고 판단하기 어려웠으며, 쓰기 지연·잠금·임시 버퍼 사용량을 함께 살펴야 했다.

PostgreSQL 11 업그레이드

  • PostgreSQL 9.6 이후에는 autovacuum과 관련된 중요한 최적화가 포함됐다.
  • PostgreSQL 10 이상에서는 Amazon RDS의 성능 분석 도구가 개선되어 원인 조사에 도움이 된다.
  • Figma는 이미 스테이징 환경을 PostgreSQL 11로 업그레이드하고 수개월간 테스트한 상태였다.
  • 운영 환경 업그레이드 절차도 사전에 마련해 두었기 때문에 긴급 상황에서도 업그레이드를 진행할 수 있었다.
  • PostgreSQL 11의 개선된 쿼리 플래너는 문제가 된 실행 계획이 선택될 가능성을 제거했다.
  • autovacuum의 성능 특성도 PostgreSQL 9에서 11로 오면서 개선되어 두 가지 주요 원인을 함께 완화했다.

후속 조치

  • 고비용·장시간 실행 쿼리에 대한 모니터링을 강화한다.
  • 쿼리가 실행될 수 있는 시간에 더 엄격한 제한을 둔다.
  • 실행 계획의 예상 행 수와 실제 행 수 사이의 큰 차이를 지속적으로 점검한다.
  • CPU뿐 아니라 쓰기 IOPS, 쓰기 지연, 잠금 경합, 임시 버퍼 사용량, autovacuum backlog를 함께 모니터링해야 한다.
  • 데이터베이스 버전 업그레이드는 장애 발생 후 처음 검토하기보다, 스테이징 테스트와 운영 전환 계획을 미리 준비해야 한다.

실무적으로는 장시간 쿼리에 타임아웃을 설정하고, 정기적으로 EXPLAIN ANALYZE와 실행 계획 변화를 검토하며, autovacuum 상태를 별도 지표로 관리하는 것이 중요하다. alc-vesm.