IL-0390 PostHog · 2025-11-11databaseaws
PostHog US Cloud 의 Persons Postgres 데이터베이스 쓰기가 크게 느려져 이벤트와 persons 수집이 최대 2일 지연됐다
2025년 11월 11일 16:02 UTC 부터 11월 14일 15:02 UTC 까지 PostHog 의 수집 처리 파이프라인 성능이 크게 떨어져, US 리전 모든 고객의 이벤트 처리가 최대 2일 지연됐다. 원인은 Person 정보를 저장하는 Postgres 데이터베이스가 person 속성을 담는 JSONb 열과 관련해 전에 겪은 적 없는 Postgres 한계에 닿은 것이었다. PostgreSQL 은 압축 뒤 2KB 를 넘는 큰 열 값을 TOAST 테이블이라는 별도 테이블에 저장하고, 옮긴 값마다 약 40억 개 크기의 32비트 공간에서 고유한 OID 를 하나씩 할당한다. OID 는 객체 식별자이고, 전역 카운터에서 나오며 40억 개마다 한 바퀴 돈다. 이미 쓴 값이 나오면 Postgres 는 다음 값으로 다시 시도한다. PostHog 의 Persons 테이블은 properties 열이 자주 2KB 를 넘어 TOAST 값이 아주 많았다. 쓴 OID 가 한계에 가까워지자 INSERT 나 UPDATE 한 건마다 비어 있는 OID 를 찾느라 엄청난 양을 읽게 됐다. 쓰기 쿼리 하나의 디스크 읽기는 10kb 에서 15MB 로, 지연은 100배로 늘었고 이벤트 수집이 거의 멈췄다.
근본 원인은 문제가 시작되고 하루 반이 지난 11월 12일 22:17 UTC 에야 찾았다. OID 고갈은 큰 규모에서도 드물게 겪는 현상이었다. 표준 대시보드는 이것을 곧바로 가리키지 않았고, TOAST 와 OID 사용량을 보는 관측 수단도 없었다. PostHog 는 AWS RDS 팀 엔지니어와 외부 컨설턴트의 도움을 받았고, 새 파티션 테이블로 옮기는 것 말고는 방법이 없다는 결론에 이르렀다. 새 TOAST 테이블과 OID 공간을 갖는 파티션 Persons 테이블을 만들고, 트리거로 옛 테이블과 새 테이블을 맞추며 기존 데이터를 백필했다. 쓰기는 새 테이블로 보내고 읽기는 새 테이블을 먼저 보고 옛 테이블로 넘어가게 바꿨다. 장애 중 새 문제를 만들지 않으려고 웹 앱은 사람이 통제하는 배포로 내보냈다.
11월 14일 15:02 UTC 에 수집이 정상으로 돌아왔고, PostHog 는 밀린 이벤트 처리에 집중했다. 이때 AWS MSK 에서 따로 문제가 났다. MSK 의 tiered storage 는 최근 4시간치 데이터를 로컬 디스크에 두었다가 S3 로 넘긴다. 밀린 데이터를 따라잡는 동안 이 4시간치가 유난히 커져 로컬 디스크 사용률이 85% 에 닿았다. 수집을 잠시 멈추고 해당 토픽의 로컬 보존 기간을 줄인 뒤, 디스크 여유를 확인하고 수집을 다시 시작했다. 오래 걸릴 백필은 Dagster 로 옮겼다. 11월 15일 06:20 UTC 에 밀린 이벤트를 모두 처리해 완전히 복구했고, 잃은 데이터는 없었다.
- 심각도
- –
- 영향 범위
- Event and persons ingestion for US Cloud, delayed from 10 minutes up to 2 days; analytics on recent data, feature flags and experiments using person properties, filtering in error tracking and session replay, and CDP destinations and workflows were affected
- 영향 사용자
- All customers in the US region
- 지역
- US Cloud
- 감지까지
- –
- 복구까지
- 3d 14h 18m
증상
2025년 11월 11일 16:02 UTC 부터 PostHog 수집 처리 파이프라인의 성능이 크게 떨어져, US 리전 모든 고객의 이벤트 처리가 지연되기 시작했다. 고객이 최근에 보낸 이벤트가 PostHog 에 보이지 않았다.
Persons 데이터베이스의 쓰기는 TOAST 테이블에서 쓸 수 있는 OID 를 기다리느라 업데이트 한 건에 몇 초씩 걸렸다. 쓰기 쿼리 하나가 읽는 디스크 양은 10kb 에서 15MB 로 늘었고, 이 쿼리들의 지연은 100배가 됐다. 수집 파이프라인은 보통의 확장 수단으로는 손쓸 수 없을 만큼 느려졌다.
지연은 고객에 따라 10분에서 최대 2일이었다. 최근 기간이 들어간 Analytics 차트와 쿼리는 부정확했고, person 속성을 쓰는 feature flag 는 그 속성이 늦게 반영됐다. Error tracking 과 Session replay 수집은 정상이었지만 Person 업데이트로 거르는 필터는 영향을 받았고, Persons 에 기대는 CDP destination 과 Workflow 는 늦게 실행됐다.
CPU, 메모리, IOPS, 잠금 경합을 보는 표준 대시보드는 OID 고갈을 곧바로 가리키지 않았다. TOAST 테이블 크기나 OID 사용량, 특정 테이블의 쓰기당 디스크 읽기 증폭을 보는 관측 수단이 없어서, 근본 원인을 찾는 데 하루 반이 걸렸다.
11월 14일 수집이 회복된 뒤 밀린 이벤트를 처리하는 동안 AWS MSK 의 로컬 디스크 사용률이 약 85% 까지 올라 알림이 울렸다.
원인
- 촉발
- Persons 테이블의 properties 열은 자주 2KB 를 넘어 TOAST 테이블에 따로 저장되는데, 이 값마다 할당하는 32비트 OID 공간이 거의 다 찼다. 그러자 쓰기 한 건마다 비어 있는 OID 를 찾느라 이미 쓴 OID 를 길게 훑어야 했다.
감지
–
조치
- 새 TOAST 테이블과 새 OID 공간을 갖는 파티션 Persons 테이블 구조를 새로 만들었다.
- 실시간 쓰기가 옛 테이블과 새 테이블에 함께 맞춰지도록 데이터베이스 트리거를 넣었다.
- 백필 스크립트로 기존 Person 데이터를 옛 테이블에서 새 테이블로 복사했다.
- 새 쓰기는 모두 새 테이블로 가고, 옮기는 동안 읽기는 새 테이블을 먼저 본 뒤 옛 테이블로 넘어가도록 수집과 애플리케이션 로직을 바꿨다.
- 장애 중 새 문제를 만들 위험이 있어, 웹 앱은 완전 자동 롤아웃 대신 사람이 통제하는 배포로 운영에 내보냈다. 엔지니어 여럿이 주말 내내 교대로 Feature flags API, Error tracking 수집, Django 웹 애플리케이션을 고쳤다.
- 새 Persons 테이블에서 수집 성능이 돌아온 뒤, 파티션별 지연, 처리량, 자원 사용률을 지켜보며 수집 워커를 늘려 밀린 이벤트를 처리했다.
- MSK 로컬 디스크 사용률이 약 85% 에 닿자 수집을 잠시 멈췄다.
- 해당 Kafka 토픽의 로컬 보존 기간을 줄여, S3 로 넘기기 전에 디스크에 두는 데이터를 줄였다.
- 디스크 여유가 충분한 것을 확인한 뒤 수집을 다시 시작했다.
- 오래 걸리는 백필 작업을 더 잘 지켜보고 안정적으로 돌리려고 백필 과정을 Dagster 로 옮겼고, 남은 백필과 정리 작업을 주말 동안 Dagster 로 끝냈다.
후속 조치
- 쓰기마다 디스크 읽기가 크게 늘어나는 현상에 지표와 알림을 더한다.
- TOAST 테이블 통계에 지표와 알림을 더한다.
- 큰 규모에서 문제가 될 수 있는 다른 Postgres 엔진 한계에도 지표와 알림을 더한다.
- 비슷한 Postgres 엔진 수준 문제의 증상과 진단 방법을 런북으로 정리하고, 옮길지 제자리에서 고칠지 정하는 의사 결정 트리를 분명하게 넣는다.
- 고객에게 언제 어떻게 알릴지, 누구에게 에스컬레이션할지, 누가 대신 맡을지를 분명히 정한 고객 소통 런북을 새로 만든다.
- persons 데이터베이스에 다른 데이터 저장소를 쓰는 방안을 계속 검토한다.
- 새 테이블로 통합하는 작업을 마무리한다.
- 백필 도구와 Kafka tiered storage 의 안전장치를 개선한다.
- Person 과 비슷한 테이블을 처음부터 비슷한 한계에 닿지 않게 설계하고 운영한다.
교훈
Persons 테이블 하나에 analytics, feature flag, replay 필터, CDP 같은 핵심 기능 다수가 기대고 있어, 이 테이블이 느려지자 제품의 넓은 부분이 영향을 받았다. TOAST 증가, OID 사용량, 쓰기당 디스크 읽기 증폭을 보는 모니터링이 없어 OID 고갈을 원인으로 확정하는 데 하루 반쯤 걸렸다. 처음의 백필 방식은 길고 큰 마이그레이션에 필요한 가시성과 견고함이 모자라 장애 중에 Dagster 로 옮겨야 했다. MSK 디스크가 차오른 일로 tiered storage 설정과 알림이 큰 백로그 상황에 맞춰져 있지 않았다는 것이 드러났다. 평소 고객 소통을 맡는 팀원이 장애 내내 모두 자리에 없어 대신할 사람을 급히 찾아야 했다.
PostHog 는 잘된 점으로 네 가지를 꼽았다. 데이터를 잃지 않았다. 여러 팀과 외부 컨설턴트, AWS 엔지니어가 함께 드문 엔진 수준 문제를 진단했다. 시스템을 살려 둔 채 트리거와 백필로 새 Persons 테이블로 옮겼다. 엔지니어가 직접 정기적으로 상태를 알렸다.
출처
참고 문서
관련 사례
같은 원인 · 공통 메시지 브로커, 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0288CDN77 의 ClickHouse 데이터 파이프라인에서 이중화된 인스턴스 세 곳의 ZooKeeperWait 가 수천 초로 치솟아 복제가 한 시간 넘게 느려졌다CDN77 · 2026같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0305Intercom 의 PlanetScale 샤드 하나에서 복제본이 CPU 100% 로 주 데이터베이스를 따라가지 못해 받은편지함에 최대 2.2시간 전의 데이터가 보였다Intercom · 2026같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0287Atlas 와 Cloud Manager 의 모니터링을 받치는 내부 데이터베이스 클러스터의 샤드 하나가 과부하되어 지표 수집과 클러스터 작업이 늦어졌다MongoDB · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0298Wikimedia sessionstore 의 Cassandra 노드가 디스크가 가득 차 잇따라 죽고 쿼럼을 잃어 편집이 실패했다Wikimedia Foundation · 2025같은 원인 · 공통 데이터베이스
IL-0312max_connections 를 올리려고 재시작한 주 PostgreSQL 데이터베이스가 다시 올라오지 않아 Gadget 의 모든 앱 요청이 멈췄다Gadget · 2024같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0110Grafana Agent 파드가 메모리를 많이 쓰던 노드에 Hangfire 파드가 함께 올라가 시스템 OOM 으로 CrashLoopBackOff 를 반복했고, 노드가 응답을 멈추고 NotReady 가 됐다.DFDS · 2024같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0202갑자기 몰린 쿼리와 데이터베이스 쓰기로 Honeycomb 수집 호스트가 메모리 부족으로 죽었고, 쿠버네티스 CrashLoopBackOff 가 용량 회복을 막아 US1 이벤트 수집이 한 시간 넘게 불안정했다Honeycomb · 2023 · sev1같은 원인 · 공통 데이터베이스
IL-0386Google Cloud 로 옮긴 뒤 GKE 노드에서 Postgres 연결 타임아웃과 memcached i/o timeout 이 간헐적으로 튀었다incident.io · 2023같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0206GKE 파드 안의 Consul 에이전트가 메모리 급증으로 거듭 OOM kill 되어 Rails 파드가 데이터베이스 복제본을 찾지 못했고, 모든 쿼리가 primary 로 몰려 GitLab.com 이 느려졌다.GitLab · 2022같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0384US-EAST-1 의 Amazon Kinesis Data Streams 에서 레코드 읽기와 쓰기가 하루 대부분 실패했다Amazon Web Services · 2020같은 원인 · 공통 메시지 브로커
IL-0496전역 복제 Cassandra 클러스터에서 모든 리전의 인스턴스 CPU 가 100% 로 치솟아 쿼리가 타임아웃됐고, 같은 부하가 이틀 저녁 더 찾아왔다Ably · 2020같은 원인 · 공통 데이터베이스
IL-0443Aurora MySQL reader 가 이유 없이 재시작한 뒤 writer 의 insert latency 가 7배쯤 오르고 replication lag 가 하루 넘게 이어졌다Repro · 2019같은 원인 · 공통 데이터베이스
IL-0037imagePullPolicy가 Always인 DaemonSet이 크래시 루프를 돌며 이미지를 계속 받아, NAT 세 대를 같이 쓰던 리전 전체가 이미지 레지스트리에서 429로 막혔다Datadog · 2019같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0211Mandrill 의 PostgreSQL 샤드 하나가 트랜잭션 ID 랩어라운드를 막으려고 쓰기를 멈춰 약 40시간 동안 메일 발송이 줄었다Mailchimp · 2019같은 원인 · 공통 데이터베이스
IL-0064CPU 를 많이 쓰는 파드가 Google Cloud 노드 하나에 몰려 노드가 커널 패닉으로 죽었고, 다시 배치된 파드가 다음 노드를 또 죽이며 웹사이트와 API 가 멈췄다.Moonlight · 2019같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0334RDS MySQL 의 bookmarks 테이블이 2TB 파일 크기 한도에 닿아 INSERT 가 실패하고 Instapaper 가 31시간 동안 멈췄다Instapaper · 2017같은 원인 · 공통 데이터베이스
IL-0333사양을 낮춘 RDS PostgreSQL 인스턴스가 피크 부하를 못 버텨 헬스 체크가 실패하고 Buildkite 대시보드가 몇 시간 동안 내려갔다Buildkite · 2016같은 원인 · 공통 데이터베이스
IL-0282US-East 리전의 DynamoDB 스토리지 서버들이 멤버십 정보를 받지 못해 스스로 요청 처리에서 빠지면서 고객 요청의 약 55% 가 실패했다Amazon Web Services · 2015같은 원인 · 공통 데이터베이스
IL-0275Kafka 브로커들이 네트워크 한계에 닿아 줄줄이 쓰러지면서 Parse.ly 의 데이터 처리가 멈추고 대시보드에 몇 시간 동안 새 데이터가 나오지 않았다Parse.ly · 2015같은 원인 · 공통 메시지 브로커
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0390
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0390/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.