2026년 4월 4일 토요일, 블루스카이의 AppView 데이터 플레인 — 소셜 앱의 읽기를 처리하는 백엔드 — 이 'failed to set post cache item: dial tcp: bind: address already in use' 같은 오류를 기록하기 시작했다. 데이터 플레인은 주 Scylla 데이터베이스의 부하를 줄이기 위해 memcached에 크게 의존하는데, 당직 인프라 엔지니어인 Jim Calabro는 로그 급증이 사용자 대면 트래픽 감소와 일치하는 것을 확인했다. 네트워크 모니터링은 깨끗했기에, 서비스가 절뚝거리는 동안 주말 내내 원인은 숨겨져 있었다.
근본 원인은 그 주에 배포된 새 내부 서비스였다: 초당 GetPostRecord 요청은 3건 미만이었지만 배치당 게시물 URI가 15,000–20,000개였다(정상은 1~50개). 모든 데이터 플레인 RPC 핸들러는 errgroup.SetLimit으로 동시성을 제한하는데, 이 엔드포인트만 그 줄이 빠져 있었다. 단일 호출이 최대 20,000개의 고루틴을 생성해 memcached 연결 폭풍을 일으켰고, 1,000개 소켓 유휴 풀이 넘치자 연결들이 TCP TIME_WAIT에 쌓여 모든 임시 포트를 고갈시켰다. 클라이언트는 한 데이터 센터에서 실행되었고, 클라이언트별 지표가 없어 모든 유형의 캐시 오류가 범인을 가렸다.
4월 6일 월요일에는 죽음의 나선으로 치달았다: 초당 수백만 건의 memcached 요청이 실패하자, 블루스카이의 모든 오류 기록 정책이 초당 수백만 건의 블로킹 write(2) 로그 쓰기를 시도했다. 블로킹 시스템 콜의 홍수는 Go 런타임의 OS 스레드를 약 150개에서 1,500개로 밀어올려 GC를 기아 상태로 만들고 긴 stop-the-world 일시 정지를 초래했다. 공격적으로 조정된 GOGC와 GOMEMLIMIT는 데이터 플레인이 주기적으로 OOM 크래시를 일으키게 했다 — 약 30분간 살아 있다가 내려가고, 반복. 각 재시작은 구멍을 더 깊게 했다: TIME_WAIT 소켓 때문에 재시작된 프로세스가 memcached 풀을 다시 만들 수 없었다.
월요일의 임시방편은 유쾌할 정도로 터무니없었다: 나가는 모든 연결에 무작위 127.x.y.z 루프백 IP를 선택하는 커스텀 다이얼러로, ip+port 공간을 고갈된 범위 너머로 확장했다. 그것이 나선을 멈췄고, 팀이 진짜 근본 원인을 찾아 빠진 SetLimit(50)을 복원한 것은 수요일이 되어서였다. Calabro의 공개 사후 분석은 커뮤니케이션 실패도 인정했다: 상태 페이지가 제3자 네트워크 제공자의 탓으로 돌렸는데, '그것은 분명히 아니었다'.
무엇을 치렀나
2026년 4월 6일 약 8시간 동안 블루스카이 전체 사용자의 대략 절반에게 간헐적 다운타임 — 해당 인프라 리드가 재직한 이래 플랫폼 최악의 장애
왜 일어났나
동시성 제한이 구조가 아니라 관례에 의해 강제되었다: 하나를 제외한 모든 핸들러에 SetLimit이 있었고, 제한 없는 엔드포인트 하나로 호스트 수준 자원을 고갈시키기에 충분했다.
트래픽 계약에는 형태 제한이 없었다: 20,000개 항목 배치를 거부하는 것이 없었기에, 조용한 내부 클라이언트 하나 — 초당 3건 요청 — 가 부하 원천으로서 수백만 개의 정상 클라이언트보다 우위를 차지했다.
실패 처리가 실패를 증폭시켰다: 초당 수백만 건의 오류마다 모든 memcached 오류를 기록한 것이 캐시 문제를 스레드 폭발, GC 일시 정지, OOM 크래시로 전환했다.
관측성은 작은 요청을 가정했고 클라이언트별 지표가 없었기에, 모든 캐시 유형의 오류가 책임 있는 단일 호출자와 단일 엔드포인트를 며칠 동안 가렸다.
재시작을 통한 복구가 깨져 있었다: 죽은 프로세스의 TIME_WAIT 소켓이 새 프로세스의 memcached 풀 재구축을 막아, OOM 재시작을 더 많은 포트 고갈로 바꿨다.
교훈
제한 없는 고루틴 루프 하나가 다른 모든 안전장치를 압도했다. 동시성 제한은 엔드포인트별 습관이 아니라 구조적이어야 한다: 하나가 빠진 단일 엔드포인트가 전체 장애가 되었다.
후속 조치
서비스는 월요일에 무작위 루프백 다이얼러로 안정화되었고, 실제 수정 — 동시성 제한 복원 — 이 4월 8일 수요일에 적용되자 그것은 제거되었다. 총 노출은 대략 절반의 사용자에게 약 8시간의 간헐적 다운타임이었다. 2026년 4월 10일 발행된 사후 분석은 클라이언트별 관측성, 소수의 과대 요청을 보내는 클라이언트 탐지, 그리고 대량 로깅에서 Prometheus 지표와 OpenTelemetry 트레이싱으로의 전환을 약속했으며, 이틀 뒤 신뢰성 연구자 Lorin Hochstein의 상세한 독립 분석을 이끌어냈다.
근거 확인하기
출처
- April 2026 Outage Post-Mortem Jim Calabro (Bluesky infrastructure engineer), pckt.blog · pckt.blog ·
- Thoughts on the Bluesky public incident write-up Surfing Complexity (Lorin Hochstein) · surfingcomplexity.blog ·
- Bluesky April 2026 Outage Post-Mortem (discussion, 141 points) Hacker News · news.ycombinator.com ·