{"id":"IL-0434","org":"CyberAgent","date":"2016-06-10","docs":[],"title":{"en":"Rolling restarts of a 30-node Elasticsearch 0.19 cluster after a host failure left 12 shards unassigned","ko":"ElasticSearch 0.19 클러스터 전체 재시작 뒤 샤드 12개가 unassigned 로 남아 데이터 일부를 읽을 수 없었다"},"domain":["database"],"impact":{"scope":"12 shards of the Elasticsearch cluster behind an Ameba user service stayed unassigned and part of the data was unavailable until the shard files were repaired by hand; the API servers were slow during the restarts","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Automatic shard reallocation should have been turned off before restarting nodes. After each node restart, the next node should have been restarted only after reallocation had completely finished, not just after the log file looked fine.","ko":"재시작할 때는 자동 재배치를 끄고 작업해야 했다. 노드 하나를 재시작한 뒤에는 로그만 볼 것이 아니라 재배치가 완전히 끝나는 것을 보고 나서 다음 노드를 재시작해야 했다."},"related":[],"sources":[{"url":"https://ameblo.jp/principia-ca/entry-12168516931.html","kind":"blog","archived":"https://web.archive.org/web/20251205063730/https://ameblo.jp/principia-ca/entry-12168516931.html"}],"summary":{"en":"Ameba ran Elasticsearch 0.19.10 for a user-facing service on 30 OpenStack virtual servers with 24 cores and an 8GB heap each, holding 3 indices, about 300GB of data, 128 shards and 2 replicas. When an OpenStack host failed, one node went down and its shards were reallocated to the other nodes. After the host recovered, the node was migrated to another host in case the host failed again, its Elasticsearch process was started and it joined the cluster, which turned green. The API servers' health check against Elasticsearch still returned false. On another Elasticsearch environment a false health check had once been fixed by restarting all nodes, so the operators restarted all nodes here too, without turning off automatic shard reallocation and without waiting for reallocation to finish after each node. Reallocation ran over and over, the cluster became unstable and the API servers slowed down; a second full restart steadied the cluster but left 12 shards unassigned.\n\nThe shard files on disk explained why. For shard 53 of index A, directories existed on nodes 3, 10, 22 and 29 but only node 22 had files, and its state file said \"primary\" : false. For shard 51 of index B, nodes 27 and 28 both had data with different contents, and a lucene-core index check showed node 27's copy was broken and node 28's was healthy. For shards 2 and 4 of index C, files were left only on node 27 and node 25 respectively, with state files saying \"primary\" : true. With the Elasticsearch process stopped on the nodes involved, the operators copied the surviving files to the other nodes, deleted the broken copy on node 27, and edited the _state files so that exactly the surviving copy was marked primary true and the copies were false. After the processes were started, the Head plugin showed the shards back in the cluster.","ko":"CyberAgent 의 Ameba 는 사용자 서비스에 ElasticSearch 0.19.10 을 OpenStack 가상 서버 30대로 운영했다. 인덱스는 3개, 샤드는 128개, 레플리카는 2개였고, 전체 데이터는 약 300GB 였다. OpenStack 호스트 서버가 다운되어 노드 하나가 내려가자 샤드 재배치가 돌아 그 노드의 샤드가 다른 노드로 흩어졌다. 클러스터 상태는 그린이었지만 API 서버 쪽 헬스 체크가 false 를 반환했다. 호스트가 복구된 뒤 노드를 다른 호스트로 옮겨 클러스터에 다시 넣었지만 헬스 체크는 여전히 false 였다.\n\n팀은 다른 환경에서 같은 증상을 전체 재시작으로 고친 경험이 있어, 자동 재배치를 끄지 않은 채 1번 노드부터 로그를 보며 차례로 재시작했다. 스무 번째 노드까지 재시작했을 즈음부터 API 서버에 지연이 생기고 Head 플러그인으로 상태를 볼 수 없게 되었다. 재배치가 계속 돌아 클러스터가 불안정해진 것이었다. 작업을 멈췄다가 다시 1번 노드부터 전체 재시작하자 지연과 헬스 체크는 정상으로 돌아왔지만, 프라이머리를 포함한 샤드 12개가 unassigned 로 남아 데이터 일부를 잃은 상태가 되었다.\n\n팀은 allocate 명령으로 샤드를 옮기는 데 실패하자 각 노드의 샤드 디렉터리와 _state 의 상태 파일을 직접 살폈다. 파일이 남은 노드의 샤드 파일을 다른 노드로 복사하고, 상태 파일의 \"primary\" 값을 고쳐 한 노드만 프라이머리로 두었다. B 인덱스는 lucene-core 로 인덱스를 검사해 망가진 쪽을 지우고 정상인 쪽을 복사했다. 프로세스를 다시 띄운 뒤 Head 플러그인으로 샤드가 클러스터에 돌아온 것을 확인했다."},"trigger":{"en":"An OpenStack host server went down, and one node of the Elasticsearch cluster went down with it.","ko":"OpenStack 호스트 서버가 다운되어 30대짜리 ElasticSearch 클러스터의 노드 하나가 내려갔다."},"severity":"unknown","symptoms":["high-latency","data-loss"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":{"en":"The health check that the API servers run against Elasticsearch returned false while the Head plugin showed the cluster as green.","ko":"API 서버가 ElasticSearch 에 하는 헬스 체크가 false 를 반환했다. 클러스터 상태는 Head 플러그인에서 그린으로 보였다."},"components":["elasticsearch-opensearch"],"root_cause":"human-operation","remediation":[{"text":{"en":"Migrated the Elasticsearch node's virtual server to another host after the failed host recovered","ko":"호스트가 언제 다시 다운될지 몰라, 복구된 ElasticSearch 노드 서버를 다른 호스트 서버로 마이그레이션했다."}},{"text":{"en":"Started the node's Elasticsearch process and let it rejoin the cluster","ko":"마이그레이션 뒤 ElasticSearch 프로세스를 띄워 노드를 클러스터에 다시 넣었다."}},{"text":{"en":"Restarted all nodes in order from node 1, pausing at about the twentieth when the API slowed","ko":"헬스 체크를 되살리려고 1번 노드부터 로그를 보며 차례로 전체 재시작했지만, 스무 번째 노드까지 재시작했을 즈음 API 서버 지연이 생겨 멈췄다."}},{"text":{"en":"Restarted all nodes again from node 1, which ended the API delays but left 12 shards unassigned","ko":"다시 1번 노드부터 차례로 전체 재시작해 API 서버 지연과 헬스 체크를 되살렸다."}},{"text":{"en":"Tried to move an unassigned shard with the allocate command of _cluster/reroute, which failed","ko":"_cluster/reroute 의 allocate 명령으로 unassigned 샤드를 옮기려 했지만 오류가 나서 실패했다."}},{"text":{"en":"For index A, copied node 22's shard files to nodes 3 and 10 and set primary to true in node 22's state file","ko":"A 인덱스의 53번 샤드는 22번 노드에만 파일이 남아 있었다. 그래서 프로세스를 멈추고 그 파일을 디렉터리만 남은 3번 노드와 10번 노드로 복사한 뒤, 22번 노드의 상태 파일만 \"primary\" 를 true 로 바꿨다."}},{"text":{"en":"For index B, deleted the broken shard files on node 27, copied node 28's files to node 27 and other nodes and marked node 28 primary","ko":"B 인덱스의 51번 샤드는 lucene-core 검사로 27번 노드 쪽이 망가진 것을 확인했다. 27번 노드의 파일을 지운 뒤 28번 노드의 파일을 27번 노드와 다른 노드로 복사하고, 28번 노드만 \"primary\" 를 true 로 바꿨다."}},{"text":{"en":"For index C, copied shards 2 and 4 from nodes 27 and 25 to two other nodes each and marked the copies as not primary","ko":"C 인덱스의 2번 샤드는 27번 노드에만, 4번 샤드는 25번 노드에만 파일이 남아 있었다. 그래서 각 파일을 다른 두 노드로 복사하고, 복사한 쪽의 상태 파일은 \"primary\" 를 false 로 바꿨다."}}],"action_items":[{"text":{"en":"Upgrade Elasticsearch and stop running such an old version","ko":"오래된 ElasticSearch 버전을 그만 쓰고 버전을 올린다."}}],"contributing":["assumption-unverified","automation-amplified"],"recurrence_of":null,"symptoms_text":{"en":"After an OpenStack host server went down and took one Elasticsearch node with it, the health check that the API servers run against Elasticsearch returned false, although the Head plugin showed the cluster status as green. The check stayed false after the node was brought back and the cluster was green again.\n\nOperators then restarted every node one by one, starting from node 1 and checking the log files as they went. From about the twentieth node the API servers became slow, the restarts were paused, and the Head plugin could no longer show the cluster status: repeated shard reallocation had made the cluster unstable.\n\nA second full restart from node 1 brought the Head plugin back, the API delays ended and the health check returned true. But 12 shards, including primary shards, did not come back into the cluster and stayed unassigned, so part of the data was lost to the service. Moving an unassigned shard with the allocate command of _cluster/reroute ended in an error.","ko":"OpenStack 호스트 서버가 다운되어 ElasticSearch 노드 하나가 내려간 뒤, API 서버 쪽 ElasticSearch 헬스 체크가 false 를 반환했다. Head 플러그인으로 본 클러스터 상태는 그린이었다.\n\n노드를 다른 호스트로 옮겨 다시 클러스터에 넣은 뒤에도 클러스터 상태는 그린이었지만 API 서버 쪽 헬스 체크는 계속 false 였다.\n\n1번 노드부터 차례로 전체 재시작을 하던 중 스무 번째 노드까지 재시작했을 즈음부터 API 서버 쪽에 지연이 생겼고, Head 플러그인으로 ElasticSearch 상태를 볼 수 없게 되었다. 샤드 재배치가 계속 돌면서 클러스터가 불안정해졌다.\n\n다시 전체 재시작을 하자 Head 플러그인이 돌아오고 API 서버 지연이 풀렸으며 헬스 체크도 true 가 되었다. 그러나 샤드 12개가 클러스터로 돌아오지 않았고, 프라이머리 샤드까지 빠져 데이터 일부를 읽을 수 없었다.\n\n_cluster/reroute 의 allocate 명령으로 unassigned 샤드를 옮겨 보려 했지만 오류가 나서 옮기지 못했다."},"updated_at":"2026-11-14T12:34:08.405123Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0434","org_slug":"cyberagent"}