Incident Library

IL-0274 GitHub · 2013-01-24database

GitHub 코드 검색의 elasticsearch 클러스터에서 일부 노드 CPU 가 100% 에 가깝게 차고 마스터가 계속 바뀌면서 검색과 색인이 타임아웃되고 샤드 데이터가 사라졌다

GitHub 의 코드 검색 색인은 크기가 커서 전용 elasticsearch 클러스터에 따로 둔다. 클러스터는 색인 데이터를 담는 저장 노드 26대와 질의를 조정하는 클라이언트 노드 8대로 이루어지고, 저장 노드마다 2TB SSD 가 있다. 클러스터에는 코드 17TB 정도가 들어 있고, 샤드마다 다른 노드에 복제본을 하나씩 두어 전체는 약 34TB 였다. 사용률은 67% 정도였다. 이 클러스터는 Java 6 와 elasticsearch 0.19.9 로 몇 달 동안 문제없이 돌았다. 1월 17일 코드 검색 공개를 앞두고 수정과 성능 개선이 들어간 0.20.2 로 업그레이드했고, 이번 장애는 업그레이드 뒤 이 클러스터에서 난 두 번째 장애였다.

1월 24일 목요일 코드 검색 질의와 색인 갱신 작업이 타임아웃되기 시작했다. 일부 저장 노드의 elasticsearch java 프로세스가 CPU 를 100% 가까이 썼고, 노드들이 빠르게 마스터로 선출됐다가 빠졌다. 팀은 마스터 역할이 빠르게 오가며 생길 문제를 막으려고 클러스터를 완전히 멈추고, 샤드 할당과 재균형을 끄는 "maintenance mode" 로 다시 올렸다. 그 뒤 일부 노드는 클러스터에 다시 들어오지 못했고 일부 샤드는 같은 노드에 두 번 할당되려 했다. 팀은 elasticsearch 를 개발하는 회사의 엔지니어 두 명에게 도움을 청했고, 할당되지 않는 주 샤드 23개와 복제본이 모두 데이터를 잃었음을 확인했다. 업그레이드와 설정 변경을 내보내느라 클러스터를 여러 번 재시작해야 했다. 재시작할 때마다 17TB 색인 데이터를 디스크에서 다시 읽어 샤드를 검증하고 복구해야 했고, 복구에서 이 일이 가장 오래 걸렸다.

두 엔지니어는 클러스터 설정이 잘못됐거나 조정이 필요한 곳을 찾았다. 두 사람은 GitHub 가 겪은 문제에서 elasticsearch 자체의 버그 두 개를 찾아 몇 시간 만에 수정 버전을 냈다. GitHub 는 2009년 초에 나온 Java 6 버전을 쓰고 있었다. 이 버전에는 elasticsearch 와 Lucene 에 영향을 주는 심각한 버그 여럿과 큰 메모리 할당 문제가 있어 높은 부하로 이어질 수 있었다. JVM 의 최소·최대 메모리가 달라 메모리가 더 필요할 때마다 Java 프로세스가 멈췄다. 여기에 오래된 Java 가 겹쳐, 공개 검색으로 부하가 늘 때 노드가 잠깐씩 멈췄다. minimum_master_nodes 가 설정돼 있지 않아 노드가 오래 멈추면 노드 일부가 따로 클러스터를 이루려 해 클러스터가 불안정해졌다. 팀은 Puppetmaster 에 이 변경 전용 토픽 브랜치와 환경을 만들어 각 노드에 Puppet 을 돌리는 방식으로 Java 와 elasticsearch 를 업그레이드하고 권고대로 설정을 바꿨다. 그 뒤로 불규칙한 부하와 빠른 마스터 선출은 재현되지 않았다. 코드 검색 말고 다른 GitHub 구성 요소는 영향을 받지 않았다.

심각도
–
영향 범위
GitHub Code Search: search queries and index updates from new pushes timed out, and 23 primary shards with their replicas lost their data; no other GitHub component was affected
영향 사용자
–
지역
–
감지까지
–
복구까지
–

증상

2013년 1월 24일 목요일 예외 추적·모니터링 시스템이 예외가 크게 치솟은 것을 잡았다. 예외 대부분은 코드 검색 질의의 타임아웃과, 새 push 의 데이터로 코드 검색 색인을 갱신하는 백그라운드 작업의 타임아웃이었다.

클러스터 멤버의 상태와 elasticsearch 로그를 보니 무작위로 보이는 일부 저장 노드에 부하가 엄청나게 걸려 있었다. 대부분의 노드는 CPU 를 한 자릿수 퍼센트만 썼지만 몇 대는 모든 CPU 코어를 100% 가까이 쓰고 있었다. 시스템이나 IO 가 일으킨 부하는 아니었고, 부하를 만드는 것은 elasticsearch 가 도는 java 프로세스뿐이었다.

검색과 색인 타임아웃이 계속되는 동안 로그에는 여러 노드가 빠르게 마스터로 선출됐다가 다시 마스터에서 빠지는 것이 찍혔다.

클러스터를 완전히 멈췄다가 다시 올린 뒤 일부 노드는 클러스터에 전혀 다시 들어오지 못했고, 일부 데이터 샤드는 같은 노드에 두 번 할당되려 했다. 할당되지 않는 샤드는 주 샤드 23개와 그 복제본이었고, 모두 데이터를 잃은 상태였다.

증상 간헐적 타임아웃노드 CPU 고부하스플릿 브레인데이터 유실

원인

촉발
2013년 1월 17일 코드 검색 클러스터를 elasticsearch 0.19.9 에서 0.20.2 로 업그레이드했다. 그 뒤 코드 검색을 공개하자 클러스터에 높은 부하가 걸렸고 메모리 할당이 계속 일어났다.

감지

예외 추적·모니터링 시스템이 예외가 크게 치솟은 것을 잡았다.

조치

후속 조치

교훈

GitHub 는 elasticsearch 0.20.2 를 코드 검색 클러스터에 내보내기 전에 자기 인프라에서 충분히 시험하지 않았고 다른 클러스터에서도 시험하지 않았다. 코드 검색 클러스터에 제대로 된 스테이징 환경이 없던 것이 한 요인이었다. elasticsearch 팀은 큰 클러스터에 이렇게 권했다. ES_HEAP_SIZE 환경 변수로 JVM 의 최소·최대 메모리를 같게 하고 시스템 RAM 의 50% 로 둔다. recover_after_time 을 30분으로 두지 말고 복구가 바로 시작되게 한다. minimum_master_nodes 를 설정해 노드가 오래 멈출 때 노드 일부가 따로 클러스터를 이루지 않게 한다.

출처

관련 사례

내 클러스터에도 있는지 확인하기

kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이 사례와 같은 상태를 점검합니다. 이 사례의 구성 요소: Elasticsearch 와 OpenSearch, 언어 런타임 설정. 점검 항목의 근거는 이 사례 같은 공개 보고서입니다.

AI 도구와 스크립트용

API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.