그래프
사례5건
5건 중 1~5번째
- 증상
평일 20시쯤 사업장 현장에서 고객 업무에 쓰는 특정 시스템의 단말이 통신하지 못해 영업에 문제가 생겼다는 연락이 왔다. 네트워크 그룹의 모니터링에서는 알림이 하나도 울리지 않았다.
- 촉발
Cisco Catalyst 2960L 15대의 설정을 맞추는 작업에서, SW2와 SW3 사이 LACP LAG를 이루는 물리 포트 두 개 중 SW3 쪽 한 포트에만 no switchport trunk allowed vlan 을 넣어 허용 VLAN 지정을 지웠다.
- 원인
- 구성 요소
- 기여 요인
- 감지
모니터링 알림은 울리지 않았고, 20시쯤 사업장 현장에서 단말이 통신하지 못한다는 연락을 받고 알았다. 대상 포트의 인터페이스 모니터링은 처음부터 없었고, LACP 모니터링은 꺼져 있었으며, CPU 상승은 10% 정도라 리소스 알림에 걸리지 않았다.
- 조치
- 원인 지점을 모른 채 작업을 되돌리기 시작했고, 30분쯤 뒤 장비 한 대의 인터페이스 설정을 원래대로 되돌린 시점에 복구됐다.
- 22시쯤 이어진 조사에서 원인 지점을 확인하고 다른 영향이 없음을 확인한 뒤 1차 대응을 마쳤다.
- 후속 조치
- 대상 포트에 빠져 있던 인터페이스 모니터링과 꺼져 있던 LACP 모니터링을 즉시 바로잡았다.
- 모니터링 설정 변경은 가벼운 임계값 변경까지 모두 리뷰를 거치게 했다.
- 알림 규칙을 정의한 리포지토리의 PR은 리뷰어 승인 없이는 머지할 수 없도록 설정을 바꿨다.
- PR에 AI 자동 리뷰를 켜서 사람 말고도 누락을 찾을 수 있게 했다.
- 네트워크 변경 작업은 가벼운 작업이라도 스스로 판단하지 않고 미리 공지하는 규칙으로 바꿨다.
- 작업 일시는 사업장 책임자 등과 일정을 맞추고, 사업장의 운영 일정을 파악해 행사일을 피한다는 규칙을 다시 확인했다.
- 영향이 큰 유지보수나 이번처럼 여러 대를 함께 바꾸는 작업처럼 되돌릴 때 시간이 걸리는 작업은 되돌리는 절차를 미리 만든다.
- 교훈
말단 장비 한 대라도 사업장 전체에 영향을 줄 수 있다. 작업 실수, 예상 못 한 상황, 버그 같은 이유로 작업 중에는 언제든 장애가 날 수 있으므로, 미리 일정을 맞춰 유지보수 시간을 확보해야 한다. 여러 대를 한꺼번에 바꾸면 원인 장비를 찾고 되돌리는 데 시간이 걸린다. 만일에 대비해 미리 준비하고, 사람이 아니라 구조로 막을 수 있는 부분은 막아야 한다. 지금이라면 로그를 AI에게 보여 주고 원인을 바로 찾을 수 있었을 것이다. 이번 같은 장애에는 AI의 사전 리뷰와 장애 상황 분석이 효과가 있었을 것이다.
- 증상
2025-03-10 16:23 UTC 무렵 FR-PAR 리전의 모든 제품에서 공용 인터넷 연결이 크게 흔들렸다. 인터넷 트래픽 대부분이 사실상 버려졌고, FR-PAR-2 가용 영역과 나머지 PAR 리전 사이의 공용 인터넷 연결이 심하게 끊겼다.
- 촉발
Scaleway 네트워크 팀이 FR-PAR 리전 백본에 새 데이터 센터를 붙이던 중 라우터 구성을 잘못 넣었다. 이 실수로 OpCore DC3 와 DC5 사이의 1Tbps 넘는 트래픽이 100Gbps 링크 하나로 돌아갔다.
- 원인
- 구성 요소
- 기여 요인
- 감지
라우터 구성 실수는 빨리 발견되어 4분 안에 롤백됐다.
- 조치
- 잘못 넣은 라우터 구성을 4분 안에 롤백해 16:27 UTC 에 올바른 구성을 되돌렸다.
- 후속 조치
- 변경 관리를 고쳐 동료 검토와 운영 공지 절차를 강화한다.
- 백본 수준의 네트워크 구성을 적용하기 전에 안전장치와 시험을 더 거치도록 운영 절차를 고친다.
- Object Storage 동기화 소프트웨어의 문제를 찾아 수정을 만들고 시험했으며, 이 수정을 배포하고 있다.
- 증상
처리되지 않은 잡이 밀리는지 감시하던 DataDog 에서 알림이 울렸다. 대량의 잡이 처리되지 못하고 쌓여 있었다.
- 촉발
Redash 에서 reader 인스턴스로 보내야 할 데이터 분석용 쿼리가, 데이터 소스 등록 때 잘못 설정한 클러스터 엔드포인트를 거쳐 writer 인스턴스에서 오래 실행됐다.
- 원인
- 구성 요소
- 기여 요인
- 감지
처리되지 않은 잡이 밀리는지 감시하던 DataDog 알림이 대량의 잡이 쌓였을 때 울렸다.
- 조치
- Redash 의 데이터 소스 설정 실수를 고쳐 reader 엔드포인트를 가리키게 했다.
- VACUUM 을 막는 쿼리라고 확신한 뒤 pg_terminate_backend 로 그 쿼리의 프로세스를 강제로 끝냈다.
- 프로세스가 끝난 것을 확인하고 VACUUM 을 다시 수동으로 실행해 dead tuples 를 대량으로 치웠다.
- 후속 조치
- Redash 컨테이너의 /etc/hosts 에서 writer 엔드포인트 호스트 이름을 테스트용 무효 주소인 TEST-NET-1 의 IP 주소로 지정해, Redash 에 writer 엔드포인트를 잘못 설정해도 실제로는 접속하지 못하게 한다.
- PostgreSQL 사용자의 statement_timeout 을 알맞게 설정해 오래 걸리는 쿼리를 자동으로 멈춰 재발을 막는다.
- 늘어날 잡을 견디도록 qg 를 개선하거나, SELECT FOR UPDATE SKIP LOCKED 로 락을 잡는 river 같은 기술을 쓰는 것을 검토한다.
- 교훈
que_jobs 와 전혀 관계없는 쿼리라도 같은 DB 인스턴스에서 오래 실행되면 que_jobs 의 dead tuples 를 치우지 못하게 막아 테이블이 계속 커지고, qg 의 디큐 성능 저하와 DB 부하 상승으로 이어진다. 글쓴이는 이것을 오래 걸리는 쿼리 때문에 VACUUM 이 효과를 내지 못하는 PostgreSQL 운영의 전형적인 경우로 보았다. 이런 상황에서 어디를 확인해야 하는지를 정해 두고 습관으로 만들어야 한다고 느꼈다. 현재 qg 가 쓰는 advisory lock 과 Recursive CTE 는 dead tuples 의 영향을 받기 쉬운 설계다.
- 증상
OpenStack 호스트 서버가 다운되어 ElasticSearch 노드 하나가 내려간 뒤, API 서버 쪽 ElasticSearch 헬스 체크가 false 를 반환했다. Head 플러그인으로 본 클러스터 상태는 그린이었다.
- 촉발
OpenStack 호스트 서버가 다운되어 30대짜리 ElasticSearch 클러스터의 노드 하나가 내려갔다.
- 원인
- 구성 요소
- 기여 요인
- 감지
API 서버가 ElasticSearch 에 하는 헬스 체크가 false 를 반환했다. 클러스터 상태는 Head 플러그인에서 그린으로 보였다.
- 조치
- 호스트가 언제 다시 다운될지 몰라, 복구된 ElasticSearch 노드 서버를 다른 호스트 서버로 마이그레이션했다.
- 마이그레이션 뒤 ElasticSearch 프로세스를 띄워 노드를 클러스터에 다시 넣었다.
- 헬스 체크를 되살리려고 1번 노드부터 로그를 보며 차례로 전체 재시작했지만, 스무 번째 노드까지 재시작했을 즈음 API 서버 지연이 생겨 멈췄다.
- 다시 1번 노드부터 차례로 전체 재시작해 API 서버 지연과 헬스 체크를 되살렸다.
- _cluster/reroute 의 allocate 명령으로 unassigned 샤드를 옮기려 했지만 오류가 나서 실패했다.
- A 인덱스의 53번 샤드는 22번 노드에만 파일이 남아 있었다. 그래서 프로세스를 멈추고 그 파일을 디렉터리만 남은 3번 노드와 10번 노드로 복사한 뒤, 22번 노드의 상태 파일만 "primary" 를 true 로 바꿨다.
- B 인덱스의 51번 샤드는 lucene-core 검사로 27번 노드 쪽이 망가진 것을 확인했다. 27번 노드의 파일을 지운 뒤 28번 노드의 파일을 27번 노드와 다른 노드로 복사하고, 28번 노드만 "primary" 를 true 로 바꿨다.
- C 인덱스의 2번 샤드는 27번 노드에만, 4번 샤드는 25번 노드에만 파일이 남아 있었다. 그래서 각 파일을 다른 두 노드로 복사하고, 복사한 쪽의 상태 파일은 "primary" 를 false 로 바꿨다.
- 후속 조치
- 오래된 ElasticSearch 버전을 그만 쓰고 버전을 올린다.
- 교훈
재시작할 때는 자동 재배치를 끄고 작업해야 했다. 노드 하나를 재시작한 뒤에는 로그만 볼 것이 아니라 재배치가 완전히 끝나는 것을 보고 나서 다음 노드를 재시작해야 했다.
- 증상
2012-12-24 PST 오후 12시 24분부터 US-East 리전의 ELB 제어 평면에서 로드 밸런서를 관리하는 API 호출의 지연과 오류율이 올랐다. 이때는 돌고 있는 로드 밸런서의 요청 처리에 영향이 없었다.
- 촉발
운영 환경에 접근할 수 있는 아주 적은 수의 개발자 가운데 한 명이 유지보수 프로세스를 실수로 운영 ELB 상태 데이터를 대상으로 실행해 데이터 일부를 논리적으로 지웠다. 그 개발자는 그때 실수를 알아채지 못했다.
- 원인
- 구성 요소
- 기여 요인
- 감지
데이터가 지워진 뒤 ELB 제어 평면에서 로드 밸런서를 관리하는 API 호출의 지연과 오류율이 올랐고, 기술팀은 이 API 오류부터 살폈다. 사라진 상태 데이터는 팀이 성능이 떨어진 로드 밸런서를 깊이 파고든 뒤에야 찾았다. 데이터를 지운 개발자는 그때 실수를 알아채지 못했다.
- 조치
- PST 오후 5시 2분에 확장과 축소 워크플로를 포함한 ELB 제어 평면 워크플로 여러 개를 꺼서, 돌고 있는 다른 로드 밸런서가 사라진 상태 데이터의 영향을 받지 않게 했다.
- 영향받은 로드 밸런서 가운데 일부를 월요일 밤에 손으로 복구했다.
- 처음 쓴 복원 방법이 몇 시간 걸리고도 쓸 수 있는 스냅샷을 만들지 못하자 다른 복구 절차를 찾아, 12월 25일 PST 오전 2시 45분에 데이터가 지워지기 직전 시점의 ELB 상태 데이터 스냅샷을 복원했다.
- 복원한 데이터에 스냅샷 이후의 시스템 상태 변경을 합쳤고, 오전 5시 40분에 병합과 새 상태 데이터 검증을 마쳤다.
- 영향받지 않은 로드 밸런서를 건드리지 않고 영향받은 로드 밸런서마다 제대로 복구되도록 ELB 워크플로와 API 를 천천히 다시 켰다. 오전 8시 15분에 대부분의 API 와 백엔드 워크플로가 다시 켜졌고, 오전 10시 30분에 영향받은 로드 밸런서가 거의 모두 정상으로 돌아왔다.
- 후속 조치
- 운영 ELB 상태 데이터의 접근 통제를 바꿨다. 상시 권한으로 잘못 설정된 접근을 되돌렸고, 운영 ELB 데이터에 접근할 때마다 사고 건별 Change Management 승인을 받게 했다.
- 이번에 배운 것을 반영해 데이터 복구 절차를 고쳤다. AWS 는 비슷한 일이 생기면 ELB 상태 데이터를 훨씬 빨리 복구할 수 있다고 봤다.
- ELB 제어 평면 워크플로가 중앙 서비스 데이터와 현재 로드 밸런서 상태를 더 신중하게 맞추도록 다시 짜, 논리적 데이터 손실이나 손상이 생겨도 손으로 복원하지 않고 자동으로 복구되게 한다.
이 5건에서 가장 많이 나오는 구성 요소: PostgreSQL vacuum, 백본망. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.
원인별1
운영 실수5건
- 구성 요소
- 기여 요인
IL-0568DeNA의 한 사업장에서 L2 스위치 루프가 생겨 사업장 전체의 단말이 서버에 접속하지 못하거나 통신이 느려졌다DeNA2026IL-0348FR-PAR 리전의 모든 제품에서 공용 인터넷 연결이 끊기고 여러 제품이 오래 불안정했다Scaleway2025IL-0582Aurora PostgreSQL 위의 qg 잡 큐에서 que_jobs 의 dead tuples 가 계속 늘어 잡이 대량으로 밀렸다Kanmu2024IL-0434ElasticSearch 0.19 클러스터 전체 재시작 뒤 샤드 12개가 unassigned 로 남아 데이터 일부를 읽을 수 없었다CyberAgent2016IL-0224유지보수 작업이 운영 ELB 상태 데이터 일부를 지워 US-East 리전의 Elastic Load Balancer 일부가 오류를 내고 나머지는 확장하거나 바꿀 수 없게 됐다.