5 minute read

unassigned shards 문제를 해결하기

지금 우리 시스템에선, 3개의 마스터, 데이터 노드 안에 nori tokenizer plugin 을 사용하고 있었다. 그런데 버전업중 하나의 plugin 을 누락하여 shard를 rebalance 하는 과정중 unassigned shard가 생기는 문제가 발생하였다.

unassigned shard 의 원인은 굉장히 다양한데 이걸 어떻게 해결하면 될지 알아보자.


들어가기전에

엘라스틱 서치에서 정상적인 클러스터라 하면 균형이 잘 잡힌 클러스터를 생각할수 있다. primary 샤드와 replica 샤드는 노드에 장애가 생겼을때 지속적인 안정성을 위하여 모든 노드에 분산이 된다.

하지만 UNSIGNED STATE 로 남아 있는 샤드가 있다면 어떻게 처리를 해야 할까?

해결책에 대하여 살펴보기전에 자신의 샤드에 보존해 할 데이터가 있는지 부터 확인해보자 (만약 그렇지 않을 경우 이러한 샤드를 제거하는 것이 문제를 해결하는 가장 간단한 방법.. ㅎㅎ)

저장할 만한 가치가 있는 데이터가 존재한다면 아래 솔루션을 하나씩 살펴보자.

(이 포스트에선 기본포트 :9200 에서 각 Elasticsearch 인스턴스의 HTTP 서비스를 실행하고 있다는 가정하에 형식을 지정한다.)

목차

  1. 문제가 되는 shard 확인
  2. shard 할당이 의도적으로 지연되는 경우
  3. 많은 양의 샤드에 비해 노드가 충분치 못한경우
  4. 샤드 할당을 다시 하도록 설정
  5. 클러스터에 샤드 데이터가 더이상 존재하지 않는 경우

0. 문제가 되는 shard 확인

문제가 되고 있는 shard를 확인해보자.

Elasticsearch의 cat shards API 를 통해 어떠한 shard가 unassigend 상태인지 확인할수 있다.

/_cat/shards?v&h=index,shard,prirep,state,unassigned.reason

만약 5버전 이상의 Elasticsearch 를 사용하고 있다면 [Cluster allocation explain Api] 를 통해 shard allocation 문데에 대한 정보를 얻을수 있다.

curl -XGET localhost:9200/_cluster/allocation/explain?pretty

output 결과는 cluster 안의 shard가 왜 unassigned 상태로 남아있는지 상세정보를 알려준다. (내껀,, 찍기전에 해결을 해버려서, 다른 예시를 가져옴,)

{
  "index" : "testing",
  "shard" : 0,
  "primary" : false,
  "current_state" : "unassigned",
  "unassigned_info" : {
    "reason" : "INDEX_CREATED",
    "at" : "2018-04-09T21:48:23.293Z",
    "last_allocation_status" : "no_attempt"
  },
  "can_allocate" : "no",
  "allocate_explanation" : "cannot allocate because allocation is not permitted to any of the nodes",
  "node_allocation_decisions" : [
    {
      "node_id" : "t_DVRrfNS12IMhWvlvcfCQ",
      "node_name" : "t_DVRrf",
      "transport_address" : "127.0.0.1:9300",
      "node_decision" : "no",
      "weight_ranking" : 1,
      "deciders" : [
        {
          "decider" : "same_shard",
          "decision" : "NO",
          "explanation" : "the shard cannot be allocated to the same node on which a copy of the shard already exists"
        }
      ]
    }
  ]
}

위의 상세 정보를 읽어보면 replica shard가 왜 unassigned 상태로 남아있는지 확인이 가능하다. “shard의 복사본이 이미 존재하는 동일한 노드에는 shard를 할당 할수 없다”라는 메세지이다. 이문제에 대한 해결책은 아래서 확인이 가능하다.

할당되지 않는 shard가 이미 삭제했다고 생각한 인덱스에 속하거나, 더이상 필요하지 않은 오래된 인덱스에 속하는것이라면 index를 삭제하여 cluster의 상태를 녹색으로 복원하는것이 가능하다.

curl -XDELETE 'localhost:9200/index_name/'

여전히 문제가 해결되지 않았다면 다른 해결책을 아래서 추가로 확인해보자.

1. shard 할당이 의도적으로 지연되는 경우

node가 cluster를 벗어날때, primary 노드는 일정 시간(default 1분) 내에 원래 노드를 복구할 수 있는 경우 리소스를 불필요하게 낭비 하지 않도록 일시적으로 shard 재할당을 지연한다. 이 겨우 로그는 아래와 같이 표시 된다.

[TIMESTAMP][INFO][cluster.routing] [PRIMARY NODE NAME] delaying allocation for [54] unassigned shards, next check in [1m]

우리는 이걸 동적으로 지연 시간을 조정할수 있다.

curl -XPUT "localhost:9200/<INDEX_NAME>/_settings?pretty" -H 'Content-Type: application/json' -d'
{
    "settings": {
        "index.unassigned.node_left.delayed_timeout: "5m"
    }
}

특정 을 _all 로 변경시 모든 인덱스에 대해 위 세팅값을 적용할 수 있다. delay time 이 끝나면 primary shard의 할당이 제대로 이루어 지는지 확인해보자, 그래도 해결이 되지 않는경우, 다른 해결책을 확인해보자.

2. 많은 양의 샤드에 비해 노드가 충분치 못한경우

node가 cluster에 join 하고 떨어질때, primary node는 자동으로 shard를 재할당 하므로 동일한 node에 여러 개의 replica shard가 할당 되지는 않는다. 즉, primary node는 replica와 동일한 노드에 primary shard를 할당하지 않으며, 동일한 replica shard 두개를 동일한 node 에 할당 받지 않는다/ 이에 따라 shard 를 분배하기에 충분한 node 가 없다면 shard 가 할당되지 않는 상태로 남게 된다.

이 문제를 방지하기 위해 아래 공식에 따라 cluster 의 모든 index가 cluster 에 있는 모든 node 수보다 primary shard 당 replica수가 적도록 초기화를 해야한다.

N >= R+1 (N: 노드, R: cluster의 모든 index 에서 가장크게 설정된 replica shard 수)

replica 의 수를 줄이는건 언제든 가능하므로 아래 명령어를 통해 replica 의 수를 줄이도록 하자.

curl -XPUT "localhost:9200/<INDEX_NAME>/_settings?pretty" -H 'Content-Type: application/json' -d' { "number_of_replicas": 2 }'

3. 샤드 할당을 다시 하도록 설정

shard 할당을 사용하도록 설정하려면 Cluster Update Settings API 를 통해 가능하다.

우리에게 Cluster 관리 권한이 존재한다면, 우리는 이 API 를 통해 동적으로 실행중인 Cluster 를 업데이트하고 설정할수 있다. 이 API를 통해 elasticsearch.yml 를 수정하고 재시작 하지 않고도 설정 변경이 가능하다.

Elasticsearch 에서 설정을 셋팅하는 방법은 여러가지가 있는데, 같은 기능에 대해서 우선순위는 아래와 같이 부여된다.

  1. Transient setting
  2. Persistent setting
  3. elasticsearch.yml setting
  4. Default setting value

3-1. Transient Setting

  • 1회성 설정
  • 클러스터 재시작할 경우 리셋

3-2. Persistent

  • 영구적인 설정
  • 클러스터 재시작하더라도 유지

3-3. elasticsearch.yml

  • 해당 설정은 로컬 구성으로만 사용하도록 권고
  • dynamic 설정을 통해 클러스터 설정을 관리
    • static 설정의 경우 elasticsearch.yml에 구성하며, 클러스터가 시작하기 전에 설정되어야 한다.
  • 각 노드 별로 설정이 다를 경우 문제 발생할 수 있으므로 주의

3-4. Default

  • 코드 상에 정의되어 있는 설정

이러한 설정에 관해서는 다음 포스팅에서 다시 한번 확인해보도록 하고 다시 본론으로 돌아가자.

아래는 Cluster Update Setting API 요청 방법이다.

curl -X PUT "localhost:9200/_cluster/settings?pretty" -H 'Content-Type: application/json' -d'
{
    "transient" : {
        "cluster.routing.allocation.enable" : "all"
    }
}
'

4. 클러스터에 샤드 데이터가 더이상 존재하지 않는 경우

이 경우는 index의 primary shard 0 이 할당 되지 않은 경우이다. replica node 가 없는 노드 에서 발생했을수도 있고 (초기 indexing process 속도를 높이는데 주로 씀), replica node 가 없는 상태에서 node 가 cluster 에서 이동한경우, 기본적으로 global cluster 상태 파일에서 shard를 검색하지만 이러한경우 shard의 데이터를 찾을수 없다.

또는 재부팅 하는 동안 node 에 문제가 발생했을수도 있다. 일반적으로 node 가 cluster에 다시 연결을 재개할 떄, disk shard에 대한 정보를 primary shard 로 전달한 다음 해당 shard 를 “unassigned” 에서 “assigned/started” 상태로 돌린다.

만약 이 과정에서 어떠한 이유로 실패가 된다면, shard 는 unassigned 상태로 남아있게 되는것이다.

이러한 시나리오에서 우리는 원래 노드가 복구되어 클러스터에 다시 연결되도록 하거나 (primary shard를 강제 할당하지 않음), Cluster Reroute API 를 사용하여, shard를 강제로 할당하고 원본 데이터 소스를 사용하여 shard 를 강제 할당하고 원본 데이터 소스를 사용하여 누락된 데이터를 다시 인덱싱 하거나 백업에 대시 인덱싱하는 방법중 선택할수 있다.

만약 후자를 선택한 경우, 이 방법은 __텅빈 shard__를 할당한다는 것을 알아두자, 만약 원본의 primary shard data가 포함된 노드가 나중에 cluster 에 다시 조인 하는 경우, 새로 생성된 (비어있는) shard 에 의해 덮어 쓰이게 된다.

다른 옵션도 존재하니, 반드시 API 를 직접 확인해 보도록 하자.

curl -XPOST "localhost:9200/_cluster/reroute?pretty" -H 'Content-Type: application/json' -d'
{
    "commands" : [
        {
          "allocate_empty_primary" : {
                "index" : "constant-updates", 
                "shard" : 0,
                "node" : "<NODE_NAME>", 
                "accept_data_loss" : "true"
          }
        }
    ]
}
'