그래프
사례2건
2건 중 1~2번째
IL-0229손상된 SmartEdge 데이터 파일을 받은 bunny.net 의 전 세계 DNS 서버가 크래시를 되풀이해 플랫폼 대부분이 2시간 넘게 멈췄다.bunny.net2021- 증상
2021-06-22 UTC 8:25 에 업데이트를 내보내고 몇 분 만에 전 세계에 있는 100대 가까운 bunny.net DNS 서버가 거의 모두 죽었다. bunny.net 은 트래픽의 60% 넘게 잃었고, 수백 Gbit 의 처리량이 사라졌으며, 750,000개가 넘는 웹사이트가 영향을 받았다.
- 촉발
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 은 내부 인프라의 핵심 부분까지 모든 시스템이 서로 기대도록 설계했다. 그 때문에 손상된 파일 하나가 여러 겹의 이중화를 무너뜨리고 복구할 길까지 막았다. 자체 인프라를 자기 생태계 안에 지으면 한 곳의 장애가 연쇄로 번질 수 있다. 업데이트는 카나리 방식으로 잘게 배포하려 했지만, 중요하지 않다고 본 소프트웨어 하나가 여러 클러스터에 동시에 걸친 단일 장애 지점이 됐다. 급하게 고치는 동안 오타와 실수가 늘었고, 결국 침착하게 모든 것을 다시 확인한 뒤의 마지막 배포로 복구했다.
- 증상
2021년 3월 6일 11시 길드 업데이트 점검을 마친 뒤 데이터베이스 CPU 사용량이 예상보다 조금 높았다. 11시 30분쯤 24코어 머신인 데이터베이스 노드 하나가 24코어를 모두 쓰며 CPU 사용량이 최대치에 이르렀고, 같은 시각 서버 지표에서 상당한 양의 에러가 보이기 시작했다. 곧 다른 두 노드에서도 CPU 사용량 이상이 나타났다.
- 촉발
길드 업데이트 점검 뒤 서비스를 열자 모든 유저가 곧바로 새 기능을 썼고, 분석용 테이블에 guild-<uuid> 형식의 Primary Key가 매우 빠르게 쓰였다. 리팩토링으로 Primary Key 형식이 바뀐 테이블도 있었다.
- 원인
- 구성 요소
- 기여 요인
- 감지
모니터링 중 한 노드의 CPU 사용량이 최대치에 이르렀다는 소식과 함께 서버 지표에서 에러가 관측돼 알았다. 이후 노드 문제는 Host Status Check 실패 슬랙 알림과 이상 로그 감지 채널의 알림으로 알았다.
- 조치
- 기존 유저를 내보내지 않고 새 로그인만 막아 입장 인원을 0명으로 둔 대기열처럼 썼고, 지표를 보며 막고 풀기를 반복해 동시 접속자 수를 조절했다.
- 오후 2시 50분 노드 여러 대가 health check를 통과하지 못하자 아무도 게임을 할 수 없는 전체 긴급 점검에 들어갔다.
- 전체 데이터베이스 백업이 멈추자 테이블 단위로 백업했다. 부하가 몰린 것은 특정 테이블의 일부 Range였고 그 테이블은 다른 테이블로 복구할 수 있었기 때문이다.
- 서비스를 열기 전에 데이터베이스 부하를 최대한 줄이려고 플레이 기록 저장을 잠시 멈췄다.
- 오후 6시 반쯤 문제가 된 테이블들에 Split 작업을 시작해 부하가 모든 노드에 고르게 나뉘도록 했다.
- Host Status Check에 실패하고 filemap_fdatawait_range_keep_errors 로그가 나온 노드를 클러스터에서 빼기로 하고, Range 분리와 그 노드의 Decommission을 함께 진행했다. Decommission이 끝나자 복제되지 않은 Range가 0이 되고 지표가 안정됐다.
- 서비스를 다시 연 뒤 한 노드가 CPU를 100% 쓰자 다시 대기열 방식으로 접속을 조절해 CPU 사용량을 안정시켰다.
- 같은 노드가 거듭 CPU 100%에 이르러 노드 자체의 문제로 보고 그 노드를 종료해 문제를 끝냈다.
- 교훈
일반 RDBMS에서는 Primary Key prefix를 바꿔도 큰 문제가 되지 않지만, 분산 처리를 하는 CockroachDB의 프로덕션 클러스터에서는 이런 변경에 상당한 주의가 필요하다. 팀은 CockroachDB 스터디에서 문서와 자료를 읽어 이 내용을 알고 있었다. 그러나 직접 겪어 보니 글로 읽어 알던 것보다 훨씬 큰 일이었다.
이 2건에서 가장 많이 나오는 구성 요소: CDN 과 엣지 네트워크, 데이터베이스. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.