본문으로 바로가기
본문으로 바로가기

데이터 복제

이 예제에서는 데이터를 복제하는 간단한 ClickHouse 클러스터를 설정하는 방법을 살펴봅니다. 서버는 총 5대로 구성됩니다. 이 중 2대는 데이터 사본을 저장하는 데 사용됩니다. 나머지 3대의 서버는 데이터 복제를 조정하는 데 사용됩니다.

구성할 클러스터의 아키텍처는 아래와 같습니다.

ReplicatedMergeTree를 사용한 1개 세그먼트와 2개 레플리카의 아키텍처 다이어그램
참고

ClickHouse Server와 ClickHouse Keeper를 동일한 서버에서 함께 실행하는 것도 가능하지만, 프로덕션 환경에서는 ClickHouse Keeper에 전용 호스트를 사용하는 것을 강력히 권장하며, 이 예제에서는 이러한 방식을 보여 줍니다.

Keeper 서버는 더 작게 구성해도 되며, 각 Keeper 서버에는 일반적으로 4GB RAM이면 충분합니다. 이는 ClickHouse Server 규모가 상당히 커지기 전까지 유효합니다.

선행 조건

  • 이전에 로컬 ClickHouse 서버를 한 번 이상 설정해 본 적이 있습니다
  • ClickHouse의 설정 파일 등 기본 구성 개념에 익숙합니다
  • 사용 중인 머신에 Docker가 설치되어 있습니다

디렉터리 구조 및 테스트 환경 설정하기

예제 파일

다음 단계에서는 클러스터를 처음부터 설정하는 방법을 단계별로 안내합니다.
이 단계를 건너뛰고 바로 클러스터를 실행하려면, examples 리포지토리의 'docker-compose-recipes' 디렉터리에서 예제 파일을 다운로드할 수 있습니다.

이 튜토리얼에서는 Docker compose를 사용하여 ClickHouse 클러스터를 설정합니다. 이 설정은 별도의 로컬 머신, 가상 머신 또는 Cloud 인스턴스에서도 작동하도록 수정할 수 있습니다.

다음 명령을 실행하여 이 예제의 디렉터리 구조를 설정하세요:

mkdir cluster_1S_2R
cd cluster_1S_2R

# Create clickhouse-keeper directories
for i in {01..03}; do
  mkdir -p fs/volumes/clickhouse-keeper-${i}/etc/clickhouse-keeper
done

# Create clickhouse-server directories
for i in {01..02}; do
  mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server
done

다음 docker-compose.yml 파일을 cluster_1S_2R 디렉터리에 추가하세요:

version: '3.8'
services:
  clickhouse-01:
    image: "clickhouse/clickhouse-server:latest"
    user: "101:101"
    container_name: clickhouse-01
    hostname: clickhouse-01
    volumes:
      - ${PWD}/fs/volumes/clickhouse-01/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
      - ${PWD}/fs/volumes/clickhouse-01/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
    ports:
      - "127.0.0.1:8123:8123"
      - "127.0.0.1:9000:9000"
    depends_on:
      - clickhouse-keeper-01
      - clickhouse-keeper-02
      - clickhouse-keeper-03
  clickhouse-02:
    image: "clickhouse/clickhouse-server:latest"
    user: "101:101"
    container_name: clickhouse-02
    hostname: clickhouse-02
    volumes:
      - ${PWD}/fs/volumes/clickhouse-02/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
      - ${PWD}/fs/volumes/clickhouse-02/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
    ports:
      - "127.0.0.1:8124:8123"
      - "127.0.0.1:9001:9000"
    depends_on:
      - clickhouse-keeper-01
      - clickhouse-keeper-02
      - clickhouse-keeper-03
  clickhouse-keeper-01:
    image: "clickhouse/clickhouse-keeper:latest-alpine"
    user: "101:101"
    container_name: clickhouse-keeper-01
    hostname: clickhouse-keeper-01
    volumes:
     - ${PWD}/fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
    ports:
        - "127.0.0.1:9181:9181"
  clickhouse-keeper-02:
    image: "clickhouse/clickhouse-keeper:latest-alpine"
    user: "101:101"
    container_name: clickhouse-keeper-02
    hostname: clickhouse-keeper-02
    volumes:
     - ${PWD}/fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
    ports:
        - "127.0.0.1:9182:9181"
  clickhouse-keeper-03:
    image: "clickhouse/clickhouse-keeper:latest-alpine"
    user: "101:101"
    container_name: clickhouse-keeper-03
    hostname: clickhouse-keeper-03
    volumes:
     - ${PWD}/fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
    ports:
        - "127.0.0.1:9183:9181"

다음 하위 디렉터리와 파일을 생성하세요:

for i in {01..02}; do
  mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server/config.d
  mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server/users.d
  touch fs/volumes/clickhouse-${i}/etc/clickhouse-server/config.d/config.xml
  touch fs/volumes/clickhouse-${i}/etc/clickhouse-server/users.d/users.xml
done
  • config.d 디렉터리에는 ClickHouse 서버 구성 파일 config.xml이 포함됩니다. 이 파일에는 각 ClickHouse 노드에 대한 사용자 지정 구성이 정의되어 있으며, 모든 ClickHouse 설치에 포함되는 기본 ClickHouse 구성 파일 config.xml과 함께 적용됩니다.
  • users.d 디렉터리에는 사용자 구성 파일 users.xml이 포함됩니다. 이 파일에는 사용자에 대한 사용자 지정 구성이 정의되어 있으며, 모든 ClickHouse 설치에 포함되는 기본 ClickHouse users.xml 구성 파일과 함께 적용됩니다.
사용자 지정 구성 디렉터리

자체 구성을 작성할 때는 /etc/clickhouse-server/config.xmletc/clickhouse-server/users.xml의 기본 구성을 직접 수정하는 대신, config.dusers.d 디렉터리를 활용하는 것이 모범 사례입니다.

다음 행은

<clickhouse replace="true">

config.dusers.d 디렉터리에 정의된 설정 섹션이 기본 config.xmlusers.xml 파일에 정의된 기본 설정 섹션보다 우선하도록 합니다.

ClickHouse 노드 구성하기

서버 설정

이제 fs/volumes/clickhouse-{}/etc/clickhouse-server/config.d에 위치한 각 빈 설정 파일 config.xml을 수정하세요. 아래에서 강조 표시된 줄은 각 노드별로 변경해야 합니다:

<clickhouse replace="true">
    <logger>
        <level>debug</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <!--highlight-next-line-->
    <display_name>cluster_1S_2R node 1</display_name>
    <listen_host>0.0.0.0</listen_host>
    <http_port>8123</http_port>
    <tcp_port>9000</tcp_port>
    <user_directories>
        <users_xml>
            <path>users.xml</path>
        </users_xml>
        <local_directory>
            <path>/var/lib/clickhouse/access/</path>
        </local_directory>
    </user_directories>
    <distributed_ddl>
        <path>/clickhouse/task_queue/ddl</path>
    </distributed_ddl>
    <remote_servers>
        <cluster_1S_2R>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>clickhouse-01</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>clickhouse-02</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_1S_2R>
    </remote_servers>
    <zookeeper>
        <node>
            <host>clickhouse-keeper-01</host>
            <port>9181</port>
        </node>
        <node>
            <host>clickhouse-keeper-02</host>
            <port>9181</port>
        </node>
        <node>
            <host>clickhouse-keeper-03</host>
            <port>9181</port>
        </node>
    </zookeeper>
    <!--highlight-start-->
    <macros>
        <shard>01</shard>
        <replica>01</replica>
        <cluster>cluster_1S_2R</cluster>
    </macros>
    <!--highlight-end-->
</clickhouse>
디렉터리파일
fs/volumes/clickhouse-01/etc/clickhouse-server/config.dconfig.xml
fs/volumes/clickhouse-02/etc/clickhouse-server/config.dconfig.xml

위 구성 파일의 각 섹션에 대한 자세한 설명은 다음과 같습니다.

네트워킹 및 로깅

네트워크 인터페이스로의 외부 통신은 listen host 설정을 활성화하면 사용할 수 있습니다. 이렇게 하면 다른 호스트에서 ClickHouse 서버 호스트에 접속할 수 있습니다:

<listen_host>0.0.0.0</listen_host>

HTTP API 포트는 8123으로 설정됩니다:

<http_port>8123</http_port>

ClickHouse 기본 프로토콜을 사용하여 clickhouse-client 및 기타 기본 ClickHouse 도구가 clickhouse-server 및 다른 clickhouse-server와 상호 작용할 때 사용하는 TCP 포트는 9000입니다:

<tcp_port>9000</tcp_port>

로깅은 <logger> 블록에서 정의됩니다. 이 예제 구성은 1000M 크기에 도달할 때마다 롤오버되는 디버그 로그를 제공하며, 총 3회 롤오버됩니다:

<logger>
    <level>debug</level>
    <log>/var/log/clickhouse-server/clickhouse-server.log</log>
    <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
    <size>1000M</size>
    <count>3</count>
</logger>

로깅 구성에 대한 자세한 내용은 기본 ClickHouse 구성 파일에 포함된 주석을 참조하세요.

클러스터 구성

클러스터 구성은 <remote_servers> 블록에서 설정합니다. 여기에서 클러스터 이름 cluster_1S_2R을 정의합니다.

<cluster_1S_2R></cluster_1S_2R> 블록은 <shard></shard><replica></replica> 설정을 사용하여 클러스터의 레이아웃을 정의하며, ON CLUSTER 절을 사용하여 클러스터 전체에서 실행되는 쿼리인 분산 DDL 쿼리의 템플릿 역할을 합니다. 기본적으로 분산 DDL 쿼리가 허용되지만, allow_distributed_ddl_queries 설정으로 비활성화할 수도 있습니다.

internal_replication을 true로 설정하면 데이터가 레플리카 중 하나에만 기록됩니다.

<remote_servers>
    <!-- cluster name (should not contain dots) -->
    <cluster_1S_2R>
        <!-- <allow_distributed_ddl_queries>false</allow_distributed_ddl_queries> -->
        <shard>
            <!-- Optional. Whether to write data to just one of the replicas. Default: false (write data to all replicas). -->
            <internal_replication>true</internal_replication>
            <replica>
                <host>clickhouse-01</host>
                <port>9000</port>
            </replica>
            <replica>
                <host>clickhouse-02</host>
                <port>9000</port>
            </replica>
        </shard>
    </cluster_1S_2R>
</remote_servers>

각 서버에 대해 다음 매개변수를 지정합니다:

ParameterDescriptionDefault Value
host원격 서버의 주소입니다. 도메인 또는 IPv4, IPv6 주소를 사용할 수 있습니다. 도메인을 지정하면 서버가 시작될 때 DNS 조회를 수행하며, 그 결과는 서버가 실행되는 동안 유지됩니다. DNS 조회가 실패하면 서버가 시작되지 않습니다. DNS 레코드를 변경한 경우 서버를 다시 시작해야 합니다.-
port메신저 통신에 사용하는 TCP 포트입니다(configtcp_port, 일반적으로 9000으로 설정). http_port와 혼동하지 마십시오.-

Keeper 구성

<ZooKeeper> 섹션은 ClickHouse Keeper(또는 ZooKeeper)가 실행 중인 위치를 ClickHouse에 알려줍니다. ClickHouse Keeper 클러스터를 사용하는 경우, 클러스터의 각 <node>를 지정해야 하며, <host><port> 태그를 사용하여 각각의 호스트명과 포트 번호를 지정하십시오.

ClickHouse Keeper 설정은 튜토리얼의 다음 단계에서 설명합니다.

<zookeeper>
    <node>
        <host>clickhouse-keeper-01</host>
        <port>9181</port>
    </node>
    <node>
        <host>clickhouse-keeper-02</host>
        <port>9181</port>
    </node>
    <node>
        <host>clickhouse-keeper-03</host>
        <port>9181</port>
    </node>
</zookeeper>
참고

ClickHouse Keeper를 ClickHouse Server와 동일한 서버에서 실행할 수 있지만, 프로덕션 환경에서는 ClickHouse Keeper를 전용 호스트에서 실행하실 것을 강력히 권장합니다.

매크로 설정

또한 <macros> 섹션은 복제된 테이블(Replicated Table)에 대한 매개변수 치환을 정의하는 데 사용됩니다. 이러한 매개변수는 system.macros에 나열되며, 쿼리에서 {shard}(세그먼트)와 {replica}(레플리카) 같은 치환을 사용할 수 있습니다.

<macros>
    <shard>01</shard>
    <replica>01</replica>
    <cluster>cluster_1S_2R</cluster>
</macros>
참고

이러한 값들은 클러스터의 레이아웃에 따라 고유하게 정의됩니다.

사용자 구성

이제 fs/volumes/clickhouse-{}/etc/clickhouse-server/users.d에 위치한 각 빈 설정 파일 users.xml을 다음과 같이 수정하세요:

<?xml version="1.0"?>
<clickhouse replace="true">
    <profiles>
        <default>
            <max_memory_usage>10000000000</max_memory_usage>
            <use_uncompressed_cache>0</use_uncompressed_cache>
            <load_balancing>in_order</load_balancing>
            <log_queries>1</log_queries>
        </default>
    </profiles>
    <users>
        <default>
            <access_management>1</access_management>
            <profile>default</profile>
            <networks>
                <ip>::/0</ip>
            </networks>
            <quota>default</quota>
            <access_management>1</access_management>
            <named_collection_control>1</named_collection_control>
            <show_named_collections>1</show_named_collections>
            <show_named_collections_secrets>1</show_named_collections_secrets>
        </default>
    </users>
    <quotas>
        <default>
            <interval>
                <duration>3600</duration>
                <queries>0</queries>
                <errors>0</errors>
                <result_rows>0</result_rows>
                <read_rows>0</read_rows>
                <execution_time>0</execution_time>
            </interval>
        </default>
    </quotas>
</clickhouse>
디렉터리파일
fs/volumes/clickhouse-01/etc/clickhouse-server/users.dusers.xml
fs/volumes/clickhouse-02/etc/clickhouse-server/users.dusers.xml

이 예제에서는 편의상 기본 사용자를 비밀번호 없이 구성합니다. 실제 환경에서는 이 방식을 권장하지 않습니다.

참고

이 예제에서는 클러스터의 모든 노드에서 각 users.xml 파일이 동일합니다.

ClickHouse Keeper 구성하기

Keeper 설정

복제가 동작하려면 ClickHouse Keeper 클러스터를 설정하고 구성해야 합니다. ClickHouse Keeper는 데이터 복제를 위한 조정 시스템을 제공하며, 대체로 사용할 수 있는 ZooKeeper를 대체하는 역할을 합니다. 하지만 ClickHouse Keeper는 ZooKeeper보다 더 나은 보증과 신뢰성을 제공하고 리소스를 더 적게 사용하므로 권장됩니다. 고가용성과 정족수(quorum)를 유지하기 위해 최소 3개의 ClickHouse Keeper 노드를 실행하는 것이 좋습니다.

참고

ClickHouse Keeper는 클러스터의 어느 노드에서든 ClickHouse와 함께 실행될 수 있지만, 확장 및 ClickHouse Keeper 클러스터를 데이터베이스 클러스터와 독립적으로 관리할 수 있도록 전용 노드에서 실행하는 것이 권장됩니다.

다음 명령을 예제 폴더의 루트에서 실행하여 각 ClickHouse Keeper 노드에 대한 keeper_config.xml 파일을 생성하십시오:

for i in {01..03}; do
  touch fs/volumes/clickhouse-keeper-${i}/etc/clickhouse-keeper/keeper_config.xml
done

각 노드 디렉터리 fs/volumes/clickhouse-keeper-{}/etc/clickhouse-keeper에 생성된 비어 있는 설정 파일을 수정하십시오. 아래에서 강조 표시된 줄을 각 노드에 맞게 변경해야 합니다.

<clickhouse replace="true">
    <logger>
        <level>information</level>
        <log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
        <errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <listen_host>0.0.0.0</listen_host>
    <keeper_server>
        <tcp_port>9181</tcp_port>
        <!--highlight-next-line-->
        <server_id>1</server_id>
        <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
        <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
        <coordination_settings>
            <operation_timeout_ms>10000</operation_timeout_ms>
            <session_timeout_ms>30000</session_timeout_ms>
            <raft_logs_level>information</raft_logs_level>
        </coordination_settings>
        <raft_configuration>
            <server>
                <id>1</id>
                <hostname>clickhouse-keeper-01</hostname>
                <port>9234</port>
            </server>
            <server>
                <id>2</id>
                <hostname>clickhouse-keeper-02</hostname>
                <port>9234</port>
            </server>
            <server>
                <id>3</id>
                <hostname>clickhouse-keeper-03</hostname>
                <port>9234</port>
            </server>
        </raft_configuration>
    </keeper_server>
</clickhouse>
디렉터리파일
fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeperkeeper_config.xml
fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeperkeeper_config.xml
fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeperkeeper_config.xml

각 구성 파일에는 아래에 나오는 고유한 구성이 포함됩니다. server_id 값은 해당 ClickHouse Keeper 노드에 대해 클러스터 내에서 고유해야 하며, &lt;raft_configuration&gt; 섹션에 정의된 서버 &lt;id&gt;와 일치해야 합니다. tcp_port는 ClickHouse Keeper의 클라이언트가 사용하는 포트입니다.

<tcp_port>9181</tcp_port>
<server_id>{id}</server_id>

다음 섹션에서는 Raft 합의 알고리즘의 정족수(quorum)에 참여하는 서버를 구성합니다.

<raft_configuration>
    <server>
        <id>1</id>
        <hostname>clickhouse-keeper-01</hostname>
        <!-- TCP port used for communication between ClickHouse Keeper nodes -->
        <!--highlight-next-line-->
        <port>9234</port>
    </server>
    <server>
        <id>2</id>
        <hostname>clickhouse-keeper-02</hostname>
        <port>9234</port>
    </server>
    <server>
        <id>3</id>
        <hostname>clickhouse-keeper-03</hostname>
        <port>9234</port>
    </server>
</raft_configuration>
ClickHouse Cloud는 관리를 단순화합니다

ClickHouse Cloud는 세그먼트와 레플리카 관리를 수반하는 운영 부담을 제거합니다. 이 플랫폼은 고가용성, 복제, 확장에 대한 결정을 자동으로 처리합니다. 컴퓨팅 리소스와 스토리지는 분리되어 있으며, 수요에 따라 수동 구성이나 지속적인 유지 보수 없이 확장됩니다.

자세히 알아보기

설정 테스트하기

Docker가 머신에서 실행 중인지 확인하세요. cluster_1S_2R 디렉터리의 루트에서 docker-compose up 명령을 사용하여 클러스터를 시작하세요:

docker-compose up -d

docker가 ClickHouse 및 Keeper 이미지를 가져온 후 컨테이너를 시작하는 것을 확인할 수 있습니다:

[+] Running 6/6
 ✔ Network cluster_1s_2r_default   Created
 ✔ Container clickhouse-keeper-03  Started
 ✔ Container clickhouse-keeper-02  Started
 ✔ Container clickhouse-keeper-01  Started
 ✔ Container clickhouse-01         Started
 ✔ Container clickhouse-02         Started

클러스터가 실행 중인지 확인하려면 clickhouse-01 또는 clickhouse-02에 연결한 후 다음 쿼리를 실행하세요. 첫 번째 노드에 연결하는 명령은 다음과 같습니다:

# Connect to any node
docker exec -it clickhouse-01 clickhouse-client

성공하면 ClickHouse 클라이언트 프롬프트가 표시됩니다:

cluster_1S_2R node 1 :)

다음 쿼리를 실행하여 각 호스트에 정의된 클러스터 토폴로지를 확인하세요:

SELECT 
    cluster,
    shard_num,
    replica_num,
    host_name,
    port
FROM system.clusters;
   ┌─cluster───────┬─shard_num─┬─replica_num─┬─host_name─────┬─port─┐
1. │ cluster_1S_2R │         1 │           1 │ clickhouse-01 │ 9000 │
2. │ cluster_1S_2R │         1 │           2 │ clickhouse-02 │ 9000 │
3. │ default       │         1 │           1 │ localhost     │ 9000 │
   └───────────────┴───────────┴─────────────┴───────────────┴──────┘

다음 쿼리를 실행하여 ClickHouse Keeper 클러스터의 상태를 확인하세요:

SELECT *
FROM system.zookeeper
WHERE path IN ('/', '/clickhouse')
   ┌─name───────┬─value─┬─path────────┐
1. │ sessions   │       │ /clickhouse │
2. │ task_queue │       │ /clickhouse │
3. │ keeper     │       │ /           │
4. │ clickhouse │       │ /           │
   └────────────┴───────┴─────────────┘

mntr 명령은 ClickHouse Keeper가 실행 중인지 확인하고, 세 개의 Keeper 노드 간 관계에 대한 상태 정보를 확인하는 데 일반적으로 사용됩니다. 이 예제에서 사용된 구성에는 함께 동작하는 세 개의 노드가 있습니다. 노드들은 리더를 선출하고, 나머지 노드들은 팔로워가 됩니다.

mntr 명령은 성능 관련 정보와 특정 노드가 팔로워인지 리더인지에 대한 정보를 제공합니다.

Keeper에 mntr 명령을 보내기 위해 netcat을 설치해야 할 수도 있습니다. 다운로드 정보는 nmap.org 페이지를 참고하십시오.

각 Keeper 노드의 상태를 확인하기 위해 clickhouse-keeper-01, clickhouse-keeper-02, clickhouse-keeper-03의 셸에서 아래 명령을 실행합니다. clickhouse-keeper-01에 대한 명령은 아래와 같습니다.

docker exec -it clickhouse-keeper-01  /bin/sh -c 'echo mntr | nc 127.0.0.1 9181'

아래는 follower 노드에서 반환된 예시 응답입니다.

zk_version      v23.3.1.2823-testing-46e85357ce2da2a99f56ee83a079e892d7ec3726
zk_avg_latency  0
zk_max_latency  0
zk_min_latency  0
zk_packets_received     0
zk_packets_sent 0
zk_num_alive_connections        0
zk_outstanding_requests 0
# highlight-next-line
zk_server_state follower
zk_znode_count  6
zk_watch_count  0
zk_ephemerals_count     0
zk_approximate_data_size        1271
zk_key_arena_size       4096
zk_latest_snapshot_size 0
zk_open_file_descriptor_count   46
zk_max_file_descriptor_count    18446744073709551615

아래는 리더 노드의 예시 응답입니다:

zk_version      v23.3.1.2823-testing-46e85357ce2da2a99f56ee83a079e892d7ec3726
zk_avg_latency  0
zk_max_latency  0
zk_min_latency  0
zk_packets_received     0
zk_packets_sent 0
zk_num_alive_connections        0
zk_outstanding_requests 0
# highlight-next-line
zk_server_state leader
zk_znode_count  6
zk_watch_count  0
zk_ephemerals_count     0
zk_approximate_data_size        1271
zk_key_arena_size       4096
zk_latest_snapshot_size 0
zk_open_file_descriptor_count   48
zk_max_file_descriptor_count    18446744073709551615
# highlight-start
zk_followers    2
zk_synced_followers     2
# highlight-end

이로써 단일 세그먼트와 두 개의 레플리카로 구성된 ClickHouse 클러스터 설정을 완료했습니다. 다음 단계에서는 클러스터에 테이블을 생성하세요.

데이터베이스 생성하기

클러스터가 올바르게 설정되어 실행 중임을 확인했으므로, UK property prices 예제 데이터셋 튜토리얼에서 사용된 것과 동일한 테이블을 재생성하게 됩니다. 이 데이터셋은 1995년 이후 영국 잉글랜드와 웨일스의 부동산 거래 가격에 대한 약 3천만 개의 행으로 구성되어 있습니다.

각 호스트의 클라이언트에 연결하려면 별도의 터미널 탭 또는 창에서 다음 명령을 각각 실행하세요:

docker exec -it clickhouse-01 clickhouse-client
docker exec -it clickhouse-02 clickhouse-client

각 호스트의 clickhouse-client에서 아래 쿼리를 실행하여 기본 데이터베이스를 제외하고 생성된 데이터베이스가 없음을 확인하십시오:

SHOW DATABASES;
   ┌─name───────────────┐
1. │ INFORMATION_SCHEMA │
2. │ default            │
3. │ information_schema │
4. │ system             │
   └────────────────────┘

clickhouse-01 클라이언트에서 ON CLUSTER 절을 사용하는 다음 분산 DDL 쿼리를 실행하여 uk라는 새 데이터베이스를 생성하십시오:

CREATE DATABASE IF NOT EXISTS uk 
-- highlight-next-line
ON CLUSTER cluster_1S_2R;

각 호스트의 클라이언트에서 이전과 동일한 쿼리를 다시 실행하여 clickhouse-01에서만 쿼리를 실행했음에도 불구하고 클러스터 전체에 데이터베이스가 생성되었는지 확인하십시오:

SHOW DATABASES;
   ┌─name───────────────┐
1. │ INFORMATION_SCHEMA │
2. │ default            │
3. │ information_schema │
4. │ system             │
#highlight-next-line
5. │ uk                 │
   └────────────────────┘

클러스터에 테이블 생성

데이터베이스가 생성되었으므로 클러스터에 테이블을 생성하세요. 호스트 클라이언트 중 하나에서 다음 쿼리를 실행하세요:

CREATE TABLE IF NOT EXISTS uk.uk_price_paid_local
--highlight-next-line
ON CLUSTER cluster_1S_2R
(
    price UInt32,
    date Date,
    postcode1 LowCardinality(String),
    postcode2 LowCardinality(String),
    type Enum8('terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4, 'other' = 0),
    is_new UInt8,
    duration Enum8('freehold' = 1, 'leasehold' = 2, 'unknown' = 0),
    addr1 String,
    addr2 String,
    street LowCardinality(String),
    locality LowCardinality(String),
    town LowCardinality(String),
    district LowCardinality(String),
    county LowCardinality(String)
)
--highlight-next-line
ENGINE = ReplicatedMergeTree
ORDER BY (postcode1, postcode2, addr1, addr2);

이는 UK property prices 예제 데이터셋 튜토리얼의 원본 CREATE 문에서 사용된 쿼리와 동일하며, ON CLUSTER 절과 ReplicatedMergeTree 엔진 사용만 다릅니다.

ON CLUSTER 절은 CREATE, DROP, ALTER, RENAME과 같은 DDL(Data Definition Language, 데이터 정의 언어) 쿼리를 분산 실행하기 위해 설계되었으며, 클러스터의 모든 노드에 스키마 변경 사항이 적용되도록 보장합니다.

ReplicatedMergeTree 엔진은 일반 MergeTree 테이블 엔진과 동일하게 작동하며, 추가로 데이터를 복제합니다.

clickhouse-01 또는 clickhouse-02 클라이언트에서 아래 쿼리를 실행하여 클러스터 전체에 테이블이 생성되었는지 확인하세요:

SHOW TABLES IN uk;
   ┌─name────────────────┐
1. │ uk_price_paid.      │
   └─────────────────────┘

데이터 삽입

데이터 세트가 크고 완전히 수집하는 데 몇 분이 소요되므로, 먼저 작은 하위 집합만 삽입합니다.

clickhouse-01에서 아래 쿼리를 사용하여 데이터의 더 작은 부분 집합을 삽입하세요:

INSERT INTO uk.uk_price_paid_local
SELECT
    toUInt32(price_string) AS price,
    parseDateTimeBestEffortUS(time) AS date,
    splitByChar(' ', postcode)[1] AS postcode1,
    splitByChar(' ', postcode)[2] AS postcode2,
    transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
    b = 'Y' AS is_new,
    transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
    addr1,
    addr2,
    street,
    locality,
    town,
    district,
    county
FROM url(
    'http://prod1.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv',
    'CSV',
    'uuid_string String,
    price_string String,
    time String,
    postcode String,
    a String,
    b String,
    c String,
    addr1 String,
    addr2 String,
    street String,
    locality String,
    town String,
    district String,
    county String,
    d String,
    e String'
) LIMIT 10000
SETTINGS max_http_get_redirects=10;

각 호스트에서 데이터가 완전히 복제되어 있음을 확인하세요:

-- clickhouse-01
SELECT count(*)
FROM uk.uk_price_paid_local

--   ┌─count()─┐
-- 1.│   10000 │
--   └─────────┘

-- clickhouse-02
SELECT count(*)
FROM uk.uk_price_paid_local

--   ┌─count()─┐
-- 1.│   10000 │
--   └─────────┘

호스트 중 하나에 장애가 발생했을 때 어떤 일이 일어나는지 확인하려면, 호스트 중 하나에서 간단한 테스트 데이터베이스와 테스트 테이블을 생성하세요:

CREATE DATABASE IF NOT EXISTS test ON CLUSTER cluster_1S_2R;
CREATE TABLE test.test_table ON CLUSTER cluster_1S_2R
(
    `id` UInt64,
    `name` String
)
ENGINE = ReplicatedMergeTree
ORDER BY id;

uk_price_paid 테이블과 마찬가지로, 두 호스트 중 어느 쪽에서든 데이터를 삽입할 수 있습니다:

INSERT INTO test.test_table (id, name) VALUES (1, 'Clicky McClickface');

호스트 중 하나가 다운되면 어떻게 될까요? 이를 시뮬레이션하려면 다음 명령을 실행하여 clickhouse-01을 중지하세요:

docker stop clickhouse-01

다음 명령을 실행하여 호스트가 다운되었는지 확인하세요:

docker-compose ps
NAME                   IMAGE                                        COMMAND            SERVICE                CREATED          STATUS          PORTS
clickhouse-02          clickhouse/clickhouse-server:latest          "/entrypoint.sh"   clickhouse-02          X minutes ago    Up X minutes    127.0.0.1:8124->8123/tcp, 127.0.0.1:9001->9000/tcp
clickhouse-keeper-01   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-01   X minutes ago    Up X minutes    127.0.0.1:9181->9181/tcp
clickhouse-keeper-02   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-02   X minutes ago    Up X minutes    127.0.0.1:9182->9181/tcp
clickhouse-keeper-03   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-03   X minutes ago    Up X minutes    127.0.0.1:9183->9181/tcp

clickhouse-01이 중단된 상태에서 테스트 테이블에 다른 행의 데이터를 삽입하고 테이블을 쿼리하세요:

INSERT INTO test.test_table (id, name) VALUES (2, 'Alexey Milovidov');
SELECT * FROM test.test_table;
   ┌─id─┬─name───────────────┐
1. │  1 │ Clicky McClickface │
2. │  2 │ Alexey Milovidov   │
   └────┴────────────────────┘

이제 다음 명령어로 clickhouse-01을 재시작하세요 (확인을 위해 docker-compose ps를 다시 실행할 수 있습니다):

docker start clickhouse-01

docker exec -it clickhouse-01 clickhouse-client를 실행한 후 clickhouse-01에서 테스트 테이블을 다시 쿼리합니다:

SELECT * FROM test.test_table
   ┌─id─┬─name───────────────┐
1. │  1 │ Clicky McClickface │
2. │  2 │ Alexey Milovidov   │
   └────┴────────────────────┘

이 단계에서 전체 UK 부동산 가격 데이터셋을 수집하여 실습해 보고 싶으시다면, 다음 쿼리를 실행하세요:

TRUNCATE TABLE uk.uk_price_paid_local ON CLUSTER cluster_1S_2R;
INSERT INTO uk.uk_price_paid_local
SELECT
    toUInt32(price_string) AS price,
    parseDateTimeBestEffortUS(time) AS date,
    splitByChar(' ', postcode)[1] AS postcode1,
    splitByChar(' ', postcode)[2] AS postcode2,
    transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
    b = 'Y' AS is_new,
    transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
    addr1,
    addr2,
    street,
    locality,
    town,
    district,
    county
FROM url(
    'http://prod1.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv',
    'CSV',
    'uuid_string String,
    price_string String,
    time String,
    postcode String,
    a String,
    b String,
    c String,
    addr1 String,
    addr2 String,
    street String,
    locality String,
    town String,
    district String,
    county String,
    d String,
    e String'
    ) SETTINGS max_http_get_redirects=10;

clickhouse-02 또는 clickhouse-01에서 테이블을 쿼리하세요:

SELECT count(*) FROM uk.uk_price_paid_local;
   ┌──count()─┐
1. │ 30212555 │ -- 30.21 million
   └──────────┘

결론

이 클러스터 토폴로지의 장점은 두 개의 레플리카가 있을 때 데이터가 서로 다른 두 호스트에 저장된다는 점입니다. 한 호스트에 장애가 발생해도 다른 레플리카가 데이터 손실 없이 계속해서 데이터를 제공합니다. 이를 통해 스토리지 수준에서의 단일 장애 지점을 제거할 수 있습니다.

하나의 호스트가 중지되더라도, 남아 있는 레플리카는 계속해서 다음 작업을 수행할 수 있습니다:

  • 중단 없이 읽기 쿼리 처리
  • 일관성 설정(consistency settings)에 따라 새로운 쓰기 요청 수락
  • 애플리케이션에 대한 서비스 가용성 유지

장애가 발생한 호스트가 다시 온라인 상태가 되면, 다음을 수행할 수 있습니다:

  • 정상 레플리카로부터 누락된 데이터 자동 동기화
  • 수동 개입 없이 정상적인 운영 재개
  • 전체 중복성(redundancy) 빠른 복원

다음 예제에서는 두 개의 세그먼트가 있지만 레플리카는 하나만 있는 클러스터를 설정하는 방법을 살펴봅니다.