ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ClickHouse] ReplicatedMergeTree 테이블 Backup 적용하기
    Database/Clickhouse 2024. 2. 29. 07:04
    반응형

    - 목차

     

    들어가며.

    이번 글에서는 ReplicatedMergeTree 테이블을 BackupRestore 하는 방법에 대해서 알아보도록 하겠습니다.

     

    먼저 ReplicatedMergeTree 에 대해서 간단히 이야기해보겠습니다.

    ReplicatedMergeTree 는 최소 2개의 ClickHouse Replica 들이 필요합니다.

    그리고 이 Replica 들은 새롭게 생성된 Part 파일 정보를 서로 공유하며 Replication 을 수행하게 됩니다.

    이들이 복제를 위한 수단으로 Zookeeper 를 사용합니다.

    각 Replica 는 클라이언트의 요청에 의해서 새롭게 생성된 Part 정보를 Zookeeper Znode 에 기록하고,

    다른 Replica 는 Watcher 로써 생성된 Part 에 대한 알림을 받아 Part 를 복사합니다.

     

    Backup 과 Restore 는 altinity/clickhouse-backup 도커 이미지를 기반으로 실습해 볼 예정이며,

    아래 링크의 내용을 통해서 MergeTree Table 을 백업하는 기본적인 내용을 습득하실 수 있습니다.

     

    https://westlife0615.tistory.com/669

     

    [ClickHouse] MergeTree 테이블 Backup 하기 ( clickhouse-backup )

    - 목차 들어가며.이번 글에서는 Altinity clickhouse-backup 이미지를 기반으로 ClickHouse 의 MergeTree 테이블을 Backup 하는 방법에 대해서 알아봅니다. https://hub.docker.com/r/altinity/clickhouse-backup https://hub.docke

    westlife0615.tistory.com

     

     

    ClickHouse 환경 구축.

    ReplicatedMergeTree Table 생성을 위해서 1-Shard & 2-Replicas 구조의 ClickHouse Cluster 를 먼저 생성합니다.

    그리고 ReplicatedMergeTree 를 사용하기 위해서는 Zookeeper 가 함께 동반되어야 합니다.

     

    먼저 ClickHouse Cluster 를 구축할 설정 파일을 생성합니다.

    아래의 명령어는 Zookeeper 와 ClickHouse 서버들의 관계를 명시한 config.xml 설정 파일입니다.

     

    cat <<'EOF'> /tmp/config.xml
    <yandex>
        <zookeeper>
            <node index="1">
                <host>zookeeper1</host>
                <port>2181</port>
            </node>
            <node index="2">
                <host>zookeeper2</host>
                <port>2181</port>
            </node>
            <node index="3">
                <host>zookeeper3</host>
                <port>2181</port>
            </node>
        </zookeeper>
    
        <remote_servers>
            <clickhouse_cluster>
                <shard>
                    <replica>
                        <host>replica1</host>
                        <port>9000</port>
                    </replica>
                    <replica>
                        <host>replica2</host>
                        <port>9000</port>
                    </replica>
                </shard>
            </clickhouse_cluster>
        </remote_servers>
    </yandex>
    EOF

     

     

    그리고 macro 설정도 함께 추가합니다.

     

    cat <<'EOF'> /tmp/macro1.xml
    <yandex>
      <macros>
        <shard>1</shard>
        <replica>1</replica>
      </macros>
    </yandex>
    EOF
    
    cat <<'EOF'> /tmp/macro2.xml
    <yandex>
      <macros>
        <shard>1</shard>
        <replica>2</replica>
      </macros>
    </yandex>
    EOF

     

    아래의 docker-compose.yaml 파일은 3개의 Zookeeper 와 2개의 ClickHouse Replica 를 생성합니다.

     

    cat <<'EOF'> /tmp/ch.yaml
    version: '3.9'
    
    services:
      replica1:
        image: altinity/clickhouse-server:22.8.15.25.altinitystable
        container_name: replica1
        hostname: replica1
        platform: linux/amd64
        networks:
          - clickhouse
        volumes:
          - replica1:/var/lib/clickhouse
          - /tmp/config.xml:/etc/clickhouse-server/config.d/config.xml
          - /tmp/macro1.xml:/etc/clickhouse-server/config.d/macro.xml
    
      replica2:
        image: altinity/clickhouse-server:22.8.15.25.altinitystable
        container_name: replica2
        hostname: replica2
        platform: linux/amd64
        networks:
          - clickhouse
        volumes:
          - replica2:/var/lib/clickhouse
          - /tmp/config.xml:/etc/clickhouse-server/config.d/config.xml
          - /tmp/macro2.xml:/etc/clickhouse-server/config.d/macro.xml
    
      zookeeper1:
        image: zookeeper:3.6.1
        container_name: zookeeper1
        hostname: zookeeper1
        platform: linux/amd64
        volumes:
          - zookeeper1:/data
        networks:
          - clickhouse
        environment:
          ZOO_MY_ID: 1
          ZOO_SERVERS: "server.1=zookeeper1:2888:3888;2181 server.2=zookeeper2:2888:3888;2181 server.3=zookeeper3:2888:3888;2181"
    
      zookeeper2:
        image: zookeeper:3.6.1
        container_name: zookeeper2
        hostname: zookeeper2
        platform: linux/amd64
        volumes:
          - zookeeper2:/data
        networks:
          - clickhouse
        environment:
          ZOO_MY_ID: 2
          ZOO_SERVERS: "server.1=zookeeper1:2888:3888;2181 server.2=zookeeper2:2888:3888;2181 server.3=zookeeper3:2888:3888;2181"
    
      zookeeper3:
        image: zookeeper:3.6.1
        container_name: zookeeper3
        hostname: zookeeper3
        platform: linux/amd64
        volumes:
          - zookeeper3:/data
        networks:
          - clickhouse
        environment:
          ZOO_MY_ID: 3
          ZOO_SERVERS: "server.1=zookeeper1:2888:3888;2181 server.2=zookeeper2:2888:3888;2181 server.3=zookeeper3:2888:3888;2181"
    
    networks:
      clickhouse:
        driver: bridge
        external: true
    
    volumes:
      replica1:
      replica2:
      zookeeper1:
      zookeeper2:
      zookeeper3:
    
    EOF
    docker-compose -f /tmp/ch.yaml -p clickhouse up -d

     

     

    위 명령어의 실행 후, 생성되는 Docker Container 목록은 아래와 같습니다.

     

     

    생성된 Cluster 의 구성요소는 system.clusters 테이블을 통해서 확인할 수 있습니다.

     

    select cluster, shard_num, replica_num, host_name 
    from system.clusters where cluster = 'clickhouse_cluster' 
    format Vertical;
    Row 1:
    ──────
    cluster:     clickhouse_cluster
    shard_num:   1
    replica_num: 1
    host_name:   replica1
    
    Row 2:
    ──────
    cluster:     clickhouse_cluster
    shard_num:   1
    replica_num: 2
    host_name:   replica2

     

     

    ReplicatedMergeTree 테이블 생성.

    ReplicatedMergeTree Table 의 DDL Query 는 아래와 같습니다.

    각 Replica 에 macro 를 등록해두었기에 아래와 같은 {shard} 와 {replica} 치환변수를 사용할 수 있습니다.

     

    docker exec -it replica1 clickhouse-client
    CREATE TABLE default.products_local  ON CLUSTER 'clickhouse_cluster' (
        id UInt64,
        name String,
        price Float64,
        created_at DateTime
    ) ENGINE = ReplicatedMergeTree(
        '/clickhouse/tables/{shard}/products_local',
        '{replica}'
    )
    ORDER BY id
    PARTITION BY toYYYYMM(created_at);

     

    그리고 아래의 Insert Query 를 통해서 10만개의 데이터를 생성합니다.

     

    INSERT INTO default.products_local (id, name, price, created_at)
    SELECT
        number + 1 AS id,
        concat('Product_', toString(number + 1)) AS name,
        round(rand() % 10000 / 100.0, 2) AS price,
        toDateTime('2023-01-01 00:00:00') + intDiv(number, 100) AS created_at
    FROM numbers(100000);
    SELECT count(*)
    FROM default.products_local
    
    Query id: 64a41d69-f8a2-402d-ac9c-19b92bd4f0d8
    
    ┌─count()─┐
    │  100000 │
    └─────────┘
    
    1 row in set. Elapsed: 0.034 sec.

     

     

    아래의 Docker 명령어를 통해서 2개의 Replica 가 서로의 데이터를 복제

    docker exec replica1 clickhouse-client --query="select count(*) from default.products_local;"
    docker exec replica2 clickhouse-client --query="select count(*) from default.products_local;"

     

     

    ReplicatedMergeTree 테이블의 Backup & Restore.

    이제 생성된 ReplicatedMergeTree 테이블에 Backup 과 Restore 를 수행합니다.

     

    먼저 Backup 스냅샷을 저장할 원격 저장소를 실행합니다.

    docker run --name minio -d \
    --network clickhouse \
    -e MINIO_ROOT_USER=ROOTUSER -e MINIO_ROOT_PASSWORD=123456789 \
    -p 9000:9000 -p 9001:9001 \
    bitnami/minio
    docker exec minio \
    	bash -c '
        	mc alias set ch-backup http://localhost:9000 ROOTUSER 123456789 && \
            mc mb ch-backup/clickhouse
        '

     

     

    그리고 Backup 을 위한 설정 파일과 Backup 을 실행할 도커 컨테이너를 실행합니다.

     

    cat <<'EOF'> /tmp/config1.yml
    general:
      remote_storage: s3
    
    clickhouse:
      host: replica1
      port: 9000
      username: ""
      password: ""
      database: "default"
      sync_replicated_tables: true
      log_sql_queries: false
      timeout: 5m
      data_path: '/var/lib/clickhouse'
    
    s3:
      access_key: "ROOTUSER"
      secret_key: "123456789"
      bucket: "clickhouse"
      endpoint: "http://minio:9000"
      path: replica1
      region: "us-east-1"
      force_path_style: true
    EOF
    
    cat <<'EOF'> /tmp/config2.yml
    general:
      remote_storage: s3
    
    clickhouse:
      host: replica2
      port: 9000
      username: ""
      password: ""
      database: "default"
      sync_replicated_tables: true
      log_sql_queries: false
      timeout: 5m
      data_path: '/var/lib/clickhouse'
    
    s3:
      access_key: "ROOTUSER"
      secret_key: "123456789"
      bucket: "clickhouse"
      endpoint: "http://minio:9000"
      path: replica2
      region: "us-east-1"
      force_path_style: true
    EOF

     

    그리고 아래와 같이 2개의 Docker Container 를 실행합니다.

    각각 replica1, replica2 를 백업하기 위한 컨테이너입니다.

    유념해야 할 점은 ClickHouse Server 를 실행하면서 사용한 Volume 을 함께 바인딩해주어야합니다.

    ClickHouse Server 의 실제 Part 파일에 접근할 수 있도록 파일시스템을 공유해야하기 때문입니다.

     

    docker run -it --rm -u clickhouse \
       --network clickhouse \
       --platform linux/amd64 \
       --mount type=bind,source=/tmp/config1.yml,target=/etc/clickhouse-backup/config.yml \
       -v "clickhouse_replica1:/var/lib/clickhouse" \
       altinity/clickhouse-backup:2.6.5 bash -c 'clickhouse-backup create backup && clickhouse-backup upload backup'
    docker run -it --rm -u clickhouse \
       --network clickhouse \
       --platform linux/amd64 \
       --mount type=bind,source=/tmp/config2.yml,target=/etc/clickhouse-backup/config.yml \
       -v "clickhouse_replica2:/var/lib/clickhouse" \
       altinity/clickhouse-backup:2.6.5 bash -c 'clickhouse-backup create backup && clickhouse-backup upload backup'

     

    위 명령어가 실행됨으로써 아래와 같이 MinIO 의 Bucket 내부에 백업 파일들이 생성됩니다.

     

    docker exec minio mc ls ch-backup -r /clickhouse
       591B STANDARD clickhouse/replica1/backup/metadata.json
       606B STANDARD clickhouse/replica1/backup/metadata/default/products_local.json
     1.2MiB STANDARD clickhouse/replica1/backup/shadow/default/products_local/default_202301_0_0_0.tar
       591B STANDARD clickhouse/replica2/backup/metadata.json
       606B STANDARD clickhouse/replica2/backup/metadata/default/products_local.json
     1.2MiB STANDARD clickhouse/replica2/backup/shadow/default/products_local/default_202301_0_0_0.tar

     

    새로운 ClickHouse Server 로 Restore 하기.

    이제 새로운 ClickHouse Cluster 를 실행하여 Backup 된 스냅샷을 Restore 합니다.

    기존의 실행 중인 docker-compose Project 를 삭제하고 새롭게 실행하셔도 무방합니다.

    저는 아래와 같은 명령어를 통해서 모든 Container 와 Volume 을 삭제한 후에 다시 Docker Compose 를 실행하였습니다.

     

    docker rm -f replica1
    docker rm -f replica2
    docker rm -f zookeeper1
    docker rm -f zookeeper2
    docker rm -f zookeeper3
    
    docker volume rm clickhouse_replica1
    docker volume rm clickhouse_replica2
    docker volume rm clickhouse_zookeeper1
    docker volume rm clickhouse_zookeeper2
    docker volume rm clickhouse_zookeeper3

     

    Container 와 Volume 삭제 후에 다시 docker-compose 를 실행합니다.

     

    docker-compose -f /tmp/ch.yaml -p clickhouse up -d

     

     

    그리고 아래의 clickhouse-backup 명령어를 통해서 새롭게 생성된 ClickHouse replica1 과 replica2 의 Restore 를 수행합니다.

     

    docker run -it --rm -u clickhouse \
       --network clickhouse \
       --platform linux/amd64 \
       --mount type=bind,source=/tmp/config1.yml,target=/etc/clickhouse-backup/config.yml \
       -v "clickhouse_replica1:/var/lib/clickhouse" \
       altinity/clickhouse-backup:2.6.5 bash -c 'clickhouse-backup download backup && clickhouse-backup restore backup'
    docker run -it --rm -u clickhouse \
       --network clickhouse \
       --platform linux/amd64 \
       --mount type=bind,source=/tmp/config2.yml,target=/etc/clickhouse-backup/config.yml \
       -v "clickhouse_replica2:/var/lib/clickhouse" \
       altinity/clickhouse-backup:2.6.5 bash -c 'clickhouse-backup download backup && clickhouse-backup restore backup'

     

    그 후 각 Replica 의 상태를 확인하게 되면 백업의 컨텐츠가 반영됨을 확인할 수 있습니다.

    docker exec replica1 clickhouse-client --query="select count(*) from default.products_local;"
    docker exec replica2 clickhouse-client --query="select count(*) from default.products_local;"

     

     

    반응형
Designed by Tistory.