ElasticsearchKibanaAWSS3NCPObject Storage

Elasticsearch 백업하기 (with Kibana)

2022.12.09


현재(2022.12.10. 00:33 기준) PRV Elasticsearch 서버에는 1개의 Elasticsearch 노드만 존재하고, 데이터는 약 700만개, 용량은 32.16GB를 차지하고 있다. index management

사용중인 Elasticsearch 서버의 스펙

NCP [Standard] 2vCPU, 4GB Mem, 50GB Disk [g1]

50GB는 금새 바닥날 것이고, 4GB 메모리는 80~90% 대 사용률을 보이며, CPU는 평균 10% 미만으로 사용중이다. 샤드를 구성하기에는 상당히 부족한 스펙이었지만, 단일 노드로도 300ms 내에 결과를 받아오고 있고, 아직까지 사용자가 서비스를 이용함에 부족함이 없는 상황이다.

추후 부하테스트를 진행해본다면 어떤 결과가 나올지 궁금하다.

Elasticsearch를 DB로 사용한 이유

  1. 사용자에게 검색에 대한 응답을 빠르게 할 것

  2. 외부 API인 Crossref로부터 데이터를 가져오는 병목을 최대한 줄일 것

  3. Crossref에는 약 1억개 이상의 데이터가 있고 용량은 약 160GB 정도이다.

    이 정도 되는 데이터에도 정상적으로 검색이 잘 작동할 수 있는 구조를 쉽게 만들 수 있어야했다.

    inverted index 방식의 저장방식은 데이터가 많아지더라도 새롭게 데이터가 저장 될 때 큰 저하를 일으키지 않을 수 있었고, 샤딩을 통해 빠른 검색 속도와 안전한 data 저장 방식을 보다 쉽게 구성할 수 있었다.

백업을 해야겠다고 생각한 이유

  • 최초에는 docker compose를 사용하여 single-node로 Elasticsearch 서버를 띄워놨었고, 샤드를 구성하기위해 container를 중지하고 다시 시작할 경우 데이터가 날아가버리면 어떡하나 하는 걱정이 있었다.

  • crossref로부터 데이터를 가져오는 것은 만만치않은 작업이었기에, 한번 저장해놨던 데이터가 우리 DB에서 사라져서 또 다시 요청해야하는 번거로움을 없애고 싶었고, 따라서 백업 데이터를 가지고 있고 싶었다.

    • 200만개 이상의 데이터가 저장되어있던 상태였기에, 이 정보를 날리기에는 너무 아까웠다.
  • Crossref에서는 torrent로 약 160GB의 논문 정보를 제공한다.

    API로 검색했을 때 볼 수 있는 정보들이 토렌트로 제공되어지는 것을 확인하였고, 다운로드해서, elasticsearch에 집어넣으면 검색엔진이 만들어지겠구나! 라고 생각했었다.

    • 하지만, torrent 파일에는 피어가 제공되지 않아서 다운로드 예상 시간이 한달이 훌쩍 넘어갔다.
    • 따라서 당장 서비스를 제공해야하는 입장에서, 차근차근 crossref로부터 데이터를 가져오는 작업을 진행하는게 낫겠다는 판단을 했다.

ElasticSearch에서 제공하는 snapshot 기능

  • elasticsearch에서 제공하는 snapshot 기능을 사용해서 snapshot 내용을 S3에 업로드 가능하다.
  • NCP Object Storage는 AWS S3 API를 사용해서 접근할 수 있다.
    • AWS S3 요금(Ohio 기준)
      • 저장소 : 최초 50TB / Month $0.023 per GB,
      • 데이터 전송
        • In : 무료
        • Out : (최초 100GB 무료) First 10TB / Month $0.09 per GB
    • NCP Object Storage 요금 (VAT 별도)
      • 1PB 이하 : 월 평균 저장량 GB 당 28원
      • 1PB 초과 : 월 평균 저장량 GB 당 26원
  • Snapshot을 진행하기전에 AWS S3 또는 NCP Object Storage에 버킷을 생성한다.
    • AWS IAM으로 생성한 사용자에게 AmazonS3FullAccess 권한을 부여하고, Access-key와 Secret-key를 기록해둔다.
    • NCP를 사용할 경우, Sub Account 를 생성해주어도 되고, 계정의 마이페이지-계정관리-인증키 관리에서 Access Key ID와 Secret key를 기록해둔다.
      • Sub Account를 사용한다면, NCP_OBJECT_STORAGE_MANAGER 권한이 부여되어야한다.

공식 document를 보면 어떻게 repository를 생성하고, snapshot을 execute 하는지 확인할 수 있다.

REST API를 사용해서 repository를 생성하고 snapshot 관련 policy를 작성할 수 있는데, Kibana를 통해서 관리하는 것도 편리하다.

elasticsearch single node + kibana 연결하기(docker-compose)
  • docker-compose.yml

    version: "3.8"
    
    services:
      setup:
        image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
        volumes:
          - certs:/usr/share/elasticsearch/config/certs
        user: "0"
        command: >
          bash -c '
            if [ ! -f config/certs/ca.zip ]; then
              echo "Creating CA";
              bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip;
              unzip config/certs/ca.zip -d config/certs;
            fi;
            if [ ! -f config/certs/certs.zip ]; then
              echo "Creating certs";
              echo -ne \\
              "instances:\\n"\\
              "  - name: esnode1\\n"\\
              "    dns:\\n"\\
              "      - esnode1\\n"\\
              "      - localhost\\n"\\
              "    ip:\\n"\\
              "      - 127.0.0.1\\n"\\
              > config/certs/instances.yml;
              bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key;
              unzip config/certs/certs.zip -d config/certs;
            fi;
            echo "Setting file permissions"
            chown -R root:root config/certs;
            find . -type d -exec chmod 750 \\{\\} \\;;
            find . -type f -exec chmod 640 \\{\\} \\;;
            echo "Waiting for Elasticsearch availability";
            until curl -s --cacert config/certs/ca/ca.crt <https://esnode1:9200> | grep -q "missing authentication credentials"; do sleep 30; done;
            echo "Setting kibana_system password";
            until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" <https://esnode1:9200/_security/user/kibana_system/_password> -d "{\\"password\\":\\"${KIBANA_PASSWORD}\\"}" | grep -q "^{}"; do sleep 10; done;
            echo "Good to go!";
          '
      esnode1:
        depends_on:
          - setup
        image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
        volumes:
          - certs:/usr/share/elasticsearch/config/certs
          - esnode1-data:/usr/share/elasticsearch/data
        ports:
          - ${ES_PORT}:9200
        environment:
          - node.name=esnode1
          - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
          - bootstrap.memory_lock=true
          - discovery.type=single-node
          - xpack.security.enabled=true
          - xpack.security.http.ssl.enabled=true
          - xpack.security.http.ssl.key=certs/esnode1/esnode1.key
          - xpack.security.http.ssl.certificate=certs/esnode1/esnode1.crt
          - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
          - xpack.security.http.ssl.verification_mode=certificate
          - xpack.security.transport.ssl.enabled=true
          - xpack.security.transport.ssl.key=certs/esnode1/esnode1.key
          - xpack.security.transport.ssl.certificate=certs/esnode1/esnode1.crt
          - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
          - xpack.security.transport.ssl.verification_mode=certificate
          - xpack.license.self_generated.type=${LICENSE}
        ulimits:
          memlock:
            soft: -1
            hard: -1
    
      kibana:
        depends_on:
          - esnode1
        image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
        volumes:
          - certs:/usr/share/kibana/config/certs
          - kibana-data:/usr/share/kibana/data
        ports:
          - ${KIBANA_PORT}:5601
        environment:
          - SERVERNAME=kibana
          - ELASTICSEARCH_HOSTS=https://esnode1:${ES_PORT}
          - ELASTICSEARCH_USERNAME=kibana_system
          - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
          - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
    
    volumes:
      certs:
        driver: local
      esnode1-data:
        driver: local
      kibana-data:
        driver: local
    
  • setup → elasticsearch → kibana 순으로 서비스가 띄워진다.

  • setup에서는 cert 파일을 만들어서 elasticsearch와 ssl 통신을 하도록 한다.

  • ssl 설정이 불필요하다면, xpack.security.enable=false 로 하고, 이후 하단부에 있는 environment 들은 지워주면 된다.

    # .env
    STACK_VERSION=8.5.1
    ELASTIC_PASSWORD=<your elastic password>
    KIBANA_PASSWORD=<your kibana password>
    ES_PORT=9200
    LICENSE=basic
    KIBANA_PORT=5601
    
    docker compose up --env-file .env up -d
    
만약 2개의 shard를 생성하고 싶다면 아래와 같은 docker compose 파일을 사용하면 된다.
  • 다만, RAM 4GB 에서는 이 정도로도 elasticsearch 서비스가 unexpected exit 되곤 한다.

    version: "3.8"
    
    services:
      setup:
        container_name: setup
        image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
        volumes:
          - certs:/usr/share/elasticsearch/config/certs
        user: "0"
        command: >
          bash -c '
            if [ ! -f config/certs/ca.zip ]; then
              echo "Creating CA";
              bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip;
              unzip config/certs/ca.zip -d config/certs;
            fi;
            if [ ! -f config/certs/ca.zip ]; then
              echo "Creating certs";
              echo -ne \\
              "instances:\\n"\\
              "  - name: esmaster\\n"\\
              "    dns:\\n"\\
              "      - esmaster\\n"\\
              "      - localhost\\n"\\
              "    ip:\\n"\\
              "      - 127.0.0.1\\n"\\
              "  - name: es01\\n"\\
              "    dns:\\n"\\
              "      - es01\\n"\\
              "      - localhost\\n"\\
              "    ip:\\n"\\
              "      - 127.0.0.1\\n"\\
              "  - name: es02\\n"\\
              "    dns:\\n"\\
              "      - es02\\n"\\
              "      - localhost\\n"\\
              "    ip:\\n"\\
              "      - 127.0.0.1\\n"\\
              > config/certs/instances.yml;
              bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key;
              unzip -o config/certs/certs.zip -d config/certs;
            fi;
            echo "Setting file permissions"
            chown -R root:root config/certs;
            find . -type d -exec chmod 750 \\{\\} \\;;
            find . -type f -exec chmod 640 \\{\\} \\;;
            echo "Waiting for Elasticsearch availability";
            until curl -s --cacert config/certs/ca/ca.crt <https://esmaster:9200> | grep -q "missing authentication credentials"; do sleep 30; done;
            echo "Setting kibana_system password";
            until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" <https://esmaster:9200/_security/user/kibana_system/_password> -d "{\\"password\\":\\"${KIBANA_PASSWORD}\\"}" | grep -q "^{}"; do sleep 10; done;
            echo "Setup Finished";
          '
      esmaster:
        container_name: esmaster
        depends_on:
          - setup
        image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
        volumes:
          - certs:/usr/share/elasticsearch/config/certs
          - esmasterdata:/usr/share/elasticsearch/data
        ports:
          - ${ES_PORT}:9200
        environment:
          - node.name=esmaster
          - cluster.name=${CLUSTER_NAME}
          - cluster.initial_master_nodes=esmaster,es01,es02
          - discovery.seed_hosts=es01,es02
          - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
          - bootstrap.memory_lock=true
          - xpack.security.enabled=true
          - xpack.security.http.ssl.enabled=true
          - xpack.security.http.ssl.key=certs/esmaster/esmaster.key
          - xpack.security.http.ssl.certificate=certs/esmaster/esmaster.crt
          - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
          - xpack.security.http.ssl.verification_mode=certificate
          - xpack.security.transport.ssl.enabled=true
          - xpack.security.transport.ssl.key=certs/esmaster/esmaster.key
          - xpack.security.transport.ssl.certificate=certs/esmaster/esmaster.crt
          - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
          - xpack.security.transport.ssl.verification_mode=certificate
          - xpack.license.self_generated.type=${LICENSE}
        mem_limit: ${MEM_LIMIT}
        ulimits:
          memlock:
            soft: -1
            hard: -1
    
      es01:
        container_name: es01
        depends_on:
          - esmaster
        image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
        volumes:
          - certs:/usr/share/elasticsearch/config/certs
          - esdata01:/usr/share/elasticsearch/data
        environment:
          - node.name=es02
          - cluster.name=${CLUSTER_NAME}
          - cluster.initial_master_nodes=esmaster,es01,es02
          - discovery.seed_hosts=esmaster,es02
          - bootstrap.memory_lock=true
          - xpack.security.enabled=true
          - xpack.security.http.ssl.enabled=true
          - xpack.security.http.ssl.key=certs/es01/es01.key
          - xpack.security.http.ssl.certificate=certs/es01/es01.crt
          - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
          - xpack.security.http.ssl.verification_mode=certificate
          - xpack.security.transport.ssl.enabled=true
          - xpack.security.transport.ssl.key=certs/es01/es01.key
          - xpack.security.transport.ssl.certificate=certs/es01/es01.crt
          - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
          - xpack.security.transport.ssl.verification_mode=certificate
          - xpack.license.self_generated.type=${LICENSE}
        mem_limit: ${MEM_LIMIT}
        ulimits:
          memlock:
            soft: -1
            hard: -1
    
      es02:
        container_name: es02
        depends_on:
          - es01
        image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
        volumes:
          - certs:/usr/share/elasticsearch/config/certs
          - esdata02:/usr/share/elasticsearch/data
        environment:
          - node.name=es02
          - cluster.name=${CLUSTER_NAME}
          - cluster.initial_master_nodes=esmaster,es01,es02
          - discovery.seed_hosts=esmaster,es01
          - bootstrap.memory_lock=true
          - xpack.security.enabled=true
          - xpack.security.http.ssl.enabled=true
          - xpack.security.http.ssl.key=certs/es02/es02.key
          - xpack.security.http.ssl.certificate=certs/es02/es02.crt
          - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
          - xpack.security.http.ssl.verification_mode=certificate
          - xpack.security.transport.ssl.enabled=true
          - xpack.security.transport.ssl.key=certs/es02/es02.key
          - xpack.security.transport.ssl.certificate=certs/es02/es02.crt
          - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
          - xpack.security.transport.ssl.verification_mode=certificate
          - xpack.license.self_generated.type=${LICENSE}
        mem_limit: ${MEM_LIMIT}
        ulimits:
          memlock:
            soft: -1
            hard: -1
    
      kibana:
        container_name: kibana
        depends_on:
          - esmaster
          - es01
          - es02
        image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
        volumes:
          - certs:/usr/share/kibana/config/certs
          - kibana-data:/usr/share/kibana/data
        ports:
          - ${KIBANA_PORT}:5601
        environment:
          - SERVERNAME=kibana
          - ELASTICSEARCH_HOSTS=https://esmaster:${ES_PORT}
          - ELASTICSEARCH_USERNAME=kibana_system
          - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
          - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
        mem_limit: ${MEM_LIMIT}
    
    volumes:
      certs:
        driver: local
      esmasterdata:
        driver: local
      esdata01:
        driver: local
      esdata02:
        driver: local
      kibana-data:
        driver: local
    

<ip>:5601 로 kibana에 접근하면 아래와 같은 화면을 확인할 수 있다.

Main

  • elastic 계정으로 로그인

    After login

  • 굳이 Integration를 추가하지 않아도 된다. Explore on my own 을 클릭 후 추후 설정하자.

  • 검색창에서 snapshot을 검색하면 Snapshot and Restore 메뉴를 확인할 수 있다.

    snapshot and restore

  • Register a repository 클릭 후, AWS S3을 클릭하여 버킷에 대한 설정을 진행한다.

    aws s3

  • required 만 입력하면 되며, NCP Object Storage나 S3의 버킷 이름을 입력해주면 된다.

    NCP bucket

repository

  • AWS S3 repository를 생성했을 때, elasticsearch는 s3.amazonaws.com 을 default endpoint로 갖는다.

    • 만약, NCP Object Storege를 쓴다면 endpoint를 입력해주어야한다.

      echo "endpoint: kr.object.ncloudstorage.com" >> config/elasticseach.yml
      
  • AWS / NCP에서 계정의 Access key와 Secret Key를 elasticsearch.keystore에 입력해주어야한다.

    docker exec -it esmaster sh
    
    sudo ./bin/elasticsearch-keystore add s3.client.default.access_key
    > Acess key 입력
    
    sudo ./bin/elasticsearch-keystore add s3.client.default.secret_key
    > Secret key 입력
    
  • 이후 POST _nodes/reload_secure_settings 로 요청을 보내면 cluster setting만 다시 불러온다.

    # example
    curl -X POST https://<id>:<pw>@<host>/_nodes/reload_secure_settings
    
  • 그 다음, Kibana에서 연결 상태를 확인해보자. (아래 사진은 AWS S3를 Repository로 사용했다.)

    • Verification status가 Connected 임을 확인할 수 있다.

    connected

  • 이제 언제마다 Snapshot을 찍을 것인지 정책(Policies)를 설정해주어야한다.

    Policies - Create policy 에서 Policy에 대한 기본 정보를 작성한다.

    policy

    • Snapshot name에는 특이한 규칙이 추가되는데, 아래와 같다.

      <static_name{date_math_expr{date_format|time_zone}}>
      

      ex) <logstash-{now/d}>logstash-2024.03.22 로 변환된다.

      더 자세한 내용은 링크 참고

      elastic docs : api-date-math-index-names

  • 이후 Snapshot에 대한 설정들을 해주면 된다.

    snapshot setting

    snapshot retention

    review policy

  • 이제 생성한 Policy를 확인해볼 수 있고, 바로 실행시켜 볼수도 있다.

    policy

  • PRV에 있는 700만개의 논문 데이터(약 32.1GB) 를 S3에 집어넣는데에는 10분정도 소요되었다.

    snapshoted

이런식으로 스냅샷을 찍어두고 외부 저장소에 저장해둘 수도 있지만, 이러한 설정을 하는 중에 휴먼에러로 데이터를 쉽게 날릴 수도 있다.

+스냅샷의 장점은, 주기적으로 변화된 내용들에 대해서만 스냅샷을 찍을 수 있다는 점이다. (처음 스냅샷을 찍는데 3시간 걸린 후, 그 다음에 스냅샷을 찍는다면 3시간+a가 아니라, a만큼의 시간만 걸린다.)

백업하는 가장 쉬운 방법은 elasticsearch에 들어가있는 정보들을 offset을 두고 처음부터 끝까지 조회하면서 저장하는 것이다.

이 때, Elasticdump 라이브러리를 사용하면 꽤나 편하다.

Elasticdump 설치 & 실행

GitHub elasticsearch dump

npm install -g elasticdump # 또는
npm install elasticdump
  • global로 설치하지 않았다면 아래와 같이 실행할 수 있다. (global로 설치했다면 그냥 elasticdump 로 실행하면 된다.)

    ./node_modules/elasticdump/bin/elasticdump \\                 
      --input=http(s)://<id>:<password>@<host:port>/<index_name> \\
      --output=./backup.json --noRefresh --limit 1000
    
  • --input : data가 저장되어있는 장소

  • --output : data가 저장될 장소

    • 위의 예시는 export이고, input과 output 내용을 바꾸면 import가 된다.
  • --noRefresh : 명령 실행 이후 새롭게 추가되는 데이터는 가져오지 않음

  • --limit : default는 데이터를 100개씩 가져오도록 되어있어서, 0.5초에 100개씩 가져올 수 있다고 해도 200만개를 갖고오기 위해서는 167시간 정도가 걸린다.

    • limit을 1000개로 했을 때, export에 2시간 정도 걸렸다.

      ...
      Wed, 07 Dec 2022 04:10:00 GMT | got 1000 objects from source elasticsearch (offset: 2427000)
      Wed, 07 Dec 2022 04:10:00 GMT | sent 1000 objects to destination file, wrote 1000
      Wed, 07 Dec 2022 04:10:01 GMT | got 418 objects from source elasticsearch (offset: 2428000)
      Wed, 07 Dec 2022 04:10:01 GMT | sent 418 objects to destination file, wrote 418
      Wed, 07 Dec 2022 04:10:01 GMT | got 0 objects from source elasticsearch (offset: 2428418)
      Wed, 07 Dec 2022 04:10:01 GMT | Total Writes: 2428418
      Wed, 07 Dec 2022 04:10:01 GMT | dump complete
      
    • limt을 1000개로 했을 때, import에는 3시간 정도 걸렸다.

      ...
      Wed, 07 Dec 2022 17:23:45 GMT | sent 1000 objects to destination elasticsearch, wrote 1000
      Wed, 07 Dec 2022 17:23:45 GMT | got 1000 objects from source file (offset: 1691000)
      Wed, 07 Dec 2022 17:23:47 GMT | sent 1000 objects to destination elasticsearch, wrote 1000
      Wed, 07 Dec 2022 17:23:47 GMT | got 1000 objects from source file (offset: 1692000)
      Wed, 07 Dec 2022 17:23:50 GMT | sent 1000 objects to destination elasticsearch, wrote 1000
      Wed, 07 Dec 2022 17:23:50 GMT | got 1000 objects from source file (offset: 1693000)
      ...
      
      • 로그를 살펴보면, from source elasticsearchto destination file or

        from source fileto destination elasticsearch 여부를 확인해볼 수 있다.

  • backup.json을 확인해보면 대략 7.6GB 인 것을 확인할 수 있다.

    -rw-r--r--    1 iseongbin  staff  8168239894 Dec  7 13:10 backup.json
    
  • backup.json은 아래와 같은 형태로 저장된다.

    // backup.json
    {"_index":"papers","_id":"10.1016/j.jpowsour.2013.08.051","_score":1,"_source":{"id":"10.1016/j.jpowsour.2013.08.051","title":"A comparative study of different binders and their effects on electrochemical properties of LiMn 2 O 4 cathode in lithium ion batteries","authors":["Zhian Zhang","Tao Zeng","Yanqing Lai","Ming Jia","Jie Li"],"doi":"10.1016/j.jpowsour.2013.08.051","publishedAt":"2013-08-27T17:32:23Z","citations":150,"references":41,"referenceList":[{"key":"10.1039/c1ee01388b","title":"Energy Environ. Sci.","doi":"10.1039/c1ee01388b"},{ ... }]}}
    {"_index":"papers","_id":"10.1039/c2jm35293a","_score":1,"_source":{"id":"10.1039/c2jm35293a","title":"High voltage cathode materials for Na-ion batteries of general formula Na3V2O2x(PO4)2F3−2x","authors":["Paula Serras","Verónica Palomares","Aintzane Goñi","Izaskun Gil de Muro","Pierre Kubiak","Luis Lezama","Teófilo Rojo"],"doi":"10.1039/c2jm35293a","publishedAt":"2012-09-07T11:00:44Z","citations":150, ... },
    ...
    
  • 만약, http 통신을 통해 https로 데이터를 전송하려다보면, 아래와 같은 오류가 날 것이다.

    Wed, 07 Dec 2022 12:31:01 GMT | starting dump
    Wed, 07 Dec 2022 12:31:02 GMT | got 100 objects from source file (offset: 0)
    Wed, 07 Dec 2022 12:31:02 GMT | Error Emitted => unable to verify the first certificate
    Wed, 07 Dec 2022 12:31:02 GMT | Error Emitted => unable to verify the first certificate
    Wed, 07 Dec 2022 12:31:02 GMT | Total Writes: 0
    Wed, 07 Dec 2022 12:31:02 GMT | dump ended with error (get phase) => Error: unable to verify the first certificate
    

    이 때 가장 편한 방법은, UNAUTHORIZED에 대해 REJECT하지 말도록 환경변수를 설정하는 것이다.

    (다만 이 때는, 내가 통제할 수 있는 환경이어야하겠다.)

     export NODE_TLS_REJECT_UNAUTHORIZED=0 && ./node_modules/elasticdump/bin/elasticdump --input ./backup.json --output=https://<id>:<password>@<ip>:<port>/<index_name>
    

    또는 elasticsearch에서 사용하는 ca.crt 파일, key를 주입시켜줘도 되겠다.

    ./node_modules/elasticdump/bin/elasticdump \\ 
        --input ./backup.json \\
        --output=https://elastic:sf9ouRmIr0MLawM77SDL@localhost:9200/papers \\
        --ca ca.crt \\
        --cacert esnode.crt \\
      --key esnode.key
    
    • ca.crt / esnode.crt / esnode.key 는 어떻게 확인할 수 있을까?

      docker exec -it esnode1 sh
      cd config/cert/ca
      ls
      

      위와 같이 직접 접근해서 해당 값을 확인해도 되고,

      docker cp esnode:/usr/share/elasticsearch/config/cert/ca/ca.crt .
      

      위와 같이 파일을 복사해서 가져와도 되겠다.

  • cloud 환경에서 elasticsearch에 여러개의 샤드를 두려다보면 아래와 같은 에러가 발생할 수 있다.

    esmaster  | bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
    

    이미지에 대한 기본 메모리 할당이 부족하다는 이야기이다.

    Virtual memory | Elasticsearch Guide [8.5] | Elastic

    서버가 재시작되어도 이 설정이 유지되려면 직접 conf 파일을 수정해야한다.

    /etc/sysctl.conf 파일의 맨 하단에 vm.max_map_count=262144 를 아래와 같이 추가하자.

    # /etc/sysctl.conf
    ...
    # sec
    net.ipv4.tcp_syncookies = 1
    net.ipv4.conf.all.accept_redirects = 0
    net.ipv4.conf.all.accept_source_route = 0
    net.ipv4.conf.all.log_martians = 1
    net.ipv4.icmp_ignore_bogus_error_responses = 1
    net.ipv4.icmp_echo_ignore_broadcasts = 1
    net.ipv4.conf.all.rp_filter = 1
    vm.max_map_count=262144
    

이후 잘 적용되었나 확인한다.

sudo sysctl -p
# net.ipv4.conf.all.arp_notify = 1
# net.ipv4.tcp_syncookies = 1
# net.ipv4.conf.all.accept_redirects = 0
# net.ipv4.conf.all.accept_source_route = 0
# net.ipv4.conf.all.log_martians = 1
# net.ipv4.icmp_ignore_bogus_error_responses = 1
# net.ipv4.icmp_echo_ignore_broadcasts = 1
# net.ipv4.conf.all.rp_filter = 1
# vm.max_map_count = 262144

cat /proc/sys/vm/max_map_count
# 262144

백업에 대한 회고

  • NCP 서버 스펙에 알맞은 Elasticsearch / Kibana 환경을 설정하는 것은 꽤나 고통스러웠다. 샤드를 몇개를 설정해야하는지 고민이 들었고, 실험해본 결과, 1개만 돌려도 메모리가 부족할 수 있는 상태임을 확인했다.
  • Kibana 설정은 굳이 필요하진 않다. Elasticsearch에 REST API를 사용할 수 있다. 다만, GUI는 초심자에게 많은 도움을 준다.
  • 현재 인스턴스의 디스크 용량이 80%를 넘었다. 700만개의 논문 정보를 수집하는데에는 5일정도 걸린 것 같다. 물론 항상 request batch가 돌아가던 것은 아니었지만, 논문 정보를 수집하기 위해서는 많은 리소스가 소요된다. 서버가 터질 것을 대비하고, DB의 확장성을 고려했을 때, Snapshot을 찍어놓는 것은 좋은 선택인 것 같다. 백업을 해놓으니 안심이 된다.
  • 나중에 서버가 날아가더라도, 다시 docker-compose를 활용하여 Kibana 세팅을 하고, S3에 연결하여 restore를 하면 될 것으로 예상된다.

추가 참고자료