IL-0229 bunny.net · 2021-06-22networking
손상된 SmartEdge 데이터 파일을 받은 bunny.net 의 전 세계 DNS 서버가 크래시를 되풀이해 플랫폼 대부분이 2시간 넘게 멈췄다.
bunny.net 의 SmartEdge 라우팅 시스템은 많은 양의 데이터를 주기적으로 DNS 노드에 동기화하고, 이 큰 데이터베이스 파일을 Edge Storage 와 Bunny CDN 으로 전 세계에 나른다. bunny.net 은 메모리와 트래픽, 가비지 컬렉터 할당을 줄이려고 얼마 전 JSON 대신 BinaryPack 이라는 바이너리 직렬화 라이브러리를 쓰기 시작했다. 2021-06-22 UTC 8:25 에 최적화 데이터베이스의 다운로드 크기를 줄이는 업데이트가 손상된 파일을 Edge Storage 에 올렸다. DNS 서버는 데이터가 없어도 돌고 예외를 무시하도록 만들어져 있었다. 하지만 손상된 파일이 BinaryPack 에서 stack overflow 예외를 일으켰고, 이 예외는 예외 처리를 건너뛰고 프로세스를 종료시켰다. 몇 분 만에 전 세계에 있는 100대 가까운 DNS 서버가 거의 모두 죽었다. bunny.net 은 트래픽의 60% 넘게 잃었고, 750,000개가 넘는 웹사이트가 영향을 받았다.
팀은 SmartEdge 업데이트를 곧바로 롤백했다. 하지만 SmartEdge 와 배포 시스템이 기대는 Edge Storage 와 CDN 이 이미 무너져, DNS 서버는 수정본을 받지 못한 채 크래시를 되풀이했다. 8:45 에 SmartEdge 를 끄는 업데이트를 손으로 배포했지만, DNS 서버가 손상된 GeoDNS 데이터베이스를 내려받아 모든 요청이 작은 Madrid PoP 로 몰렸다. 서버 100대가 루프를 돌며 다시 시작하면서 중앙 API 도 크래시했다.
9:40 무렵 팀은 모든 요청을 가장 큰 리전인 Frankfurt 로 보내는 라우팅 업데이트를 DNS 서버 몇 대에 손으로 배포해 트래픽 일부를 되찾았다. 이어 자체 시스템을 아예 쓰지 않기로 하고 배포 시스템과 파일을 외부 클라우드 스토리지 서비스로 옮겼다. 10:15 에 배포 시스템과 DNS 소프트웨어를 새 스토리지에 연결해 배포했고, 10:30 에 트래픽이 돌아왔다. 하지만 서두르다 잘못된 GeoDNS 데이터베이스 버전을 배포해 요청이 여전히 Madrid 로 갔다. 10:45 에 모든 것을 다시 확인하고 데이터베이스를 동기화해 최신 파일 세트를 배포했다. SmartEdge 없이 캐시되지 않은 데이터를 많이 내보내느라 스토리지가 한계까지 몰렸다. 11:00 에 상황이 안정되기 시작했고, bunny.net 은 복구 모드로 서비스를 다시 열었다.
- 심각도
- –
- 영향 범위
- bunny.net DNS, CDN, storage, optimizer service, API, dashboard and logging; over 60% of traffic lost
- 영향 사용자
- over 750,000 websites
- 지역
- global
- 감지까지
- 10m
- 복구까지
- 2h 35m
증상
2021-06-22 UTC 8:25 에 업데이트를 내보내고 몇 분 만에 전 세계에 있는 100대 가까운 bunny.net DNS 서버가 거의 모두 죽었다. bunny.net 은 트래픽의 60% 넘게 잃었고, 수백 Gbit 의 처리량이 사라졌으며, 750,000개가 넘는 웹사이트가 영향을 받았다.
팀은 무슨 일인지 알아채는 데 시간이 걸렸다. 10분이 지나서야 DNS 서버가 다시 시작했다가 죽기를 되풀이하고 있고, 이 상태로는 되살릴 방법이 없다는 것을 알았다. DNS 서버는 데이터가 있든 없든 돌고 예외를 무시하도록 만들어져 있었다. 하지만 손상된 파일을 읽은 BinaryPack 직렬화 라이브러리가 stack overflow 예외를 일으켰고, 이 예외는 예외 처리를 건너뛰고 프로세스를 그대로 종료시켰다.
팀은 버튼 하나로 배포를 롤백할 수 있었고 SmartEdge 업데이트를 곧바로 모두 롤백했지만 이미 늦었다. SmartEdge 와 배포 시스템은 Edge Storage 와 Bunny CDN 으로 DNS 서버에 데이터를 나르는데, 이 CDN 용량 대부분이 이미 사라진 상태였다. DNS 서버는 스스로 다시 뜰 때마다 깨진 배포를 읽고 다시 크래시해 CDN 에서 수정본을 내려받지 못했다.
UTC 8:35 에는 서버 몇 대만 요청을 버티고 있었고, 트래픽 대부분을 잃어 100Gbit 까지 떨어졌다. 하루 중 트래픽이 가장 적은 시간대였다.
8:45 에 SmartEdge 를 끄는 업데이트를 손으로 배포하자 잠시 동작하는 것처럼 보였다. 하지만 CDN 장애 때문에 DNS 서버가 손상된 GeoDNS 데이터베이스를 내려받았고, 모든 요청이 가장 작은 PoP 가운데 하나인 Madrid 로 몰려 Madrid 가 금방 무너졌다. 100대의 서버가 루프를 돌며 다시 시작하자 중앙 API 가 크래시했고, 되살린 서버도 제대로 시작하지 못했다. 팀은 네트워킹을 다시 세우려고 여러 번 시도하다 포기했다.
장애는 DNS 에서 CDN, 스토리지, optimizer 서비스로 번졌다. 수백 대의 서버가 다시 올라오는 동안 API 와 대시보드가 크래시했고, 마지막에는 로깅 서비스도 크래시했다.
원인
- 촉발
- 2021-06-22 UTC 8:25 에 최적화 데이터베이스의 다운로드 크기를 줄이려는 업데이트가 손상된 파일을 Edge Storage 에 올렸다. DNS 서버가 이 파일을 읽자 BinaryPack 직렬화 라이브러리가 stack overflow 예외를 일으켰고, 예외 처리를 건너뛴 채 DNS 프로세스가 종료됐다.
감지
팀은 무슨 일인지 알아채는 데 시간이 걸렸다. 업데이트 10분 뒤에야 DNS 서버가 다시 시작했다가 죽기를 되풀이하고 있고, 이 상태로는 되살릴 방법이 없다는 것을 알았다.
조치
- UTC 8:45 에 SmartEdge 시스템을 끄는 업데이트를 DNS 노드에 손으로 배포했다. 하지만 손상된 GeoDNS 데이터베이스 때문에 요청이 Madrid 로 몰렸다.
- 9:40 무렵 임시 조치로 모든 요청을 가장 큰 리전인 Frankfurt 로 보내는 라우팅 업데이트를 준비해 DNS 서버 몇 대에 손으로 배포했다. 트래픽의 상당 부분이 돌아왔다.
- 자체 시스템을 쓰지 않으려고 배포 시스템과 파일을 모두 외부 클라우드 스토리지 서비스로 옮겼다.
- 10:15 에 배포 시스템과 DNS 소프트웨어를 새 스토리지에 연결하도록 바꾸고 배포했다. 10:30 에 트래픽이 돌아왔지만 잘못된 GeoDNS 데이터베이스 버전 때문에 요청은 여전히 Madrid 로 갔다.
- 10:45 에 외부 서비스를 거쳐 데이터베이스를 동기화하고 최신 파일 세트를 배포해 서비스를 되살렸다. 11:00 에 상황이 안정되기 시작했다.
후속 조치
- 긴급 수정으로 BinaryPack 라이브러리를 단계적으로 걷어 낸다.
- 앞으로 쓰는 외부 라이브러리를 더 폭넓게 시험한다.
- 내부 API 를 외부의 독립 서비스로 완전히 옮긴다. 그 서비스가 내려가면 업데이트를 못 하지만, bunny.net 시스템이 내려가도 무너지는 인프라에 갇히지 않고 빠르게 대응할 수 있다.
- 중요하지 않다고 본 소프트웨어 하나가 여러 클러스터에 걸친 단일 장애 지점이 되지 않게 하는 방법을 조사한다.
- DNS 시스템이 모든 백업 데이터의 로컬 사본을 갖추고 장애를 자동으로 감지하게 해, 시스템끼리 최대한 독립시키고 장애가 연쇄로 번지지 않게 한다.
교훈
bunny.net 은 내부 인프라의 핵심 부분까지 모든 시스템이 서로 기대도록 설계했다. 그 때문에 손상된 파일 하나가 여러 겹의 이중화를 무너뜨리고 복구할 길까지 막았다. 자체 인프라를 자기 생태계 안에 지으면 한 곳의 장애가 연쇄로 번질 수 있다. 업데이트는 카나리 방식으로 잘게 배포하려 했지만, 중요하지 않다고 본 소프트웨어 하나가 여러 클러스터에 동시에 걸친 단일 장애 지점이 됐다. 급하게 고치는 동안 오타와 실수가 늘었고, 결국 침착하게 모든 것을 다시 확인한 뒤의 마지막 배포로 복구했다.
출처
관련 사례
같은 원인 · 공통 DNS 서버와 레코드
같은 원인 · 공통 DNS 서버와 레코드
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0229
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0229/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.