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개와 그 복제본이었고, 모두 데이터를 잃은 상태였다.
원인
원인 소프트웨어 결함
- 촉발
- 2013년 1월 17일 코드 검색 클러스터를 elasticsearch 0.19.9 에서 0.20.2 로 업그레이드했다. 그 뒤 코드 검색을 공개하자 클러스터에 높은 부하가 걸렸고 메모리 할당이 계속 일어났다.
감지
예외 추적·모니터링 시스템이 예외가 크게 치솟은 것을 잡았다.
조치
- 클러스터를 완전히 멈추고, 샤드 할당과 재균형을 끄는 "maintenance mode" 로 다시 올렸다.
- elasticsearch 를 개발하고 지원하는 회사의 엔지니어 두 명에게 도움을 청했다.
- 두 엔지니어의 권고대로 Java 와 elasticsearch 를 곧바로 업그레이드하고 설정을 바꿨다. Puppetmaster 에 이 변경 전용 토픽 브랜치와 환경을 만들고 각 노드에서 Puppet 을 돌렸다.
후속 조치
- 코드 검색 클러스터의 스테이징 환경을 만들어 인프라 변경을 더 잘 시험한다.
- elasticsearch 팀이 앞으로도 코드 검색 클러스터 설정을 다시 점검해, 쓰임새에 맞게 유지되도록 한다.
교훈
GitHub 는 elasticsearch 0.20.2 를 코드 검색 클러스터에 내보내기 전에 자기 인프라에서 충분히 시험하지 않았고 다른 클러스터에서도 시험하지 않았다. 코드 검색 클러스터에 제대로 된 스테이징 환경이 없던 것이 한 요인이었다. elasticsearch 팀은 큰 클러스터에 이렇게 권했다. ES_HEAP_SIZE 환경 변수로 JVM 의 최소·최대 메모리를 같게 하고 시스템 RAM 의 50% 로 둔다. recover_after_time 을 30분으로 두지 말고 복구가 바로 시작되게 한다. minimum_master_nodes 를 설정해 노드가 오래 멈출 때 노드 일부가 따로 클러스터를 이루지 않게 한다.
출처
관련 사례
IL-0216데이터센터 전환 직후 CirrusSearch Elasticsearch 지연이 치솟아 위키 검색이 일부 사용자에게 늦거나 안 됐다Wikimedia Foundation · 2023같은 원인 · 공통 Elasticsearch 와 OpenSearch
IL-0175JVM 파드의 CPU requests 를 1코어로 줄이자 JVM 이 노드의 CPU 36개를 인식해 Reactor Netty 스레드가 늘고 메모리 사용량이 경보 기준을 넘었다Hyperconnect · 2022같은 원인 · 공통 언어 런타임 설정
같은 원인 · 공통 Elasticsearch 와 OpenSearch
IL-0277Elastic Cloud us-east-1 의 ZooKeeper 조정 계층이 쿼럼을 잃어 Elasticsearch 배포에 6시간 넘게 접속하지 못하고 Kibana 는 18:44 UTC 까지 불안정했다Elastic · 2019같은 원인 · 공통 Elasticsearch 와 OpenSearch
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0274
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0274/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.