복제 + 확장
복제 + 확장 (2 샤드 2 레플리카)
이 예제에서는 복제와 확장을 모두 하는 간단한 ClickHouse 클러스터를 설정하는 방법을 배워볼게요. 두 샤드와 두 레플리카로 구성되며, 조정을 관리하고 클러스터의 쿼럼을 유지하는 3-노드 ClickHouse Keeper 클러스터가 있어요.
출처: 문서
본문
설정할 클러스터의 아키텍처는 아래와 같아요.
ClickHouse Server와 ClickHouse Keeper를 같은 서버에서 함께 실행하는 것도 가능하지만, 프로덕션 환경에서는 ClickHouse Keeper에 전용 호스트를 사용할 것을 강력히 권장해요. 이는 이 예제에서 보여줄 방식이에요. Keeper 서버는 더 작을 수 있고, ClickHouse Server가 커질 때까지 각 Keeper 서버에는 일반적으로 4GB RAM이면 충분해요.
전제 조건 (Prerequisites)
- 이전에 로컬 ClickHouse 서버를 설정한 적이 있어야 해요
- 구성 파일 같은 ClickHouse의 기본 구성 개념에 익숙해야 해요
- 머신에 docker가 설치되어 있어야 해요
1. 디렉터리 구조와 테스트 환경 설정
예제 파일 다음 단계는 클러스터를 처음부터 설정하는 과정을 안내해요. 이 단계를 건너뛰고 바로 클러스터 실행으로 뛰어들고 싶다면 examples 저장소의 'docker-compose-recipes' 디렉터리에서 예제 파일을 얻을 수 있어요.
이 튜토리얼에서는 Docker compose를 사용해 ClickHouse 클러스터를 설정해요. 이 설정은 별도의 로컬 머신, 가상 머신 또는 클라우드 인스턴스에서도 동작하도록 수정할 수 있어요.
이 예제의 디렉터리 구조를 설정하려면 다음 명령을 실행해요:
mkdir cluster_2S_2R
cd cluster_2S_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..04}; do
mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server
done
clickhouse-cluster 디렉터리에 다음 docker-compose.yml 파일을 추가해요:
docker-compose.yml
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-03:
image: "clickhouse/clickhouse-server:latest"
user: "101:101"
container_name: clickhouse-03
hostname: clickhouse-03
volumes:
- ${PWD}/fs/volumes/clickhouse-03/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
- ${PWD}/fs/volumes/clickhouse-03/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
ports:
- "127.0.0.1:8125:8123"
- "127.0.0.1:9002:9000"
depends_on:
- clickhouse-keeper-01
- clickhouse-keeper-02
- clickhouse-keeper-03
clickhouse-04:
image: "clickhouse/clickhouse-server:latest"
user: "101:101"
container_name: clickhouse-04
hostname: clickhouse-04
volumes:
- ${PWD}/fs/volumes/clickhouse-04/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
- ${PWD}/fs/volumes/clickhouse-04/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
ports:
- "127.0.0.1:8126:8123"
- "127.0.0.1:9003: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..04}; 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 설치에 포함된 기본config.xmlClickHouse 구성 파일과 결합돼요.users.d디렉터리는 사용자 구성 파일users.xml을 포함하며, 여기서 사용자에 대한 사용자 지정 구성을 정의해요. 이 구성은 모든 ClickHouse 설치에 포함된 기본 ClickHouseusers.xml구성 파일과 결합돼요.
사용자 지정 구성 디렉터리 자신의 구성을 작성할 때는
/etc/clickhouse-server/config.xml과etc/clickhouse-server/users.xml의 기본 구성을 직접 수정하기보다config.d와users.d디렉터리를 활용하는 것이 모범 사례예요.
<clickhouse replace="true">
이 줄은 config.d와 users.d 디렉터리에 정의된 구성 섹션이 기본 config.xml과 users.xml 파일에 정의된 기본 구성 섹션을 덮어쓰도록 보장해요.
2. ClickHouse 노드 구성
서버 설정 (Server setup)
이제 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>
<display_name>cluster_2S_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_2S_2R>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>clickhouse-01</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse-03</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>clickhouse-02</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse-04</host>
<port>9000</port>
</replica>
</shard>
</cluster_2S_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>
<macros>
<shard>01</shard>
<replica>01</replica>
</macros>
</clickhouse>
| 디렉터리 | 파일 |
|---|---|
fs/volumes/clickhouse-01/etc/clickhouse-server/config.d |
config.xml |
fs/volumes/clickhouse-02/etc/clickhouse-server/config.d |
config.xml |
fs/volumes/clickhouse-03/etc/clickhouse-server/config.d |
config.xml |
fs/volumes/clickhouse-04/etc/clickhouse-server/config.d |
config.xml |
위 구성 파일의 각 섹션은 아래에서 자세히 설명돼요.
네트워킹과 로깅
listen host 설정을 활성화해 네트워크 인터페이스에 대한 외부 통신을 켜요. 이는 ClickHouse 서버 호스트가 다른 호스트에서 도달 가능하도록 보장해요:
<listen_host>0.0.0.0</listen_host>
HTTP API 포트는 8123으로 설정돼요:
<http_port>8123</http_port>
clickhouse-client와 다른 네이티브 ClickHouse 도구 사이, 그리고 clickhouse-server와 다른 clickhouse-server 사이에서 ClickHouse의 네이티브 프로토콜로 상호작용하는 TCP 포트는 9000으로 설정돼요:
<tcp_port>9000</tcp_port>
로깅 구성은 <logger> 블록에서 정의돼요. 이 예제 구성은 1000M에서 세 번 롤오버되는 디버그 로그를 제공해요:
<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_2S_2R이 정의돼요. <cluster_2S_2R></cluster_2S_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_2S_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-03</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>clickhouse-02</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse-04</host>
<port>9000</port>
</replica>
</shard>
</cluster_2S_2R>
</remote_servers>
<cluster_2S_2R></cluster_2S_2R> 섹션은 클러스터의 레이아웃을 정의하고, ON CLUSTER 절을 사용해 클러스터 전역에서 실행되는 분산 DDL 쿼리의 템플릿 역할을 해요.
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 구성
추가로 <macros> 섹션은 복제 테이블의 매개변수 대체를 정의하는 데 사용돼요. 이들은 system.macros에 나열되며 쿼리에서 {shard}와 {replica} 같은 대체를 사용할 수 있게 해줘요.
<macros>
<shard>01</shard>
<replica>01</replica>
</macros>
사용자 구성 (User configuration)
이제 fs/volumes/clickhouse-{}/etc/clickhouse-server/users.d에 있는 각 빈 구성 파일 users.xml을 다음 내용으로 수정해요:
/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>
<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_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>
이 예제에서는 단순함을 위해 default 사용자가 비밀번호 없이 구성돼요. 실제로는 권장되지 않아요.
이 예제에서 각 users.xml 파일은 클러스터의 모든 노드에서 동일해요.
3. ClickHouse Keeper 구성
다음으로 조정에 사용되는 ClickHouse Keeper를 구성할 거예요.
Keeper 설정 (Keeper setup)
복제가 동작하려면 ClickHouse Keeper 클러스터를 설정하고 구성해야 해요. ClickHouse Keeper는 데이터 복제를 위한 조정 시스템을 제공하며, 사용할 수도 있는 Zookeeper를 대체하는 역할을 해요. 하지만 ClickHouse Keeper는 ZooKeeper보다 더 나은 보장과 신뢰성을 제공하고 더 적은 리소스를 사용하므로 권장돼요. 고가용성과 쿼럼 유지를 위해 최소 세 개의 ClickHouse Keeper 노드를 실행할 것을 권장해요.
ClickHouse Keeper는 ClickHouse와 함께 클러스터의 어떤 노드에서도 실행할 수 있지만, 데이터베이스 클러스터와 독립적으로 ClickHouse Keeper 클러스터를 확장·관리할 수 있게 해주는 전용 노드에서 실행할 것을 권장해요.
example 폴더의 루트에서 다음 명령으로 각 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-keeper/keeper_config.xml
<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>
<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-keeper |
keeper_config.xml |
fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper |
keeper_config.xml |
fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper |
keeper_config.xml |
각 구성 파일에는 다음 고유 구성(아래 표시)이 포함돼요. 사용되는 server_id는 해당 ClickHouse Keeper 노드에 대해 클러스터에서 고유해야 하며 <raft_configuration> 섹션에 정의된 서버 <id>와 일치해야 해요. tcp_port는 ClickHouse Keeper의 클라이언트 가 사용하는 포트예요.
<tcp_port>9181</tcp_port>
<server_id>{id}</server_id>
다음 섹션은 raft 합의 알고리즘의 쿼럼에 참여하는 서버를 구성하는 데 사용돼요:
<raft_configuration>
<server>
<id>1</id>
<hostname>clickhouse-keeper-01</hostname>
<!-- TCP port used for communication between ClickHouse Keeper nodes -->
<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는 샤드와 레플리카 관리와 관련된 운영 부담을 제거해요. 플랫폼이 고가용성, 복제, 확장 결정을 자동으로 처리해요. 컴퓨팅과 저장은 분리되어 수동 구성이나 지속적 유지보수 없이 수요에 따라 확장돼요. 더 알아보기
4. 설정 테스트
머신에서 docker가 실행 중인지 확인해요. cluster_2S_2R 디렉터리의 루트에서 docker-compose up 명령으로 클러스터를 시작해요:
docker-compose up -d
docker가 ClickHouse와 Keeper 이미지를 가져오기 시작한 다음 컨테이너를 시작하는 것을 볼 수 있어요:
[+] Running 8/8
✔ Network cluster_2s_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
✔ Container clickhouse-04 Started
✔ Container clickhouse-03 Started
클러스터가 실행 중인지 확인하려면 노드 중 하나에 연결해 다음 쿼리를 실행해요. 첫 번째 노드에 연결하는 명령은 다음과 같아요:
# Connect to any node
docker exec -it clickhouse-01 clickhouse-client
성공하면 ClickHouse 클라이언트 프롬프트가 보여요:
cluster_2S_2R node 1 :)
어떤 호스트에 어떤 클러스터 토폴로지가 정의되어 있는지 확인하려면 다음 쿼리를 실행해요:
Query
SELECT
cluster,
shard_num,
replica_num,
host_name,
port
FROM system.clusters;
Response
┌─cluster───────┬─shard_num─┬─replica_num─┬─host_name─────┬─port─┐
1. │ cluster_2S_2R │ 1 │ 1 │ clickhouse-01 │ 9000 │
2. │ cluster_2S_2R │ 1 │ 2 │ clickhouse-03 │ 9000 │
3. │ cluster_2S_2R │ 2 │ 1 │ clickhouse-02 │ 9000 │
4. │ cluster_2S_2R │ 2 │ 2 │ clickhouse-04 │ 9000 │
5. │ default │ 1 │ 1 │ localhost │ 9000 │
└───────────────┴───────────┴─────────────┴───────────────┴──────┘
ClickHouse Keeper 클러스터의 상태를 확인하려면 다음 쿼리를 실행해요:
Query
SELECT *
FROM system.zookeeper
WHERE path IN ('/', '/clickhouse')
Response
┌─name───────┬─value─┬─path────────┐
1. │ task_queue │ │ /clickhouse │
2. │ sessions │ │ /clickhouse │
3. │ keeper │ │ / │
4. │ clickhouse │ │ / │
└────────────┴───────┴─────────────┘
mntr 명령도 ClickHouse Keeper가 실행 중인지 확인하고 세 Keeper 노드의 관계에 대한 상태 정보를 얻는 데 흔히 사용돼요. 이 예제에서 사용된 구성에는 함께 동작하는 세 개의 노드가 있어요. 노드들이 리더를 선출하고 나머지 노드들은 팔로워가 돼요. mntr 명령은 성능과 특정 노드가 팔로워인지 리더인지에 대한 정보를 줘요.
Keeper에 mntr 명령을 보내려면 netcat을 설치해야 할 수 있어요. 다운로드 정보는 nmap.org 페이지를 참고하세요.
clickhouse-keeper-01, clickhouse-keeper-02, clickhouse-keeper-03의 셸에서 아래 명령을 실행해 각 Keeper 노드의 상태를 확인해요. clickhouse-keeper-01의 명령은 아래와 같아요:
docker exec -it clickhouse-keeper-01 /bin/sh -c 'echo mntr | nc 127.0.0.1 9181'
아래 응답은 팔로워 노드의 예시 응답이에요:
Response
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
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
아래 응답은 리더 노드의 예시 응답이에요:
Response
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
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
zk_followers 2
zk_synced_followers 2
이것으로 두 샤드와 두 레플리카를 가진 ClickHouse 클러스터를 성공적으로 설정했어요. 다음 단계에서는 클러스터에 테이블을 만들 거예요.
5. 데이터베이스 만들기
클러스터가 올바르게 설정되고 실행 중임을 확인했으니, UK property prices 예제 데이터셋 튜토리얼에서 사용한 것과 같은 테이블을 다시 만들 거예요. 이는 1995년 이후 잉글랜드와 웨일스의 부동산에 지불된 가격 약 3000만 행으로 구성돼요.
각 호스트의 클라이언트에 별도의 터미널 탭 또는 창에서 각각 다음 명령을 실행해 연결해요:
docker exec -it clickhouse-01 clickhouse-client
docker exec -it clickhouse-02 clickhouse-client
docker exec -it clickhouse-03 clickhouse-client
docker exec -it clickhouse-04 clickhouse-client
각 호스트의 clickhouse-client에서 아래 쿼리를 실행해 기본 데이터베이스 외에는 아직 만들어진 데이터베이스가 없는지 확인할 수 있어요:
Query
SHOW DATABASES;
Response
┌─name───────────────┐
1. │ INFORMATION_SCHEMA │
2. │ default │
3. │ information_schema │
4. │ system │
└────────────────────┘
clickhouse-01 클라이언트에서 ON CLUSTER 절을 사용한 다음 분산 DDL 쿼리를 실행해 uk라는 새 데이터베이스를 만들어요:
CREATE DATABASE IF NOT EXISTS uk
ON CLUSTER cluster_2S_2R;
쿼리를 clickhouse-01에서만 실행했는데도 데이터베이스가 클러스터 전체에 생성되었는지 확인하려면 각 호스트의 클라이언트에서 이전과 같은 쿼리를 다시 실행할 수 있어요:
SHOW DATABASES;
┌─name───────────────┐
1. │ INFORMATION_SCHEMA │
2. │ default │
3. │ information_schema │
4. │ system │
5. │ uk │
└────────────────────┘
6. 클러스터에 테이블 만들기
데이터베이스가 만들어졌으니 다음으로 복제가 있는 테이블을 만들 거예요. 어느 호스트 클라이언트에서든 다음 쿼리를 실행해요:
CREATE TABLE IF NOT EXISTS uk.uk_price_paid_local
ON CLUSTER cluster_2S_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)
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{database}/{table}/{shard}', '{replica}')
ORDER BY (postcode1, postcode2, addr1, addr2);
이것은 ON CLUSTER 절과 ReplicatedMergeTree 엔진 사용을 제외하면 UK property prices 예제 데이터셋 튜토리얼의 원래 CREATE 문에서 사용한 쿼리와 동일해요. ON CLUSTER 절은 CREATE, DROP, ALTER, RENAME 같은 DDL(Data Definition Language) 쿼리의 분산 실행을 위해 설계되어, 이러한 스키마 변경이 클러스터의 모든 노드에 적용되도록 보장해요. ReplicatedMergeTree 엔진은 일반 MergeTree 테이블 엔진처럼 동작하지만 데이터도 복제해요. 두 매개변수를 지정해야 해요:
zoo_path: 테이블 메타데이터의 Keeper/ZooKeeper 경로.replica_name: 테이블의 레플리카 이름.
zoo_path 매개변수는 원하는 무엇이든 설정할 수 있지만, 접두사를 사용하는 관례를 따르는 것이 권장돼요:
/clickhouse/tables/{shard}/{database}/{table}
여기서:
{database}와{table}은 자동으로 대체돼요.{shard}와{replica}는 각 ClickHouse 노드의config.xml파일에서 이전에 정의한 매크로예요.
각 호스트의 클라이언트에서 아래 쿼리를 실행해 테이블이 클러스터 전체에 생성되었는지 확인할 수 있어요:
Query
SHOW TABLES IN uk;
Response
┌─name────────────────┐
1. │ uk_price_paid_local │
└─────────────────────┘
7. 분산 테이블에 데이터 삽입
테이블에 데이터를 삽입하려면 ON CLUSTER를 사용할 수 없어요. ON CLUSTER는 INSERT, UPDATE, DELETE 같은 DML(Data Manipulation Language) 쿼리에는 적용되지 않기 때문이에요. 데이터를 삽입하려면 Distributed 테이블 엔진을 사용해야 해요. 2 샤드 1 레플리카 클러스터 설정 가이드에서 배웠듯이, 분산 테이블은 서로 다른 호스트에 있는 샤드에 접근할 수 있는 테이블이며 Distributed 테이블 엔진으로 정의돼요. 분산 테이블은 클러스터의 모든 샤드에 걸친 인터페이스 역할을 해요.
어느 호스트 클라이언트에서든 다음 쿼리를 실행해 이전 단계에서 만든 기존 복제 테이블을 사용하는 분산 테이블을 만들어요:
CREATE TABLE IF NOT EXISTS uk.uk_price_paid_distributed
ON CLUSTER cluster_2S_2R
ENGINE = Distributed('cluster_2S_2R', 'uk', 'uk_price_paid_local', rand());
이제 각 호스트에서 uk 데이터베이스에 다음 테이블들이 보여요:
┌─name──────────────────────┐
1. │ uk_price_paid_distributed │
2. │ uk_price_paid_local │
└───────────────────────────┘
uk_price_paid_distributed 테이블에 어느 호스트 클라이언트에서든 다음 쿼리를 사용해 데이터를 삽입할 수 있어요:
INSERT INTO uk.uk_price_paid_distributed
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;
삽입된 데이터가 클러스터의 노드들에 고르게 분산되었는지 확인하려면 다음 쿼리를 실행해요:
SELECT count(*)
FROM uk.uk_price_paid_distributed;
SELECT count(*) FROM uk.uk_price_paid_local;
┌──count()─┐
1. │ 30212555 │ -- 30.21 million
└──────────┘
┌──count()─┐
1. │ 15105983 │ -- 15.11 million
└──────────┘
결론 (Conclusion)
2 샤드 2 레플리카인 이 클러스터 토폴로지의 장점은 확장성과 장애 허용을 모두 제공한다는 것이에요. 데이터는 별도의 호스트들에 분산되어 노드당 저장·I/O 요구를 줄이고, 쿼리는 성능과 메모리 효율성을 위해 두 샤드에 걸쳐 병렬로 처리돼요. 결정적으로, 각 샤드가 다른 노드에 백업 레플리카를 가지므로 클러스터는 노드 하나의 손실을 견디고 중단 없이 쿼리를 계속 제공할 수 있어요. 이 클러스터 토폴로지의 주요 단점은 저장 오버헤드 증가예요 — 각 샤드가 중복되므로 레플리카가 없는 설정보다 두 배의 저장 용량이 필요해요. 또한 클러스터는 단일 노드 실패를 견딜 수 있지만, 두 노드가 동시에 손실되면 어떤 노드가 실패하고 샤드가 어떻게 분산되는지에 따라 클러스터가 동작하지 않을 수 있어요. 이 토폴로지는 가용성과 비용 사이의 균형을 이루어, 더 높은 복제 계수의 비용 없이 어느 정도의 장애 허용이 요구되는 프로덕션 환경에 적합해요. ClickHouse Cloud가 확장성과 장애 허용을 모두 제공하면서 쿼리를 처리하는 방법을 배우려면 "Parallel Replicas" 섹션을 참고하세요.