Incident Library
  • 원인
  • 구성 요소
  • 증상
  • 기여 요인
  • 사례

사례3건

3건 중 1~3번째

  1. 증상

    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. 증상

    2021년 10월 28일 13:37 PST 에 Vault 성능이 떨어지고 Consul 서버 한 대의 CPU 부하가 높아졌다. 이때는 플레이어에게 영향이 없었다.

    촉발

    10월 27일 14:00 PST 에 트래픽 라우팅을 맡는 백엔드 서비스에 Consul 의 새 streaming 기능을 켰다. 같은 롤아웃에서 연말 트래픽에 대비해 트래픽 라우팅 노드 수를 50% 늘렸고, 하루 뒤 Consul 성능이 떨어지기 시작했다.

    원인
    구성 요소
    기여 요인
    감지

    10월 28일 13:37 PST 에 Vault 성능 저하와 Consul 서버 한 대의 높은 CPU 부하를 보고 Roblox 엔지니어들이 조사를 시작했다. Consul 클러스터 지표에서 KV 쓰기 지연이 올라간 것을 확인했다.

    조치
    • 하드웨어 성능 저하를 의심해 Consul 클러스터 노드 한 대를 교체했다.
    • 트래픽 증가를 의심해 Consul 클러스터의 모든 노드를 128코어와 더 빠른 NVME SSD 를 단 서버로 바꿨다.
    • Consul 클러스터 전체를 내리고 장애 시작 무렵인 몇 시간 전 스냅샷으로 상태를 되돌렸으며, iptables 로 접근을 막았다가 천천히 풀었다.
    • 외부 트래픽을 막고, Consul 을 쓰는 서비스 목록을 모아 꼭 필요하지 않은 사용을 끄는 설정을 배포했으며, 서비스 인스턴스를 한 자릿수로 줄이고 헬스 체크 간격을 60초에서 10분으로 늘렸다.
    • 경합이 128코어 서버로 옮긴 탓일 수 있다고 보고 Consul 클러스터를 다시 64코어 서버로 옮겼다.
    • 트래픽 라우팅 노드를 포함한 모든 Consul 시스템에서 streaming 기능을 껐고, 설정이 15:51 PST 에 다 퍼지자 KV 쓰기의 p50 지연이 300ms 로 내려갔다.
    • 느린 리더 문제의 원인을 모르는 채로, 문제가 있는 서버가 리더로 뽑힌 채 남지 않게 막았다.
    • 캐시 시스템을 다시 배포했고, 틀어진 스케줄링 데이터와 끝나지 않는 배포 같은 문제를 밤새 찾아 고쳤다.
    • 장애와 문제 분석 중에 내렸던 서비스들을 알맞은 용량으로 다시 띄우고 제대로 도는지 확인했다.
    • DNS 조정으로 무작위로 고른 일정 비율의 플레이어만 들이고 나머지는 정적 점검 페이지로 보냈으며, 데이터베이스 부하와 캐시 성능을 보며 약 10% 씩 늘렸다.
    후속 조치
    • HashiCorp 는 시험 환경에서 이 경합 문제를 재현하는 새 벤치마크를 만들고 대규모 시험을 늘린다.
    • HashiCorp 는 극한 부하에서도 경합이 생기지 않도록 streaming 시스템의 설계를 고친다.
    • 기존 BoltDB 도구로 데이터베이스를 압축하는 절차를 만들어 배포했고, 이것으로 성능 문제가 풀렸다.
    • 텔레메트리 시스템과 Consul 사이의 순환 의존을 없애, 텔레메트리 시스템이 감시 대상 시스템에 기대지 않게 했다.
    • Consul 과 BoltDB 성능, Roblox 서비스와 Consul 사이의 트래픽 패턴을 더 잘 보이게 텔레메트리를 넓혔고, 이번 장애 상태에 가까워지는 신호에 정밀한 알림을 건다.
    • 백엔드 서비스를 둘 지리적으로 떨어진 데이터센터를 하나 더 세웠고, 데이터센터 안에서 여러 가용 영역으로 옮긴다.
    • 서비스들의 Consul KV 와 헬스 체크 사용을 검토해 일부 핵심 서비스를 전용 클러스터로 나눠 중앙 Consul 클러스터의 부하를 줄였다.
    • Consul KV 를 데이터 저장소로 쓰던 핵심 서비스의 데이터를 더 알맞은 저장 시스템으로 옮긴다.
    • 쓰지 않는 KV 데이터를 대량으로 찾아 지웠고, Consul 성능이 좋아졌다.
    • HashiCorp 와 함께 BoltDB 대신 freelist 가 끝없이 커지는 문제가 없는 후속 라이브러리 bbolt 를 쓰는 새 Consul 버전을 배포한다. 연말 최대 트래픽을 피해 새해로 미뤘고 1분기에 끝낸다.
    • 캐시 배포 방식을 다시 설계해 아무것도 없는 상태에서도 캐시 시스템을 빨리 올릴 수 있게 한다.
    • 오래 멈춘 뒤 큰 작업을 다시 올리기 쉽게 하는 Nomad 개선 몇 가지를 HashiCorp 와 찾았고, 다음 Nomad 업그레이드에서 배포한다.
    • 서버 설정을 더 빨리 바꾸는 방법을 만들어 배포했다.
    • 새 streaming 구현을 Roblox 규모와 부하로 시험한 뒤에 조심스럽게 다시 들인다.
    교훈

    Roblox 는 원인 두 가지가 Consul 구현 깊숙이 묻혀 있어 진단이 어려웠던 것이 장애를 길게 만든 주된 이유라고 봤다. 원인을 보여 줄 모니터링 시스템이 장애가 난 Consul 에 기대고 있어 분석이 크게 막혔다. 모든 백엔드 서비스를 Consul 클러스터 하나에 올린 구성이 이런 장애에 취약했다. HashiCorp 는 Roblox 와 비슷한 규모에서 streaming 을 벤치마크했지만, 이 경합은 스트림 수가 많고 교체가 잦은 조건이 겹칠 때만 나타나 전에는 보지 못했다. 더 빠른 하드웨어는 도움이 되지 않았고 오히려 안정성을 해쳤을 수 있다. 오래 완전히 멈춘 상태에서 서비스를 올리는 데도 캐시 배포와 데우기 때문에 시간이 많이 걸렸다.

  3. 증상

    2019년 7월 10일 16:35 UTC 에 데이터베이스 클러스터의 primary 노드가 고장 났고, 1분 뒤 자동 모니터링이 선출 실패를 잡아 알림을 보냈다. Stripe API 요청 대부분이 실패하기 시작했다.

    촉발

    16:35 UTC 에 데이터베이스 클러스터의 primary 노드가 고장 났다. 그 shard 에는 멈춘 노드가 여럿 있어 석 달 전 마이너 버전 업그레이드로 들어온 장애 조치 결함이 드러났다. 두 번째 장애는 선출 프로토콜을 이전 마이너 버전으로 되돌린 변경 때문에 일어났다.

    원인
    구성 요소
    기여 요인
    감지

    첫 장애는 자동 모니터링이 1분 안에 선출 실패를 잡았고, 16:36 UTC 에 팀이 알림을 받아 대응을 시작했다. 두 번째 장애는 21:14 UTC 에 클러스터의 shard 몇 개를 사용할 수 없다는 자동 알림으로 알았다.

    조치
    • 17:00 UTC 에 데이터베이스 클러스터의 모든 노드를 재시작해 새 primary 선출을 성공시켰다. 17:02 에 Stripe API 가 완전히 복구됐다.
    • 22:34 UTC 에 운영 설정을 고쳐 새로 배포하고 데이터베이스 클러스터의 노드를 재시작해 영향받은 shard 를 되살렸다.
    • 클러스터가 정상인지 확인한 뒤 사용자가 직접 보낸 API 요청에 필요한 서비스부터 트래픽을 다시 올렸다. 22:47 UTC 에 완전히 복구됐다.
    후속 조치
    • 노드가 복제 지연 지표를 보내지 않으면 알리는 모니터링을 더했다.
    • shard 가 데이터베이스 장애 조치 시스템의 이 선출 결함을 일으킬 수 있는 상태에 들어가면 알리는 모니터링을 더했다.
    • 이 결함을 고치는 수정을 데이터베이스 메인테이너와 함께 만든다.
    • 특정 클러스터로 가는 작업이 실패하면 끊어 내는 서킷 브레이커를 더 넣는다. 이번 사고의 클러스터도 대상이다.
    • shard 하나가 고장 나도 그 영향을 가두는 장애 격리 기법을 더 도입한다.
    • 실패한 요청을 거듭 재시도하는 클라이언트가 쓰는 자원을 제한한다.
    • 장애 대응 중 운영자가 설정을 빠르게 바꿀 때 더 안전하게 할 수 있도록 절차와 도구를 더 만든다.
내 클러스터에도 있는지 확인하기

이 3건에서 가장 많이 나오는 구성 요소: 인메모리 캐시, 코디네이션 키-값 저장소. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.

원인별2