사례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 의 메모리가 포화되자 엔지니어는 장애 한가운데서 가용성과 데이터 손실 사이의 어려운 선택을 해야 했다. 이 부분에는 안전장치와 설계 개선이 필요했다. 대시보드와 로그로 트래픽 급증을 먼저 배제한 덕분에 공용 의존성과 인프라 쪽 원인에 집중할 수 있었다. 대기열 비우기처럼 되돌릴 수 없는 선택을 미루고 안전한 완화부터 한 것도 도움이 됐다.
- 증상
어느 날 갑자기 애플리케이션 오류율이 나빠졌다는 알림이 울렸다. 그 시간대 Aurora MySQL RDS 인스턴스의 오류 로그에는, Aurora MySQL 이 메모리 부족으로 OOM 이 나는 것을 피하려고 커넥션을 끊고 쿼리를 거부한 기록이 남아 있었다.
- 촉발
FreeableMemory 가 내려가기 시작한 날의 애플리케이션 릴리스에서 쿠버네티스 CronJob 으로 매분 도는 배치 처리가 더해졌다.
- 원인
- 구성 요소
- 기여 요인
- 감지
애플리케이션 오류율이 나빠졌다는 알림이 울렸다.
- 조치
- Aurora MySQL 파라미터 그룹에서 Performance Schema 를 자동 관리를 뜻하는 0 에서 수동 관리를 뜻하는 1 로 바꾸고, 기본값 -1 로 무제한이던 관련 파라미터 두 개에 상한 100 을 두었다. 적용에는 RDS 인스턴스 재시작이 필요했고, 이 조치로 FreeableMemory 감소와 SwapUsage 발생이 멈췄다.
- 교훈
시스템 알림이 울렸는데 DB 부하 지표가 조용하면 Performance Schema 가 불어난 것도 의심해야 한다. 상한을 둔 두 파라미터는 기본값이 무제한이라 이번처럼 기록이 계속 쌓였다. 상한을 두면 퍼포먼스 인사이트의 호스트별 집계에서 상한을 넘은 호스트의 정보가 빠지는 단점이 있다. 애플리케이션과 Aurora MySQL 사이에 RDS Proxy 를 두어 DB 에 접속하는 HOST 를 일정하게 유지하는 방법도 있다.
이 2건에서 가장 많이 나오는 구성 요소: 인메모리 캐시, 데이터베이스. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.