사례3건
3건 중 1~3번째
- 증상
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 을 벤치마크했지만, 이 경합은 스트림 수가 많고 교체가 잦은 조건이 겹칠 때만 나타나 전에는 보지 못했다. 더 빠른 하드웨어는 도움이 되지 않았고 오히려 안정성을 해쳤을 수 있다. 오래 완전히 멈춘 상태에서 서비스를 올리는 데도 캐시 배포와 데우기 때문에 시간이 많이 걸렸다.
- 증상
2020년 3월 16일 14:19 PDT 에 실시간 연결과 채팅 메시지를 처리하는 Elixir 서비스 대부분이 죽어 용량이 한순간에 사라졌고, 여기에 의존하는 다른 시스템으로 장애가 번졌다. 14:21 에 핵심 지표가 떨어졌다는 알림과 클러스터 사용률 이상 알림이 여럿 울렸고 SEV1 이 선언됐다. 대부분의 사용자가 Discord 에 접속하지 못했다.
- 촉발
2020년 3월 16일 14:18 PDT 에 Google Cloud 관리형 인스턴스 그룹 오토스케일러가 API 클러스터에 새 노드를 넣었고, 이 노드가 etcd 에 자신을 등록하는 도중 연결이 끊겨 값이 빈 키가 서비스 디스커버리에 쓰였다.
- 원인
- 구성 요소
- 기여 요인
- 감지
14:21 PDT 에 핵심 지표가 떨어졌다는 알림과 클러스터 사용률 이상 알림이 여럿 울렸고, SEV1 이 선언됐다.
- 조치
- 잃은 실시간 용량을 다시 띄우고 장애가 난 노드를 고쳤다.
- 서비스 복구를 돕기 위해 Discord 로 들어오는 접속을 조절하기 시작했다.
- 모두가 다시 접속하는 동안 자원이 바닥나지 않도록 ScyllaDB 클러스터 두 곳의 데이터베이스 유지 작업인 anti-entropy repair 를 멈췄다.
- 서비스가 회복되는 대로 접속 허용량을 계속 늘려 더 많은 사용자가 다시 접속하게 했다.
- 후속 조치
- 값이 잘못된 키가 쓰일 가능성을 줄이려고, etcd 클라이언트가 자신을 등록하는 요청을 TCP 패킷 두 개가 아니라 하나로 보내게 바꿨다.
- 키 값이 깨진 서비스는 무시하도록 오류 처리를 더해, 같은 일이 다시 나도 그 서비스가 발견되지 않을 뿐 크래시 루프에 빠지지 않게 했다.
- Go 프로젝트에 이 문제를 버그로 보고한다.
- 교훈
서비스 디스커버리 시스템은 etcd 안의 여러 장애에는 견디도록 만들었지만, 일시적인 네트워크 오류로 값 없는 키가 쓰일 수 있다는 것은 예상하지 못했다. 이 경우 Go 의 net/http 는 HTTP 1.1 규격을 어겨, Content-Length 헤더가 있고 본문이 불완전한 요청을 거부하지 않는다. 이 때문에 예상하지 못한 장애 상황이 하나 더 생겼다.
- 증상
2019년 1월 18일 09:35 UTC 에 Elastic Cloud 의 당번 SRE 들이 AWS eu-west-1 리전 조정 계층의 서비스 저하 알림을 받았다. 10:08 UTC 무렵부터 이 리전에 배포를 둔 고객은 약 3시간 동안 자기 클러스터에 접속하기가 매우 어려워졌다.
- 촉발
09:09 UTC 에 ZooKeeper 앙상블 리더 서버의 CPU 사용량이 높은 임계치에 닿으면서 클라이언트 연결이 끊긴 것이 시작이었다.
- 원인
- 구성 요소
- 기여 요인
- 감지
09:35 UTC 에 당번 SRE 들이 조정 계층의 서비스 저하 알림을 받았고, 내부 절차에 따라 운영 장애를 열었다.
- 조치
- 급증한 클라이언트 트래픽을 받도록 프록시 계층을 수직과 수평으로 늘렸다.
- 리더 선출을 일으켜 조정 계층의 ZooKeeper 앙상블을 안정시켰다.
- 후속 조치
- 모든 Elasticsearch Service 제공자와 리전 거점에서 TreeCache 를 TreeWatcher 로 바꾼다. 2019년 1월 24일에 교체를 마쳤다.
- 운영에서 검증된 TreeWatcher 를 Apache Curator 프로젝트에 기여할 계획이다.
- 다음 버전의 프록시 계층은 ZooKeeper 에 덜 의존하고, 라우팅 테이블을 버전을 매긴 로컬 파일에 캐시해 ZooKeeper 연결이 끊기거나 불안정해도 트래픽을 보낼 수 있게 한다. 앞으로 몇 달에 걸쳐 모든 리전에 차례로 배포한다.
이 3건에서 가장 많이 나오는 구성 요소: 코디네이션 키-값 저장소, 서비스 디스커버리. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.