Replicated 데이터베이스 엔진
Replicated 데이터베이스 엔진
Atomic 엔진에 기반한 데이터베이스 엔진이에요. ZooKeeper에 쓰이고 주어진 데이터베이스의 모든 복제본에서 실행되는 DDL 로그를 통한 메타데이터 복제를 지원해요.
출처: 문서
본문
이 엔진은 Atomic 엔진에 기반해요. ZooKeeper에 쓰이고 주어진 데이터베이스의 모든 복제본에서 실행되는 DDL 로그를 통한 메타데이터 복제를 지원해요. 하나의 ClickHouse 서버는 여러 복제 데이터베이스를 동시에 실행·업데이트할 수 있어요. 하지만 같은 복제 데이터베이스의 여러 복제본은 있을 수 없어요.
데이터베이스 만들기 (Creating a database)
CREATE DATABASE testdb [UUID '...'] ENGINE = Replicated('zoo_path', 'shard_name', 'replica_name') [SETTINGS ...]
엔진 매개변수 (Engine Parameters)
zoo_path— ZooKeeper 경로. 같은 ZooKeeper 경로는 같은 데이터베이스에 대응해요.shard_name— 샤드 이름. 데이터베이스 복제본은shard_name으로 샤드로 그룹화돼요.replica_name— 복제본 이름. 복제본 이름은 같은 샤드의 모든 복제본에 대해 서로 달라야 해요.
매개변수는 생략할 수 있고, 이 경우 누락된 매개변수가 기본값으로 대체돼요. zoo_path가 매크로 {uuid}를 포함하면 명시적 UUID를 지정하거나 생성 문에 ON CLUSTER를 추가해 모든 복제본이 이 데이터베이스에 같은 UUID를 사용하도록 보장해야 해요. ReplicatedMergeTree 테이블의 경우 인자가 없으면 기본 인자가 사용돼요: /clickhouse/tables/{uuid}/{shard}와 {replica}. 이것들은 서버 설정 default_replica_path와 default_replica_name에서 바꿀 수 있어요. 매크로 {uuid}는 테이블의 uuid로 펼쳐지고, {shard}와 {replica}는 데이터베이스 엔진 인자가 아니라 서버 설정의 값으로 펼쳐져요. 하지만 앞으로는 Replicated 데이터베이스의 shard_name과 replica_name을 사용할 수 있게 될 거예요.
기본 ZooKeeper 클러스터 대신 보조 ZooKeeper 클러스터로 복제 데이터베이스의 메타데이터를 저장하는 것도 지원돼요. SQL로 보조 ZooKeeper 클러스터로 복제 데이터베이스를 다음과 같이 만들 수 있어요.
CREATE DATABASE database_name ENGINE = Replicated('zookeeper_name_configured_in_auxiliary_zookeepers:path', 'shard_name', 'replica_name')
세부 사항과 권장 사항 (Specifics and recommendations)
Replicated 데이터베이스의 DDL 쿼리는 ON CLUSTER 쿼리와 비슷하게 동작하지만 약간의 차이가 있어요. 먼저 DDL 요청이 개시자(사용자로부터 원래 요청을 받은 호스트)에서 실행을 시도해요. 요청이 이행되지 않으면 사용자는 즉시 오류를 받고 다른 호스트는 그것을 이행하려 하지 않아요. 개시자에서 요청이 성공적으로 완료되면 다른 모든 호스트는 완료할 때까지 자동으로 재시도해요. 개시자는 다른 호스트에서 쿼리가 완료되기를 기다리려고 하고(최대 distributed_ddl_task_timeout), 각 호스트의 쿼리 실행 상태가 있는 테이블을 반환해요.
오류 시 동작은 distributed_ddl_output_mode 설정으로 조절돼요. Replicated 데이터베이스의 경우 null_status_on_timeout으로 설정하는 것이 더 좋아요. 즉 어떤 호스트가 distributed_ddl_task_timeout 동안 요청을 실행하지 못했다면 예외를 던지는 대신 그들을 위한 테이블에 NULL 상태를 보여주는 것이에요.
system.clusters 시스템 테이블은 복제 데이터베이스와 같은 이름의 클러스터를 포함하며, 이 클러스터는 데이터베이스의 모든 복제본으로 구성돼요. 이 클러스터는 복제본을 만들거나 삭제할 때 자동으로 업데이트되며, Distributed 테이블에 사용할 수 있어요.
데이터베이스의 새 복제본을 만들 때 그 복제본은 스스로 테이블을 만들어요. 복제본이 오랫동안 사용 불가하여 복제 로그에 뒤처졌다면, 로컬 메타데이터를 ZooKeeper의 현재 메타데이터와 검사하고, 초과 테이블을 데이터와 함께 별도의 비복제 데이터베이스로 옮기고(실수로 불필요한 것을 삭제하지 않도록), 누락된 테이블을 만들고, 이름이 바뀌었으면 테이블 이름을 업데이트해요. 데이터는 ReplicatedMergeTree 수준에서 복제돼요. 즉 테이블이 복제되지 않으면 데이터가 복제되지 않아요(데이터베이스는 메타데이터만 담당해요).
ALTER TABLE FREEZE|ATTACH|FETCH|DROP|DROP DETACHED|DETACH PARTITION|PART 쿼리는 허용되지만 복제되지 않아요. 데이터베이스 엔진은 현재 복제본에만 파티션/파트를 추가·가져오기·제거할 거예요. 하지만 테이블 자체가 Replicated 테이블 엔진을 사용한다면 ATTACH 후 데이터가 복제돼요.
테이블 복제를 유지하지 않고 클러스터만 구성하면 되는 경우 Cluster Discovery 기능을 참고해요.
사용 예시 (Usage example)
세 호스트로 클러스터 만들기:
node1 :) CREATE DATABASE r ENGINE=Replicated('some/path/r','shard1','replica1');
node2 :) CREATE DATABASE r ENGINE=Replicated('some/path/r','shard1','other_replica');
node3 :) CREATE DATABASE r ENGINE=Replicated('some/path/r','other_shard','{replica}');
암시적 매개변수로 클러스터에 데이터베이스 만들기:
CREATE DATABASE r ON CLUSTER default ENGINE=Replicated;
DDL-쿼리 실행:
CREATE TABLE r.rmt (n UInt64) ENGINE=ReplicatedMergeTree ORDER BY n;
┌─────hosts────────────┬──status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ shard1|replica1 │ 0 │ │ 2 │ 0 │
│ shard1|other_replica │ 0 │ │ 1 │ 0 │
│ other_shard|r1 │ 0 │ │ 0 │ 0 │
└──────────────────────┴─────────┴───────┴─────────────────────┴──────────────────┘
시스템 테이블 보기:
SELECT cluster, shard_num, replica_num, host_name, host_address, port, is_local
FROM system.clusters WHERE cluster='r';
┌─cluster─┬─shard_num─┬─replica_num─┬─host_name─┬─host_address─┬─port─┬─is_local─┐
│ r │ 1 │ 1 │ node3 │ 127.0.0.1 │ 9002 │ 0 │
│ r │ 2 │ 1 │ node2 │ 127.0.0.1 │ 9001 │ 0 │
│ r │ 2 │ 2 │ node1 │ 127.0.0.1 │ 9000 │ 1 │
└─────────┴───────────┴─────────────┴───────────┴──────────────┴──────┴──────────┘
분산 테이블 만들고 데이터 넣기:
node2 :) CREATE TABLE r.d (n UInt64) ENGINE=Distributed('r','r','rmt', n % 2);
node3 :) INSERT INTO r.d SELECT * FROM numbers(10);
node1 :) SELECT materialize(hostName()) AS host, groupArray(n) FROM r.d GROUP BY host;
┌─hosts─┬─groupArray(n)─┐
│ node3 │ [1,3,5,7,9] │
│ node2 │ [0,2,4,6,8] │
└───────┴───────────────┘
한 호스트 더에 복제본 추가:
node4 :) CREATE DATABASE r ENGINE=Replicated('some/path/r','other_shard','r2');
zoo_path에 매크로 {uuid}가 사용되면 한 호스트 더에 복제본 추가:
node1 :) SELECT uuid FROM system.databases WHERE database='r';
node4 :) CREATE DATABASE r UUID '<uuid from previous query>' ENGINE=Replicated('some/path/{uuid}','other_shard','r2');
클러스터 구성은 이렇게 보일 거예요.
┌─cluster─┬─shard_num─┬─replica_num─┬─host_name─┬─host_address─┬─port─┬─is_local─┐
│ r │ 1 │ 1 │ node3 │ 127.0.0.1 │ 9002 │ 0 │
│ r │ 1 │ 2 │ node4 │ 127.0.0.1 │ 9003 │ 0 │
│ r │ 2 │ 1 │ node2 │ 127.0.0.1 │ 9001 │ 0 │
│ r │ 2 │ 2 │ node1 │ 127.0.0.1 │ 9000 │ 1 │
└─────────┴───────────┴─────────────┴───────────┴──────────────┴──────┴──────────┘
분산 테이블도 새 호스트에서 데이터를 얻어요.
node2 :) SELECT materialize(hostName()) AS host, groupArray(n) FROM r.d GROUP BY host;
┌─hosts─┬─groupArray(n)─┐
│ node2 │ [1,3,5,7,9] │
│ node4 │ [0,2,4,6,8] │
└───────┴───────────────┘
설정 (Settings)
다음 설정이 지원돼요.
| 설정 | 기본값 | 설명 |
|---|---|---|
max_broken_tables_ratio |
1 | 오래된(staled) 테이블이 전체 테이블에서 차지하는 비율이 이보다 크면 복제본을 자동으로 복구하지 않아요. |
max_replication_lag_to_enqueue |
50 | 복제본의 복제 지연(lag)이 이보다 크면 쿼리 실행 시도 시 예외를 던져요. 0보다 커야 해요. 0은 BAD_ARGUMENTS로 거부돼요(최소값은 1) |
wait_entry_commited_timeout_sec |
3600 | 개시자 호스트가 아직 실행하지 않았는데 timeout이 초과하면 복제본이 쿼리 취소를 시도해요. |
collection_name |
클러스터 인증의 모든 정보가 정의된 서버 설정의 컬렉션 이름. | |
check_consistency |
true | 로컬 메타데이터와 Keeper의 메타데이터의 일관성을 검사하고, 불일치 시 복제본을 복구해요. |
max_retries_before_automatic_recovery |
10 | 복제본을 잃어버린 것으로 표시하고 스냅샷에서 복구하기 전에 큐 항목 실행을 시도하는 최대 횟수(0은 무한을 뜻함) |
allow_skipping_old_temporary_tables_ddls_of_refreshable_materialized_views |
false | 켜면 Replicated 데이터베이스에서 DDL을 처리할 때 가능하면 refreshable materialized view의 임시 테이블 생성·교환 DDL을 건너뛰어요. |
logs_to_keep |
1000 | Replicated 데이터베이스에 대해 ZooKeeper에 유지할 기본 로그 수. |
default_replica_path |
/clickhouse/databases/{uuid} |
ZooKeeper의 데이터베이스 경로. 인자가 생략되면 데이터베이스 생성 중 사용돼요. |
default_replica_shard_name |
{shard} |
데이터베이스에서 복제본의 샤드 이름. 인자가 생략되면 데이터베이스 생성 중 사용돼요. |
default_replica_name |
{replica} |
데이터베이스의 복제본 이름. 인자가 생략되면 데이터베이스 생성 중 사용돼요. |
internal_replication |
false | 이 Replicated 데이터베이스의 클러스터로 만든 Distributed 테이블이 데이터를 복제본 하나로 보낼지(internal replication은 클러스터의 복제본이 스스로 복제함을 뜻함) 아니면 모든 복제본으로 보낼지(내부 복제가 없다는 것은 Distributed 테이블이 삽입된 데이터를 모든 복제본으로 보냄을 뜻함) |
기본값은 설정 파일에서 덮어쓸 수 있어요.
<clickhouse>
<database_replicated>
<max_broken_tables_ratio>0.75</max_broken_tables_ratio>
<max_replication_lag_to_enqueue>100</max_replication_lag_to_enqueue>
<wait_entry_commited_timeout_sec>1800</wait_entry_commited_timeout_sec>
<collection_name>postgres1</collection_name>
<check_consistency>false</check_consistency>
<max_retries_before_automatic_recovery>5</max_retries_before_automatic_recovery>
<default_replica_path>/clickhouse/databases/{uuid}</default_replica_path>
<default_replica_shard_name>{shard}</default_replica_shard_name>
<default_replica_name>{replica}</default_replica_name>
<internal_replication>false</internal_replication>
</database_replicated>
</clickhouse>