IL-0333 Buildkite · 2016-08-22databaseaws
사양을 낮춘 RDS PostgreSQL 인스턴스가 피크 부하를 못 버텨 헬스 체크가 실패하고 Buildkite 대시보드가 몇 시간 동안 내려갔다
Buildkite 는 AWS Activate 프로그램에서 받은 크레딧이 곧 떨어진다는 것을 약 2주 전에 알고 AWS 비용을 서둘러 줄이려 했다. 가장 큰 비용은 m4.10xlarge Multi-AZ RDS PostgreSQL 데이터베이스였고, 팀은 이를 r3.2xlarge Multi-AZ 인스턴스로 낮추기로 했다. 팀은 시간에 쫓겨 새 데이터베이스가 큰 부하를 버틸지 확인하지 않았고 부하 시험도 하지 않았다. 주말 유지 보수 시간에 사양을 낮춘 뒤 성능은 괜찮아 보였다. 새 데이터베이스는 메모리가 적어서, 연결 하나당 메모리를 줄이려고 서버마다 두던 pgbouncer 를 중앙 pgbouncer 하나로 바꿨다. 가장 큰 고객들은 미국에 있었고, 팀은 미국 피크가 시작된다고 생각한 시간까지 지켜본 뒤 잠자리에 들었다.
2016년 8월 22일 16:00 UTC 무렵 데이터베이스의 CPU 사용률이 최대치에 머물렀다. 데이터베이스까지 확인하던 헬스 체크가 HTTP 500 을 내자 대시보드용 ELB 가 서버를 뺐다. 17:21 UTC 부터 로그인, 빌드 로그, 문서가 모두 막혔다. 새 서버는 https://buildkite.com/_secret/version 엔드포인트에서 배포할 리비전을 받지 못해 AMI 에 든 옛 코드로 떴다. 그 코드의 헬스 체크가 폐기된 데이터베이스를 가리켜, 새 서버는 몇 시간 동안 떴다 종료되기를 반복했다. 그동안 PagerDuty 알림은 아무도 깨우지 못했다. 온콜 담당자의 설정에서 "Immediately phone me" 규칙이 빠져 소리 없는 푸시 알림만 갔다. 에스컬레이션을 받을 다른 팀원들은 휴대폰을 무음으로 두었다.
팀은 21:00 UTC 에 깨어 문제를 파악했다. 데이터베이스 사양을 올리려 했지만 AWS 의 IAM 문제로 AWS Console 이 변경을 받지 않았고, 새 AMI 도 띄울 수 없었다. 팀은 Agent API 서버 일부를 대시보드용 ELB 로 옮겨 22:28 UTC 에 buildkite.com 을 다시 올렸지만 응답은 느렸다. IAM 문제가 풀린 뒤에는 서버가 계속 떴다 내려간 탓에 EC2 요청 한도에 걸려 기다려야 했다. 결국 aws-cli 로 데이터베이스를 부하를 감당할 인스턴스 유형으로 올렸다. 스스로 배포하는 문제를 고친 새 서버도 내보냈다. 그리고 중앙 pgbouncer 를 없애고 호스트마다 pgbouncer 를 두던 구성으로 되돌렸다. 23:10 UTC 에 완전히 복구했다.
- 심각도
- –
- 영향 범위
- buildkite.com dashboard down: no login, no build logs, no documentation; builds kept running and pull request statuses kept updating; slow responses and dropped requests from 22:28 to 23:10 UTC
- 영향 사용자
- –
- 지역
- –
- 감지까지
- 3h 39m
- 복구까지
- 5h 49m
증상
2016년 8월 22일 17:21 UTC 부터 buildkite.com 에 아무도 로그인하지 못했고 빌드 로그와 문서도 볼 수 없었다. 빌드는 계속 돌았고 GitHub 와 Bitbucket 의 Pull Request 상태도 계속 갱신됐다.
멜버른에 있던 팀은 자고 있었다. 팀은 약 4시간 뒤인 21:00 UTC 에 깨어 Buildkite 가 내려갔다는 이메일, 트윗, Slack 메시지로 가득 찬 휴대폰을 봤다.
16:00 UTC 무렵부터 사양을 새로 낮춘 데이터베이스가 부하를 따라가지 못했고 CPU 사용률이 최대치에 머물렀다. 이 성능 문제가 다른 문제를 줄줄이 일으켰다.
ELB 는 30초마다 애플리케이션에 HTTP 요청을 보내 헬스 체크를 한다. 헬스 체크 엔드포인트는 SQL 데이터베이스 두 개와 Redis, Memcache 를 확인한다. 이 엔드포인트가 데이터베이스에 접속하지 못해 HTTP 500 을 내기 시작했다. 대시보드 요청을 받는 ELB 는 실패 기준이 훨씬 낮아 서버를 자동으로 빼고 "OutOfService" 로 표시했다. Agent API 와 REST API 의 ELB 도 문제가 있었지만 서버는 남아 있었다.
빠진 서버를 대신할 새 서버도 헬스 체크를 통과하지 못했다. 새 서버는 https://buildkite.com/_secret/version 에서 최신 Git 리비전을 받아 스스로 배포한다. 그런데 buildkite.com 이 내려가 있어 리비전을 받지 못했고, AMI 에 들어 있던 옛 코드로 떴다. 옛 코드의 헬스 체크는 이미 폐기한 데이터베이스 Job::Log::Chunk::Shard::One 을 가리켰다. 몇 시간 동안 새 서버가 떴다가 헬스 체크 실패로 곧바로 종료되기를 반복했다.
팀이 데이터베이스 사양을 올리려 하자 AWS 의 IAM 문제로 AWS Console 이 변경을 받아 주지 않았다. 새 AMI 를 시험하려고 띄울 때는 IAM 역할 선택기가 동작하지 않았고 AWS Console 에 "Internal server error" 가 계속 떴다. IAM 문제가 가라앉은 뒤 EC2 서버를 띄우려 했지만, 서버가 계속 떴다 내려간 탓에 이미 EC2 요청 한도에 걸려 있었다.
22:28 UTC 에 임시 조치로 buildkite.com 이 다시 올라왔지만, 데이터베이스가 여전히 부하에 눌려 응답이 매우 느렸고 일부 요청은 버려졌다.
원인
원인 용량 한계
- 촉발
- AWS 크레딧이 곧 떨어질 상황이라 비용을 줄이려고, 주말 유지 보수 시간에 m4.10xlarge Multi-AZ RDS PostgreSQL 데이터베이스를 r3.2xlarge 로 낮췄다. 연결 하나당 메모리를 줄이려고 중앙 pgbouncer 로도 옮겼다. 월요일 미국 피크 시간에 이 데이터베이스가 부하를 버티지 못했다.
감지
New Relic, Pingdom, Datadog, Calibre, CloudWatch 가 문제를 감지하면 PagerDuty 알림이 온콜 개발자에게 전화를 건다. 하지만 온콜 담당자의 PagerDuty 설정에서 "Immediately phone me" 규칙이 빠져 소리 없는 푸시 알림만 갔다. 에스컬레이션을 받을 다른 팀원들은 휴대폰을 무음으로 두어 아무도 깨지 않았다. 팀은 21:00 UTC 에 깨어 이메일, 트윗, Slack 메시지로 장애를 알았다.
조치
- Agent API 서버 일부를 빼서 대시보드 요청을 받는 ELB 에 연결해 buildkite.com 을 다시 올렸다. 데이터베이스가 여전히 부하에 눌려 있어 요청은 느렸다.
- EC2 요청 한도에 걸린 뒤 Auto Scaling Group 의 헬스 체크를 EC2 헬스 체크로 바꾸고 원하는 서버 수를 고정했다.
- AWS Console 이 여전히 문제가 있어 aws-cli 로 데이터베이스를 부하를 감당할 수 있는 인스턴스 유형으로 올렸다.
- https://buildkite.com/_secret/version 을 참조하지 않는 새 AMI 를 만들고, 스스로 배포하는 문제를 고친 새 서버를 aws-cli 로 내보냈다.
- 중앙 pgbouncer 서버를 없애고, 잘 동작하던 이전 구성대로 호스트마다 pgbouncer 를 다시 두었다.
후속 조치
- 다른 사용자에게 영향을 주지 않고 큰 인프라 변경 뒤 부하 시험을 하는 방법을 계획한다.
- 헬스 체크가 애플리케이션에 닿기만 하면 "OK" 를 내도록 바꿨다. 이 요청에서는 더 이상 데이터베이스 연결을 확인하지 않는다.
- 애플리케이션이 데이터베이스와 의존 서비스에 접속되는지 확인하는 헬스 체크 엔드포인트를 따로 두고 Pingdom 이 호출하게 하는 방안을 검토한다.
- 최근 배포된 리비전을 S3 의 파일에 저장하고, 새로 뜬 서버가 스스로 배포할 때 그 파일을 참조하게 바꿨다.
- 팀원 모두가 PagerDuty 전화가 실제로 오는지 수동으로 시험했다.
- 모든 팀원의 설정이 맞는지 정기적으로 확인하는 회사 전체 시험을 할 수 있는지 알아본다.
- 팀원이 온콜에 들어갈 때 PagerDuty 가 전화를 걸게 하거나, 모든 Notification Rules 에 "Immediately phone" 규칙을 두도록 요구하는 방안을 PagerDuty 에 문의한다.
교훈
AWS 크레딧을 미리 지켜봐야 짧은 기간에 큰 인프라 변경을 서두르지 않는다. 크레딧을 쓰는 동안 AWS Billing Reports 는 0달러 청구서를 보여 줘서 실제 비용을 알기 어렵다. 큰 인프라 변경 뒤에는 부하 시험을 해야 한다. 헬스 체크가 실제로 무엇을 확인해야 하는지 다시 생각해야 한다. 의존하는 서버에 모두 접속되는지 확인하던 헬스 체크는 ELB 의 모든 서버가 실패할 때 어떻게 되는지 고려하지 않았다. 새 서버가 배포할 리비전을 자기 서비스에 물어보는 방식은 쓰면 안 된다. 온콜에 들어가기 전에 모든 팀원의 PagerDuty 와 iPhone 설정이 맞는지 확인해야 한다. AWS 에서 서버가 계속 떴다 내려가면 헬스 체크와 오토스케일링 규칙을 멈춰 EC2 요청 한도에 걸리지 않게 해야 한다. 팀은 사후 분석을 쓰면서 AWS 에서 Auto Scaling 프로세스를 일시 중지하고 재개할 수 있다는 것을 알았다.
출처
참고 문서
관련 사례
같은 원인 · 공통 데이터베이스, 라이브니스·레디니스 프로브
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0288CDN77 의 ClickHouse 데이터 파이프라인에서 이중화된 인스턴스 세 곳의 ZooKeeperWait 가 수천 초로 치솟아 복제가 한 시간 넘게 느려졌다CDN77 · 2026같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0305Intercom 의 PlanetScale 샤드 하나에서 복제본이 CPU 100% 로 주 데이터베이스를 따라가지 못해 받은편지함에 최대 2.2시간 전의 데이터가 보였다Intercom · 2026같은 원인 · 공통 데이터베이스
IL-0390PostHog US Cloud 의 Persons Postgres 데이터베이스 쓰기가 크게 느려져 이벤트와 persons 수집이 최대 2일 지연됐다PostHog · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 라이브니스·레디니스 프로브
같은 원인 · 공통 데이터베이스
IL-0287Atlas 와 Cloud Manager 의 모니터링을 받치는 내부 데이터베이스 클러스터의 샤드 하나가 과부하되어 지표 수집과 클러스터 작업이 늦어졌다MongoDB · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0558새 인스턴스 유형이 네트워크 연결 한도에 걸려 PubNub FRA 리전의 Pub/Sub, History, Presence 에서 간헐적으로 오류와 지연이 늘었다PubNub · 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-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-0282US-East 리전의 DynamoDB 스토리지 서버들이 멤버십 정보를 받지 못해 스스로 요청 처리에서 빠지면서 고객 요청의 약 55% 가 실패했다Amazon Web Services · 2015같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0333
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0333/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.