{"id":"IL-0229","org":"bunny.net","date":"2021-06-22","docs":[],"title":{"en":"bunny.net's DNS servers crashed in a loop on a corrupted routing database file and could not fetch a fix from its CDN","ko":"손상된 SmartEdge 데이터 파일을 받은 bunny.net 의 전 세계 DNS 서버가 크래시를 되풀이해 플랫폼 대부분이 2시간 넘게 멈췄다."},"domain":["networking"],"impact":{"scope":"bunny.net DNS, CDN, storage, optimizer service, API, dashboard and logging; over 60% of traffic lost","users":"over 750,000 websites","region":"global"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"bunny.net had built its systems to rely on each other, including the critical parts of its internal infrastructure, so one corrupted file brought down several layers of redundancy with no way back. A part of the infrastructure treated as non-critical turned out to be a single point of failure for several clusters at once, which canary deployments did not catch. Building infrastructure inside its own ecosystem lets one failure cascade through all of it. In the rush to fix the outage the team made typos and mistakes, and the final deployment came after it calmed down and double-checked everything.","ko":"bunny.net 은 내부 인프라의 핵심 부분까지 모든 시스템이 서로 기대도록 설계했다. 그 때문에 손상된 파일 하나가 여러 겹의 이중화를 무너뜨리고 복구할 길까지 막았다. 자체 인프라를 자기 생태계 안에 지으면 한 곳의 장애가 연쇄로 번질 수 있다. 업데이트는 카나리 방식으로 잘게 배포하려 했지만, 중요하지 않다고 본 소프트웨어 하나가 여러 클러스터에 동시에 걸친 단일 장애 지점이 됐다. 급하게 고치는 동안 오타와 실수가 늘었고, 결국 침착하게 모든 것을 다시 확인한 뒤의 마지막 배포로 복구했다."},"related":[],"sources":[{"url":"https://bunny.net/blog/the-stack-overflow-of-death-dns-collapse/","kind":"blog","archived":null}],"summary":{"en":"SmartEdge, bunny.net's routing system, periodically syncs large database files to the DNS nodes, using the Edge Storage platform to distribute them around the world through Bunny CDN. A few weeks earlier SmartEdge had switched from JSON to the binary serialization library BinaryPack to reduce memory, traffic and garbage collector allocations. The corrupted file crashed the DNS process through a stack overflow in BinaryPack. Because the deployment systems and SmartEdge both depended on the CDN that the DNS failure had taken down, the rollback and later fixes could not reach the DNS servers, and auto-healing restarts kept loading the broken data. A manual update at 8:45 that disabled SmartEdge on the DNS nodes made the servers download corrupted GeoDNS databases, so all requests went to the small Madrid PoP, and 100 servers restarting in a loop crashed the central API.\n\nAt around 9:40 the team prepared a routing update that sent all requests to Frankfurt, the biggest region, instead of Madrid, and deployed it by hand to a couple of DNS servers, which brought back a portion of the traffic. The team then moved all deployment systems and files to a third-party cloud storage service, and at 10:15 rewired the deployment system and DNS software to use it and deployed. Traffic was back by 10:30, but in the rush an incorrect GeoDNS database version had been deployed and requests still went to Madrid. At 10:45 the team synced the databases and deployed the newest file sets through the third-party service. With SmartEdge off, storage was pushed to its limits serving uncached data, and the platform stabilised at 11:00 in recovery mode. The outage lasted more than two hours and affected over 750,000 websites.","ko":"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개가 넘는 웹사이트가 영향을 받았다.\n\n팀은 SmartEdge 업데이트를 곧바로 롤백했다. 하지만 SmartEdge 와 배포 시스템이 기대는 Edge Storage 와 CDN 이 이미 무너져, DNS 서버는 수정본을 받지 못한 채 크래시를 되풀이했다. 8:45 에 SmartEdge 를 끄는 업데이트를 손으로 배포했지만, DNS 서버가 손상된 GeoDNS 데이터베이스를 내려받아 모든 요청이 작은 Madrid PoP 로 몰렸다. 서버 100대가 루프를 돌며 다시 시작하면서 중앙 API 도 크래시했다.\n\n9:40 무렵 팀은 모든 요청을 가장 큰 리전인 Frankfurt 로 보내는 라우팅 업데이트를 DNS 서버 몇 대에 손으로 배포해 트래픽 일부를 되찾았다. 이어 자체 시스템을 아예 쓰지 않기로 하고 배포 시스템과 파일을 외부 클라우드 스토리지 서비스로 옮겼다. 10:15 에 배포 시스템과 DNS 소프트웨어를 새 스토리지에 연결해 배포했고, 10:30 에 트래픽이 돌아왔다. 하지만 서두르다 잘못된 GeoDNS 데이터베이스 버전을 배포해 요청이 여전히 Madrid 로 갔다. 10:45 에 모든 것을 다시 확인하고 데이터베이스를 동기화해 최신 파일 세트를 배포했다. SmartEdge 없이 캐시되지 않은 데이터를 많이 내보내느라 스토리지가 한계까지 몰렸다. 11:00 에 상황이 안정되기 시작했고, bunny.net 은 복구 모드로 서비스를 다시 열었다."},"trigger":{"en":"At 8:25 AM UTC bunny.net released an update meant to reduce the download size of the SmartEdge optimization database, and it uploaded a corrupted file to Edge Storage.","ko":"2021-06-22 UTC 8:25 에 최적화 데이터베이스의 다운로드 크기를 줄이려는 업데이트가 손상된 파일을 Edge Storage 에 올렸다. DNS 서버가 이 파일을 읽자 BinaryPack 직렬화 라이브러리가 stack overflow 예외를 일으켰고, 예외 처리를 건너뛴 채 DNS 프로세스가 종료됐다."},"severity":"unknown","symptoms":["crash-loop","dns-resolution-failures","service-unavailable","requests-misrouted","uneven-load"],"timeline":{"detected_after":"10m","resolved_after":"2h 35m"},"date_kind":"incident","detection":{"en":"About 10 minutes after the release, the team realised that the DNS servers were restarting and dying.","ko":"팀은 무슨 일인지 알아채는 데 시간이 걸렸다. 업데이트 10분 뒤에야 DNS 서버가 다시 시작했다가 죽기를 되풀이하고 있고, 이 상태로는 되살릴 방법이 없다는 것을 알았다."},"components":["dns-server","cdn","object-storage"],"root_cause":"deploy-rollout","remediation":[{"text":{"en":"Deployed by hand an update that disabled the SmartEdge system on the DNS nodes","ko":"UTC 8:45 에 SmartEdge 시스템을 끄는 업데이트를 DNS 노드에 손으로 배포했다. 하지만 손상된 GeoDNS 데이터베이스 때문에 요청이 Madrid 로 몰렸다."}},{"text":{"en":"Routed all requests through Frankfurt instead of Madrid on a couple of DNS servers","ko":"9:40 무렵 임시 조치로 모든 요청을 가장 큰 리전인 Frankfurt 로 보내는 라우팅 업데이트를 준비해 DNS 서버 몇 대에 손으로 배포했다. 트래픽의 상당 부분이 돌아왔다."}},{"text":{"en":"Migrated the deployment systems and files to a third-party cloud storage service","ko":"자체 시스템을 쓰지 않으려고 배포 시스템과 파일을 모두 외부 클라우드 스토리지 서비스로 옮겼다."}},{"text":{"en":"Rewired the deployment system and DNS software to the new storage and deployed","ko":"10:15 에 배포 시스템과 DNS 소프트웨어를 새 스토리지에 연결하도록 바꾸고 배포했다. 10:30 에 트래픽이 돌아왔지만 잘못된 GeoDNS 데이터베이스 버전 때문에 요청은 여전히 Madrid 로 갔다."}},{"text":{"en":"Synced the databases and deployed the newest file sets through the third-party service","ko":"10:45 에 외부 서비스를 거쳐 데이터베이스를 동기화하고 최신 파일 세트를 배포해 서비스를 되살렸다. 11:00 에 상황이 안정되기 시작했다."}}],"action_items":[{"text":{"en":"Phase out the BinaryPack library as a hot-fix","ko":"긴급 수정으로 BinaryPack 라이브러리를 단계적으로 걷어 낸다."}},{"text":{"en":"Test third-party libraries more extensively","ko":"앞으로 쓰는 외부 라이브러리를 더 폭넓게 시험한다."}},{"text":{"en":"Migrate the internal APIs to an independent third-party service","ko":"내부 API 를 외부의 독립 서비스로 완전히 옮긴다. 그 서비스가 내려가면 업데이트를 못 하지만, bunny.net 시스템이 내려가도 무너지는 인프라에 갇히지 않고 빠르게 대응할 수 있다."}},{"text":{"en":"Find how to stop non-critical software from becoming a single point of failure across clusters","ko":"중요하지 않다고 본 소프트웨어 하나가 여러 클러스터에 걸친 단일 장애 지점이 되지 않게 하는 방법을 조사한다."}},{"text":{"en":"Make the DNS system keep a local copy of all backup data with automatic failure detection","ko":"DNS 시스템이 모든 백업 데이터의 로컬 사본을 갖추고 장애를 자동으로 감지하게 해, 시스템끼리 최대한 독립시키고 장애가 연쇄로 번지지 않게 한다."}}],"contributing":["circular-dependency","single-point-of-failure","automation-amplified","revert-did-not-restore","manual-action-worsened"],"recurrence_of":null,"symptoms_text":{"en":"On 22 June 2021, within minutes of an update released at 8:25 AM UTC, bunny.net's global fleet of close to 100 DNS servers kept crashing and restarting, more than 60% of traffic was lost, hundreds of Gbits of throughput disappeared, and over 750,000 websites were affected. After 10 minutes the team realised that the DNS servers were restarting and dying and that nothing could bring them back up in that state.\n\nThe DNS software was designed to work with or without the SmartEdge data and to ignore exceptions, but the corrupted file made the BinaryPack serialization library fail with a stack overflow exception that bypassed all exception handling and ended the process. Each time auto-healing restarted a DNS server, it loaded the broken deployment and crashed again. At 8:35 a few servers were still struggling to answer, and traffic had dropped to 100Gbit. It was the lowest traffic point of the day.\n\nRolling back all SmartEdge updates right away did not help, because SmartEdge and the deployment systems deliver data to the DNS servers through Edge Storage and Bunny CDN, and the DNS failure had taken most of the CDN capacity down. After a manual update at 8:45 disabled SmartEdge, the DNS servers downloaded corrupted GeoDNS databases through the failing CDN and sent all requests to Madrid, one of the smallest PoPs, which was quickly overwhelmed.\n\nWith 100 servers restarting in a loop, the central API began to crash, and servers that were brought back failed to start properly. After several attempts to re-establish the networking, the team gave up on that idea. The ripple took down the CDN, the storage, the optimizer service, the API and the dashboard, and finally the logging service.","ko":"2021-06-22 UTC 8:25 에 업데이트를 내보내고 몇 분 만에 전 세계에 있는 100대 가까운 bunny.net DNS 서버가 거의 모두 죽었다. bunny.net 은 트래픽의 60% 넘게 잃었고, 수백 Gbit 의 처리량이 사라졌으며, 750,000개가 넘는 웹사이트가 영향을 받았다.\n\n팀은 무슨 일인지 알아채는 데 시간이 걸렸다. 10분이 지나서야 DNS 서버가 다시 시작했다가 죽기를 되풀이하고 있고, 이 상태로는 되살릴 방법이 없다는 것을 알았다. DNS 서버는 데이터가 있든 없든 돌고 예외를 무시하도록 만들어져 있었다. 하지만 손상된 파일을 읽은 BinaryPack 직렬화 라이브러리가 stack overflow 예외를 일으켰고, 이 예외는 예외 처리를 건너뛰고 프로세스를 그대로 종료시켰다.\n\n팀은 버튼 하나로 배포를 롤백할 수 있었고 SmartEdge 업데이트를 곧바로 모두 롤백했지만 이미 늦었다. SmartEdge 와 배포 시스템은 Edge Storage 와 Bunny CDN 으로 DNS 서버에 데이터를 나르는데, 이 CDN 용량 대부분이 이미 사라진 상태였다. DNS 서버는 스스로 다시 뜰 때마다 깨진 배포를 읽고 다시 크래시해 CDN 에서 수정본을 내려받지 못했다.\n\nUTC 8:35 에는 서버 몇 대만 요청을 버티고 있었고, 트래픽 대부분을 잃어 100Gbit 까지 떨어졌다. 하루 중 트래픽이 가장 적은 시간대였다.\n\n8:45 에 SmartEdge 를 끄는 업데이트를 손으로 배포하자 잠시 동작하는 것처럼 보였다. 하지만 CDN 장애 때문에 DNS 서버가 손상된 GeoDNS 데이터베이스를 내려받았고, 모든 요청이 가장 작은 PoP 가운데 하나인 Madrid 로 몰려 Madrid 가 금방 무너졌다. 100대의 서버가 루프를 돌며 다시 시작하자 중앙 API 가 크래시했고, 되살린 서버도 제대로 시작하지 못했다. 팀은 네트워킹을 다시 세우려고 여러 번 시도하다 포기했다.\n\n장애는 DNS 에서 CDN, 스토리지, optimizer 서비스로 번졌다. 수백 대의 서버가 다시 올라오는 동안 API 와 대시보드가 크래시했고, 마지막에는 로깅 서비스도 크래시했다."},"updated_at":"2026-11-14T05:53:44.722025Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0229","org_slug":"bunny-net"}