{"id":"IL-0274","org":"GitHub","date":"2013-01-24","docs":[],"title":{"en":"GitHub's code search Elasticsearch cluster hit near-100% CPU and rapid master elections; a restart found lost shards","ko":"GitHub 코드 검색의 elasticsearch 클러스터에서 일부 노드 CPU 가 100% 에 가깝게 차고 마스터가 계속 바뀌면서 검색과 색인이 타임아웃되고 샤드 데이터가 사라졌다"},"domain":["database"],"impact":{"scope":"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","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"The Elasticsearch upgrade was not tested enough on GitHub's infrastructure before it reached the code search cluster, partly because the cluster had no proper staging environment. For large clusters the elasticsearch team recommended equal minimum and maximum JVM heap through ES_HEAP_SIZE, at 50% of system RAM, starting recovery immediately instead of after recover_after_time, and configuring minimum_master_nodes so that paused nodes do not form their own clusters.","ko":"GitHub 는 elasticsearch 0.20.2 를 코드 검색 클러스터에 내보내기 전에 자기 인프라에서 충분히 시험하지 않았고 다른 클러스터에서도 시험하지 않았다. 코드 검색 클러스터에 제대로 된 스테이징 환경이 없던 것이 한 요인이었다. elasticsearch 팀은 큰 클러스터에 이렇게 권했다. ES_HEAP_SIZE 환경 변수로 JVM 의 최소·최대 메모리를 같게 하고 시스템 RAM 의 50% 로 둔다. recover_after_time 을 30분으로 두지 말고 복구가 바로 시작되게 한다. minimum_master_nodes 를 설정해 노드가 오래 멈출 때 노드 일부가 따로 클러스터를 이루지 않게 한다."},"related":[],"sources":[{"url":"https://github.blog/news-insights/the-library/recent-code-search-outages/","kind":"blog","archived":"https://web.archive.org/web/20260808221554/https://github.blog/news-insights/the-library/recent-code-search-outages/"}],"summary":{"en":"GitHub had moved all its search to Elasticsearch, with a dedicated code search cluster of 26 storage nodes and 8 client nodes; each storage node had 2TB of SSD storage. The cluster held roughly 17TB of code, about 34TB with one replica of every shard, and was 67% full. It had run on Java 6 and Elasticsearch 0.19.9 for several months while all code was backfilled into the index. On 17 January GitHub upgraded it to Elasticsearch 0.20.2 before the public launch. The 0.20.2 release had not been tested on GitHub's infrastructure or on any other cluster first, and there was no proper staging environment for the code search cluster. About two hours after the upgrade, during cluster recovery, 7 of the 510 shards were found missing both their primary and replica copies. The team put that down to high load during recovery and, after a healthy weekend, launched Code Search.\n\nOn 24 January several storage nodes went to nearly 100% CPU in the Elasticsearch Java process, nodes were rapidly elected to and removed from the master role, and code search queries and indexing jobs timed out. The team stopped the cluster and restarted it in maintenance mode. The 23 primaries that could not be allocated, with their replicas, had lost their data. GitHub brought in two engineers from elasticsearch, the company behind Elasticsearch, who found two bugs in Elasticsearch, released a fixed version within a few hours, and identified misconfigured or untuned settings. The Java 6 version GitHub ran dated from early 2009 and has several critical bugs affecting Elasticsearch and Lucene, plus problems with large memory allocations that can cause high load. The JVM's minimum and maximum memory differed, so the Java process blocked each time it grew its heap, which together with the old Java explains the pauses once public searches added load. minimum_master_nodes was not configured, so during long pauses subsets of nodes tried to form their own clusters. recover_after_time was set to 30 minutes, which delayed recovery.\n\nGitHub rolled out upgrades of Java and Elasticsearch and the recommended configuration through a separate Puppet topic branch and environment. Each of the several restarts this needed made the cluster verify and recover its shards again, and loading 17TB of index from disk repeatedly was the slowest part of the outage; the audits added a few hours. With Elasticsearch 0.20.3, Java 7 and the new configuration, the erratic load and rapid master elections could no longer be reproduced. The outage affected only Code Search.","ko":"GitHub 의 코드 검색 색인은 크기가 커서 전용 elasticsearch 클러스터에 따로 둔다. 클러스터는 색인 데이터를 담는 저장 노드 26대와 질의를 조정하는 클라이언트 노드 8대로 이루어지고, 저장 노드마다 2TB SSD 가 있다. 클러스터에는 코드 17TB 정도가 들어 있고, 샤드마다 다른 노드에 복제본을 하나씩 두어 전체는 약 34TB 였다. 사용률은 67% 정도였다. 이 클러스터는 Java 6 와 elasticsearch 0.19.9 로 몇 달 동안 문제없이 돌았다. 1월 17일 코드 검색 공개를 앞두고 수정과 성능 개선이 들어간 0.20.2 로 업그레이드했고, 이번 장애는 업그레이드 뒤 이 클러스터에서 난 두 번째 장애였다.\n\n1월 24일 목요일 코드 검색 질의와 색인 갱신 작업이 타임아웃되기 시작했다. 일부 저장 노드의 elasticsearch java 프로세스가 CPU 를 100% 가까이 썼고, 노드들이 빠르게 마스터로 선출됐다가 빠졌다. 팀은 마스터 역할이 빠르게 오가며 생길 문제를 막으려고 클러스터를 완전히 멈추고, 샤드 할당과 재균형을 끄는 \"maintenance mode\" 로 다시 올렸다. 그 뒤 일부 노드는 클러스터에 다시 들어오지 못했고 일부 샤드는 같은 노드에 두 번 할당되려 했다. 팀은 elasticsearch 를 개발하는 회사의 엔지니어 두 명에게 도움을 청했고, 할당되지 않는 주 샤드 23개와 복제본이 모두 데이터를 잃었음을 확인했다. 업그레이드와 설정 변경을 내보내느라 클러스터를 여러 번 재시작해야 했다. 재시작할 때마다 17TB 색인 데이터를 디스크에서 다시 읽어 샤드를 검증하고 복구해야 했고, 복구에서 이 일이 가장 오래 걸렸다.\n\n두 엔지니어는 클러스터 설정이 잘못됐거나 조정이 필요한 곳을 찾았다. 두 사람은 GitHub 가 겪은 문제에서 elasticsearch 자체의 버그 두 개를 찾아 몇 시간 만에 수정 버전을 냈다. GitHub 는 2009년 초에 나온 Java 6 버전을 쓰고 있었다. 이 버전에는 elasticsearch 와 Lucene 에 영향을 주는 심각한 버그 여럿과 큰 메모리 할당 문제가 있어 높은 부하로 이어질 수 있었다. JVM 의 최소·최대 메모리가 달라 메모리가 더 필요할 때마다 Java 프로세스가 멈췄다. 여기에 오래된 Java 가 겹쳐, 공개 검색으로 부하가 늘 때 노드가 잠깐씩 멈췄다. minimum_master_nodes 가 설정돼 있지 않아 노드가 오래 멈추면 노드 일부가 따로 클러스터를 이루려 해 클러스터가 불안정해졌다. 팀은 Puppetmaster 에 이 변경 전용 토픽 브랜치와 환경을 만들어 각 노드에 Puppet 을 돌리는 방식으로 Java 와 elasticsearch 를 업그레이드하고 권고대로 설정을 바꿨다. 그 뒤로 불규칙한 부하와 빠른 마스터 선출은 재현되지 않았다. 코드 검색 말고 다른 GitHub 구성 요소는 영향을 받지 않았다."},"trigger":{"en":"On 17 January GitHub upgraded the code search cluster from Elasticsearch 0.19.9 to 0.20.2 before launching Code Search publicly; the outage began on 24 January, after the public launch.","ko":"2013년 1월 17일 코드 검색 클러스터를 elasticsearch 0.19.9 에서 0.20.2 로 업그레이드했다. 그 뒤 코드 검색을 공개하자 클러스터에 높은 부하가 걸렸고 메모리 할당이 계속 일어났다."},"severity":"unknown","symptoms":["intermittent-timeouts","node-high-cpu","split-brain","data-loss"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"incident","detection":{"en":"GitHub's exception tracking and monitoring systems detected a large spike in exceptions, mostly timeouts from code search queries and from the indexing background jobs.","ko":"예외 추적·모니터링 시스템이 예외가 크게 치솟은 것을 잡았다."},"components":["elasticsearch-opensearch","language-runtime"],"root_cause":"software-bug","remediation":[{"text":{"en":"Stopped the whole cluster and brought it back in maintenance mode, with shard allocation and rebalancing disabled","ko":"클러스터를 완전히 멈추고, 샤드 할당과 재균형을 끄는 \"maintenance mode\" 로 다시 올렸다."}},{"text":{"en":"Brought in engineers from elasticsearch, the company, to review the cluster and its unallocatable shards","ko":"elasticsearch 를 개발하고 지원하는 회사의 엔지니어 두 명에게 도움을 청했다."}},{"text":{"en":"Upgraded Java and Elasticsearch and applied the recommended configuration through a Puppet topic branch and environment","ko":"두 엔지니어의 권고대로 Java 와 elasticsearch 를 곧바로 업그레이드하고 설정을 바꿨다. Puppetmaster 에 이 변경 전용 토픽 브랜치와 환경을 만들고 각 노드에서 Puppet 을 돌렸다."}}],"action_items":[{"text":{"en":"Provision a staging environment for the code search cluster to test infrastructure changes","ko":"코드 검색 클러스터의 스테이징 환경을 만들어 인프라 변경을 더 잘 시험한다."}},{"text":{"en":"Have the elasticsearch team audit the code search cluster configuration again in future","ko":"elasticsearch 팀이 앞으로도 코드 검색 클러스터 설정을 다시 점검해, 쓰임새에 맞게 유지되도록 한다."}}],"contributing":["default-config-unchanged","skipped-upgrades","change-untested","early-signal-ignored","manual-action-worsened"],"recurrence_of":null,"symptoms_text":{"en":"On Thursday 24 January 2013 GitHub's exception tracking and monitoring systems detected a large spike in exceptions. Most of them were timeouts in code search queries and in the background jobs that update the code search indexes with data from new pushes, and the outage of the newly launched Code Search lasted into Friday 25 January.\n\nOn the Elasticsearch cluster dedicated to code search, a seemingly random subset of storage nodes carried massive load: most nodes used single-digit percentages of CPU, while several used nearly 100% of all their CPU cores. System load and IO load were ruled out; the only process behind the load was the Java process running Elasticsearch. While search and index timeouts continued, the logs showed several nodes being rapidly elected to the master role and removed from it again.\n\nTo stop the master role moving around the cluster, the team stopped the whole cluster and brought it back in \"maintenance mode\", which disables shard allocation and rebalancing. After the restart, some nodes could not rejoin the cluster at all, and some shards tried to allocate twice to the same node. The shards that could not be allocated, 23 primaries plus their replicas, had lost their data, and the cluster then spent a long time recovering the remaining shards.","ko":"2013년 1월 24일 목요일 예외 추적·모니터링 시스템이 예외가 크게 치솟은 것을 잡았다. 예외 대부분은 코드 검색 질의의 타임아웃과, 새 push 의 데이터로 코드 검색 색인을 갱신하는 백그라운드 작업의 타임아웃이었다.\n\n클러스터 멤버의 상태와 elasticsearch 로그를 보니 무작위로 보이는 일부 저장 노드에 부하가 엄청나게 걸려 있었다. 대부분의 노드는 CPU 를 한 자릿수 퍼센트만 썼지만 몇 대는 모든 CPU 코어를 100% 가까이 쓰고 있었다. 시스템이나 IO 가 일으킨 부하는 아니었고, 부하를 만드는 것은 elasticsearch 가 도는 java 프로세스뿐이었다.\n\n검색과 색인 타임아웃이 계속되는 동안 로그에는 여러 노드가 빠르게 마스터로 선출됐다가 다시 마스터에서 빠지는 것이 찍혔다.\n\n클러스터를 완전히 멈췄다가 다시 올린 뒤 일부 노드는 클러스터에 전혀 다시 들어오지 못했고, 일부 데이터 샤드는 같은 노드에 두 번 할당되려 했다. 할당되지 않는 샤드는 주 샤드 23개와 그 복제본이었고, 모두 데이터를 잃은 상태였다."},"updated_at":"2026-11-14T12:33:52.557490Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0274","org_slug":"github"}