사례2건
2건 중 1~2번째
IL-0290GitLab.com 의 Redis Sidekiq 클러스터에서 노드 여러 대가 메모리를 다 써 멈추고 쿼럼을 잃어, 웹과 Git 과 CI 전반에서 500 오류가 늘었다- 증상
2026-05-12 17:15 UTC 에 Prometheus Alertmanager 알림으로 장애가 접수됐다. 플랫폼 대시보드에서 web, Git, API, CI 러너, Sidekiq 의 오류율이 한꺼번에 올랐고, 사용자는 잦은 500 오류와 인증 실패, CI 파이프라인 실패를 겪었다.
- 촉발
같은 날 앞선 장애 inc-10084 를 완화하려고 감사 이벤트 작업을 지연 처리로 돌려 두었고, 지연된 작업이 Redis Sidekiq 클러스터에 쌓였다.
- 원인
- 구성 요소
- 기여 요인
- 감지
17:12 UTC 에 영향이 시작됐고 17:15:10 UTC 에 Prometheus Alertmanager 알림이 incident.io 에 장애를 트리아지 상태로 올렸다. 온콜이 17:16:59 UTC 에 Severity 2 로 받아들였고 17:32:49 UTC 에 Severity 1 로 올렸다. redis-sidekiq 메모리 알림은 온콜을 호출하지 않았고, 다른 신호들도 라벨과 라우팅의 틈 때문에 맞는 온콜에게 제대로 닿지 않았다.
- 조치
- 응답하지 않는 Redis 노드 두 대를 골라 재시작하고 강제로 리셋했다. 18:00 UTC 에 세 노드가 모두 올라왔고 O2 가 primary 가 됐다.
- Redis VM 을 한 대씩 멈추고 메모리와 CPU 를 두 배로 늘린 c2-standard-16 머신 타입으로 바꿨다. 18:40 UTC 에 세 노드의 교체가 끝났다.
- AuditEventStreamingWorker 를 다시 켜고 더는 지연 처리로 돌리지 않았다. 앞서 지연시킨 탓인지 이 워커의 대기열이 계속 늘어 지켜봤다.
- 후속 조치
- redis-sidekiq 메모리 알림이 왜 온콜을 호출하지 않았는지 조사한다.
- WebHookWorker poison pill 문제의 근본 원인과 실패 양상, 해결 진행 상황을 정리한다.
- 안전 한도를 끄는 완화 조치에는 담당자와 재검토 기한을 분명히 정하도록 절차를 고친다.
- AuditEvents::AuditEventStreamingWorker 가 장애를 되풀이해 일으키지 않도록 고친다.
- AuditEventStreamingWorker 의 런북을 만든다.
- PG 연결 풀 포화 문제를 후속 작업으로 다룬다.
- 교훈
web, Git, 인증, CI 러너, Sidekiq, 내부 API 가 한꺼번에 나빠져 원인 하나로 좁히고 그것을 짧게 전하기가 어려웠다. created 상태에 멈춘 파이프라인처럼 고객이 겪는 증상을 실시간으로 세고 확인할 방법이 부족했고, 관련 대시보드와 SLI 를 온콜이 찾기 어려웠다. 호스트가 응답하지 않아 SSH 로그인이 멈추면서 진단이 늦어지고 변경할 때의 위험도 커졌다. 신호가 있어도 라벨과 라우팅의 틈 때문에 맞는 온콜에게 닿지 않았다. redis-sidekiq 의 메모리가 포화되자 엔지니어는 장애 한가운데서 가용성과 데이터 손실 사이의 어려운 선택을 해야 했다. 이 부분에는 안전장치와 설계 개선이 필요했다. 대시보드와 로그로 트래픽 급증을 먼저 배제한 덕분에 공용 의존성과 인프라 쪽 원인에 집중할 수 있었다. 대기열 비우기처럼 되돌릴 수 없는 선택을 미루고 안전한 완화부터 한 것도 도움이 됐다.
- 증상
2022년 4월 11일 13:17 UTC 에 고객과 Gitpod 직원들이 워크스페이스가 간헐적으로 응답하지 않는다고 알렸다. 4월 8일과 9일에 새 세대 워크스페이스 클러스터 ws39 를 모든 리전에 배포한 직후였다.
- 촉발
2022년 4월 8일과 9일에 새 세대 워크스페이스 클러스터 ws39 를 모든 리전에 배포한 것이 시작이었다.
- 원인
- 구성 요소
- 기여 요인
- 감지
2022년 4월 11일 13:17 UTC 에 고객과 Gitpod 직원들의 신고로 알았고, incident.io 연동으로 Slack 에 장애를 열었다. 4월 12일에도 고객과 직원의 신고로 알았고, 4월 17일에는 엔지니어들이 워크스페이스 노드의 CPU 부하가 오른 것을 보고 내부 장애를 열었다.
- 조치
- IO 제한 기능이 없어 워크스페이스 시작 트래픽을 이전 세대 클러스터 ws38 로 돌렸고, 4월 11일 15:37 UTC 에 마쳤다.
- t2d 대신 더 빠른 c2d 머신 유형과 로컬 SSD 를 쓰는 새 클러스터 ws39a 를 만들어 트래픽을 옮겼다.
- Let's Encrypt 속도 제한 문제를 풀고, Let's Encrypt 에 한도를 올려 달라고 요청했다.
- ws38 클러스터를 쓸 수 없어 EU XL 트래픽을 임시로 리전 EU 클러스터로 보내 워크스페이스를 다시 시작할 수 있게 했다. 그리고 망가진 ws-eu39xl 을 대신할 ws-eu39bxl 클러스터를 새로 만들었다.
- stopping 상태에 걸린 워크스페이스를 정리해 사용자가 다시 시작할 수 있게 했다.
- 4월 8일 배포 전처럼 1TB 부트 디스크를 단 노드로 ws40 을 만들어 디스크 IO 대역폭을 늘렸다.
- 모니터링으로 노드의 작업을 직접 살펴 과도한 CPU 시간을 쓰는 워크스페이스를 찾아 시스템에서 지웠다.
- 노드를 손으로 뒤지고 채굴 탐지 시스템을 함께 써서 부정 사용자를 찾아 Gitpod 사용을 막았다.
- ws38 세대에는 없던 ws-daemon 변경을 되돌려 CPU 제한을 다시 안정시켰고, 이 수정을 ws34 클러스터에 담아 배포했다.
- 새 ws34 배포에서 워크스페이스 포트로 가는 ACME HTTP 요청을 막아 Let's Encrypt 한도에 다시 걸리지 않게 했다.
- 워크스페이스 사이에 디스크 IO 를 공정하게 나누는 ws41xl 클러스터와 일반 리전용 ws41 클러스터를 만들어 트래픽을 단계적으로 옮겼다.
- 후속 조치
- 테스트 결과가 진행하면 안 되는 배포를 미리 걸러 내도록 테스트 자동화에 계속 투자한다.
- 새 클러스터로 트래픽 비율을 옮기는 간격을 배포마다 다르게 하고, 큰 배포일수록 단계 사이를 길게 둔다.
- 워크스페이스 클러스터 배포에 위험 평가 단계를 넣어 변경 묶음의 크기와 배포 속도를 정하고, 이 단계를 자동화하는 것을 목표로 한다.
- 팀 사이 의존이 롤백을 막지 않도록 팀끼리 주는 영향을 계속 줄인다.
- PR 을 머지하기 전에 하위 호환이 깨지는 변경을 찾는 리뷰 기준을 더하고, 그런 PR 은 나눠서 배포를 롤백하기 어려운 상황을 피한다.
- 장애 완화의 첫 수단으로 롤백을 권하도록 절차를 고쳤고, 이 과정을 자동화하는 방법을 논의한다.
- 상태 페이지의 워크스페이스 서비스가 장애를 주황이나 빨강으로 제대로 표시하도록 고쳤고, 플레이북도 그에 맞게 고쳤다.
- 장애 중 내부 소통을 Slack 채널 하나와 Google Meet 하나로 모으고, 장애 절차를 그에 맞게 고쳤다.
- 당번 체계를 다시 짜서 5월 9일부터 엔지니어링 인력의 10% 가 늘 당번을 맡고, 그 시간으로 관측성과 알림과 시스템 안정성을 개선한다.
- 교훈
4월 11일에 롤백을 결정했다면 가장 좋았다. 롤백하지 않고 수정을 계속 만들어 배포하면서 고객은 필요 이상으로 오래 성능 저하를 겪었고 일부는 데이터를 잃었다. 규모가 크고 바로 앞 배포와 가까운 변경을 너무 빨리 내보냈고, 테스트 결과가 배포를 막았어야 했다. 배포 묶음을 작게 하고 배포를 자주 한다는 원칙을 ws39 에서 지키지 못했고, 팀 사이 의존이 롤백을 어렵게 만들었다. 기여 요인 가운데 일부는 막을 수 있었다.
이 2건에서 가장 많이 나오는 구성 요소: 인메모리 캐시, 컨테이너 CPU 한도. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.