Elastic Stack

Elasticsearch-7.5.0, data backup, snapshot, restore

iKay 2019. 12. 16. 03:02
반응형

 

 

Elasticsearch(엘라스틱서치)에서는 데이터를 백업(back) 하기 위해 data 디렉터리를 copy & paste 해서는 안된다. 백업하기 위한 방법으로 스냅샷(snapshto)이 유일하고 복원하기 위해서는 이 스냅샷으로 부터 restore 해야 한다.

 

다행히도 편리한 스냅샷, 복원을 위해 엘라스틱서치 자체적으로 API를 제공하고 있으며 방법도 어렵지 않다. 심지어 파일 시스템뿐만 아니라 AWS의 S3 등과도 쉽게 연동되도록 여러 플러그인(plugin)도 제공한다

 

현재 최신 버전이 7.5.0이므로 7.5.0 버전의 엘라스틱서치를 기준으로 스냅샷, 백업 방법을 정리한다.

 

스냅샷 방법만 간단히 소개하기 위해 엘라스틱서치 노드의 개수는 1개로 제한했고, 로컬 파일 시스템에 스냅샷이 백업되도록 했다. 실제로 운영하는 상황이라면 노드는 3개 이상, 백업은 DAS/SAN에 해야 할 것이다.  

 

스냅샷 백업 API에 대한 공식문서는 아래 링크를 참고하자.

https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html

 

Snapshot And Restore | Elasticsearch Reference [7.5] | Elastic

The snapshot format can change across major versions, so if you have clusters on different versions trying to write the same repository, snapshots written by one version may not be visible to the other and the repository could be corrupted. While setting t

www.elastic.co

 

1. Dokerized Elasticsearch, Kibana 띄우기 

 

포스팅된 백업 예제를 따라 하기 위해서는 Elasticsearch, Kibana가 필요하다. 이것들을 직접 설치하고 설정하고 적절히 세팅하는 것은 쉽지 않고 오래 걸릴 것이며, 예제의 환경을 그대로 재현하기는 거의 불가능할 것이다. 그래서 Dokerize 된 Elasticsearch과 Kibana를 준비했다. github(https://github.com/hgs0426/elastic-stack-example/tree/master/backup-example01)에서 다운로드하여서 간단히 docker-compose up만 하면 된다. 

 

git clone을 하고 backup-example01이라는 디렉터리로 이동한 후 docker-compose를 up 해서 elasticsearch, kibana 인스턴스 한 대를 실행시킨다. 그 방법을 아래에 정리했다.

 

# script clone
$ git clone git@github.com:hgs0426/elastic-stack-example.git
Cloning into 'elastic-stack-example'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.

# directory 이동
$ cd elastic-stack-example/backup-example01/

# elasticsearch, kibana 실행
$ docker-compose up
Creating network "backup-example01_es" with driver "bridge"
Creating kibana ... done
Creating es01   ... done

 

실행된 후 웹 브라우저를 열어 http://localhost:5601 주소를 통해 Kibana(키바나)에 접속한다. 아래와 같이 접속한 후 왼쪽의 Dev Tools로 접속한다.

 

 

2. 데이터 삽입

 

Dev Tools화면에서 아래와 같이 PUT 명령어로 book이라는 indices에 데이터 1건, movie라는 Indices에 데이터 1건을 삽입하자. 이 데이터를 이번에 스냅샷으로 백업하고 복원해 볼 것이다. 

# book indices 에 데이터 1 건 삽입
PUT /book/_doc/1
{
  "code": 1,
  "title": "엘라스틱서치 실무가이드",
  "subTitle": "한글 검색 시스템 구축부터 대용량 클러스터 운영까지",
  "introduction": "모든 것은 루씬(Lucene)으로 부터 시작됐습니다. 더그 커팅(Doug Cutting)이 고안한 역색인(Inverted Index) 구조는 빠른 검색 결과를 제공하는 데 최적의 성능과 가능성을 보여줬고, 아파치 루씬이라는 걸출한 오픈소스로 세상에 모습을 드러냈습니다. 그리고 얼마 지나지 않아 루씬을 기반으로 분산 처리가 가능하도록 고안한 아파치 솔라(Solr)가 세상에 공개됐습니다.",
  "publisher": "위키북스",
  "price": 38000,
  "PublicationDate": "2019-04-18",
  "authors": ["권택환", "김동우", "박진현", "최용호", "황희정"],
  "type": "IT",
  "language": "Korean"
}

# movie indices 에 데이터 1 건 삽입
PUT /movie/_doc/1
{
  "code": 1,
  "name": "살아남은 아이",
  "openDate": "2017-10-20",
  "type": "장편",
  "genre": "드라마,가족"
}

 

아래는 데이터를 insert 하는 화면이다. 

 

 

3. 스냅샷 리포지토리 생성

아래와 같이 PUT 명령어로 스냅샷 리포지토리를 생성한다. 

PUT _snapshot/data_backup
{
  "type": "fs",
  "settings": {
    "location": "/opt/elasticsearch/backup"
  }
}

# Response
{
  "acknowledged" : true
}

 

위에서 설명하지 않았지만, docker-compose.yml 파일을 보면, es01이라는 이름을 가진 elasticsearch 인스턴스가 실행될 때, 환경변수로 '

path.repo=/opt/elasticsearch/backup' 라는 값을 주입했다. 주입한 이유는 docker container 안에서 '/opt/elasticsearch/backup'라는 곳을 elasticsearch가 스냅샷 리포지토리로 사용하도록 하기 위해서였다. 

 

반드시, elascticsearch를 실행시키기 전에 path.repo가 환경변수로 주입되거나 config.elasticsearch.yml에 입력되어야 하고, 그 후에 위의 PUT 명력어로 스냅샷 리포지토리를 생성해야 한다. 

 

아래 표는 settings 값에 대한 설명이다. 

location 스냅샷 위치. 필수값.
compress 압축을 수행할지 여부. 메타데이터(index mapping, settings)만 압축되고 data는 압축되지 않는다. 기본 값은 true
chunk_size 스냅샷을 하는 동안 파일 크기를 작게 나눌 수 있다. 기본 값은 null로 chunk_size가 무한대이다. 
max_restore_bytes_per_sec 복구(restore)하는 속도. 기본 값은 40mb/s
max_snapshot_bytes_per_sec 스냅샷(snapshot)하는 속도. 기본 값은40mb/s
readonly 리포지토리를 readonly로 만든다. 기본 값은 false

 

잠깐 다른 이야기를 하자면, backup-example01 디렉토리 밑에 data, backup 디렉토리가 docker를 띄울 때 생성될 것인데, docker를 종료시켰다가 다시 실행시켜도 data에 elasticsearch의 데이터가 영속되도록, backup에 스냅샷 리포지토리가 영속되도록 volumes를 아래와 같이 설정했다. 

 

...

  es01: 
    image: elasticsearch:7.5.0
    container_name: es01
    environment: 
      - node.name=es01
      - cluster.name=es-docker-cluster
      - cluster.initial_master_nodes=es01
      - path.repo=/opt/elasticsearch/backup
    volumes:
      - ./data:/usr/share/elasticsearch/data
      - ./backup:/opt/elasticsearch/backup
    networks:
      - es
      
 ...

 

docker-compose.yml 설정에 대한 설명은 이번 포스팅의 주제에 벗어나므로 이 만큼만 설명하고 넘어간다.

 

 

4. 스냅샷 생성(백업)

아래와 같이 PUT 명령어로 'snapshot_20191215'라는 이름의 스냅샷(백업)을 data_backup이라는 스냅샷 리포지토리에 생성할 수 있다. 

 

  • wait_for_completion: 요청이 스냅샷 초기화 직후에 리턴되는지(기본 값), 스냅샷이 완료된 후 리턴되는지 여부이다.
  • indices: 스냅샷 할 indices를 콤마(,)로 구분한다. 즉, 스냅샷은 indicies 단위로 가능하다. 
  • ignore_unavailable:  true 값일 경우, missing되거나 closed 된 indices는 snapshot되지 않는다.(기본 값 alse)
  • Include_global_state: false 인 경우, 클러스터 글로벌 상태가 스냅샷 일부로 저장되지 않는다.
  • metadata: 스냅샷에 대한 메타데이타.  

Response를 보면 알겠지만 indices에 book, movie가 스냅샷 됐음을 알 수 있다.

PUT _snapshot/data_backup/snapshot_20191215?wait_for_completion=true
{
  "indices": "book,movie",
  "ignore_unavailable": true,
  "include_global_state": false,
  "metadata": {
    "taken_by": "kay",
    "taken_because": "daily backup"
  }
}


# Response
{
  "snapshot" : {
    "snapshot" : "snapshot_20191215",
    "uuid" : "YfVo3tBsT36ptSzi6BVoXg",
    "version_id" : 7050099,
    "version" : "7.5.0",
    "indices" : [
      "book",
      "movie"
    ],
    "include_global_state" : false,
    "metadata" : {
      "taken_by" : "kay",
      "taken_because" : "daily backup"
    },
    "state" : "SUCCESS",
    "start_time" : "2019-12-15T17:31:49.490Z",
    "start_time_in_millis" : 1576431109490,
    "end_time" : "2019-12-15T17:31:49.890Z",
    "end_time_in_millis" : 1576431109890,
    "duration_in_millis" : 400,
    "failures" : [ ],
    "shards" : {
      "total" : 2,
      "failed" : 0,
      "successful" : 2
    }
  }
}

 

5. 스냅샷 복원

data_backup의 리포지토리에서 모든 스냅샷을 조회해보자. 스냅샷을 한 후 response와 비슷하다. 

 

GET _snapshot/data_backup/_all

# Response
{
  "snapshots" : [
    {
      "snapshot" : "snapshot_20191215",
      "uuid" : "YfVo3tBsT36ptSzi6BVoXg",
      "version_id" : 7050099,
      "version" : "7.5.0",
      "indices" : [
        "book",
        "movie"
      ],
      "include_global_state" : false,
      "metadata" : {
        "taken_by" : "kay",
        "taken_because" : "daily backup"
      },
      "state" : "SUCCESS",
      "start_time" : "2019-12-15T17:31:49.490Z",
      "start_time_in_millis" : 1576431109490,
      "end_time" : "2019-12-15T17:31:49.890Z",
      "end_time_in_millis" : 1576431109890,
      "duration_in_millis" : 400,
      "failures" : [ ],
      "shards" : {
        "total" : 2,
        "failed" : 0,
        "successful" : 2
      }
    }
  ]
}

 

snapshot_20191215라는 스냅샷본을 복구해보자. 

복구할 때, elasticsearch의 indicies는 중복될 수 없다. 이미 book, movie indices는 생성되었고 삭제한 적이 없으므로 복구를 할 때, indices 이름을 변경해준다. 변경하는 방법은 아래 'rename_pattern', 'rename_replacement'를 보면 알겠지만 indices 앞에 'restored_'라는 prefix를 붙이게 했다. 

 

replace_pattern이 궁금하다면 https://docs.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html#appendReplacement(java.lang.StringBuffer,%20java.lang.String)를 참고하자.

 

POST _snapshot/data_backup/snapshot_20191215/_restore
{
  "indices": "book,movie",
  "ignore_unavailable": true,
  "include_global_state": true,
  "rename_pattern": "(.+)",
  "rename_replacement": "restored_$1"
}

# 정상적인 Response
{
  "accepted" : true
}

# indices가 중첩된 경우
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[data_backup:snapshot_20191215/YfVo3tBsT36ptSzi6BVoXg] cannot restore index [restored_book] because an open index with same name already exists in the cluster. Either close or delete the existing index or restore the index under a different name by providing a rename pattern and replacement name"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[data_backup:snapshot_20191215/YfVo3tBsT36ptSzi6BVoXg] cannot restore index [restored_book] because an open index with same name already exists in the cluster. Either close or delete the existing index or restore the index under a different name by providing a rename pattern and replacement name"
  },
  "status": 500
}

 

6. 복원된 indices 조회

아래와 같이 GET 명령어로 엘라스틱서치의 indices를 볼 수 있다. Response에서 볼 수 있듯이, restored_book, restored_movie가 있다.

GET /_cat/indices?v

# Response
health status index                    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   movie                    U97ZYtwDQpmM5wQ5ka9Fow   1   1          1            0      5.3kb          5.3kb
yellow open   restored_book            leH0Jm2RRaqFIhhPWuRktw   1   1          1            0     11.6kb         11.6kb
green  open   .kibana_task_manager_1   mNKbJ8SnTTKPstWKeYQLXg   1   0          2            1     43.5kb         43.5kb
green  open   .apm-agent-configuration w98nLo4uSjOP9w2ywKHrzQ   1   0          0            0       283b           283b
yellow open   book                     ZKNu4daaTXebn3nUvGMaSA   1   1          1            0     11.7kb         11.7kb
yellow open   restored_movie           o3AZVMuMTwOax_A0f3KAvg   1   1          1            0      5.3kb          5.3kb
green  open   .kibana_1                f58r-466RRW7ed9Lf4pphg   1   0          4            0     16.6kb         16.6kb

 

7. Indices 삭제, snapshot 삭제

불필요한 indicies와 snapshot을 삭제하는 API도 제공한다. 삭제한 경우 복구하기 불가능하므로 신중하게 삭제하자. 

 

# restored_book, restored_movie indices 삭제, 복수의 indices 삭제 가능
DELETE restored_book,restored_movie

# Response
{
  "acknowledged" : true
}
# 스냅샷 삭제
DELETE _snapshot/data_backup/snapshot_20191215

# Response
{
  "acknowledged" : true
}

 

8. 결론

 

다른 DBMS에서는 데이터를 백업(backup)하고 복구(restore)하는 방법은 여러가지이고 그 툴도 천차만별이다. 이와 달리 엘라스틱서치(Elascitsearch)에서 데이터를 백업하고 복구하기 위해서는 스냅샷(snapshot)을 하는 방법이 유일하다. 하지만 데이터를 백업하기 위해 스냅샷 API를 제공하고 있고 이 API만으로도 편리하게 스냅샷, 복구를 할 수 있다고 판단한다. 

 

이번에는 single elasticsearch node, local file system 그리고 많지 않은 데이터로 예제를 진행했지만, 다음 번에는 실제와 같은 환경을 갖춰 엘라스틱서치를 원활히 백업할 수 있도록 실험하고 연습해야 겠다.

 

 

9. 참고

[1] https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html

[2] 엘라스틱서치 실무 가이드(https://wikibook.co.kr/practical-elasticsearch/)

 

반응형