Replicated\*MergeTree 테이블
Replicated*MergeTree 테이블 (복제)
ClickHouse Cloud에서는 복제가 자동으로 관리돼요. 인자 없이 테이블을 만들어주세요. 예를 들어 아래 텍스트에서 다음을
ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/table_name',
'{replica}'
)
다음으로 대체하게 돼요.
ENGINE = ReplicatedMergeTree
복제는 MergeTree 패밀리의 테이블에서만 지원돼요.
- ReplicatedSummingMergeTree
- ReplicatedCoalescingMergeTree
- ReplicatedVersionedCollapsingMergeTree
- ReplicatedCollapsingMergeTree
- ReplicatedGraphiteMergeTree
- ReplicatedMergeTree
- ReplicatedReplacingMergeTree
- ReplicatedAggregatingMergeTree
복제는 전체 서버가 아닌 개별 테이블 수준에서 동작해요. 서버는 복제 테이블과 비복제 테이블을 동시에 저장할 수 있어요. 복제는 샤딩과 무관해요. 각 샤드는 자체 독립적인 복제를 가져요.
INSERT와 ALTER 쿼리에 대한 압축 데이터가 복제돼요 (자세한 내용은 ALTER 문서 참고). CREATE, DROP, ATTACH, DETACH, RENAME 쿼리는 단일 서버에서 실행되고 복제되지 않아요.
CREATE TABLE쿼리는 쿼리가 실행되는 서버에 새 복제 가능 테이블을 만들어요. 이 테이블이 다른 서버에 이미 존재하면 새 복제본을 추가해요DROP TABLE쿼리는 쿼리가 실행되는 서버에 있는 복제본을 삭제해요RENAME쿼리는 복제본 중 하나에서 테이블 이름을 변경해요. 즉, 복제 테이블은 서로 다른 복제본에서 서로 다른 이름을 가질 수 있어요
ClickHouse는 복제본 메타 정보를 저장하기 위해 ClickHouse Keeper를 사용해요. ZooKeeper 버전 3.4.5 이상을 사용할 수 있지만 ClickHouse Keeper가 권장돼요.
복제를 사용하려면 zookeeper 서버 구성 섹션에 매개변수를 설정해요. 보안 설정을 소홀히 하지 마세요. ClickHouse는 ZooKeeper 보안 하위 시스템의 digest ACL 스킴을 지원해요.
ClickHouse Keeper 클러스터 주소 설정 예시:
<zookeeper>
<node>
<host>example1</host>
<port>2181</port>
</node>
<node>
<host>example2</host>
<port>2181</port>
</node>
<node>
<host>example3</host>
<port>2181</port>
</node>
</zookeeper>
ClickHouse는 보조(auxiliary) ZooKeeper 클러스터에 복제본 메타 정보를 저장하는 것도 지원해요. 엔진 인자로 ZooKeeper 클러스터 이름과 경로를 제공하면 돼요. 즉, 서로 다른 테이블의 메타데이터를 서로 다른 ZooKeeper 클러스터에 저장하는 것을 지원해요.
보조 ZooKeeper 클러스터 주소 설정 예시:
<auxiliary_zookeepers>
<zookeeper2>
<node>
<host>example_2_1</host>
<port>2181</port>
</node>
<node>
<host>example_2_2</host>
<port>2181</port>
</node>
<node>
<host>example_2_3</host>
<port>2181</port>
</node>
</zookeeper2>
<zookeeper3>
<node>
<host>example_3_1</host>
<port>2181</port>
</node>
</zookeeper3>
</auxiliary_zookeepers>
테이블 메타데이터를 기본 ZooKeeper 클러스터 대신 보조 ZooKeeper 클러스터에 저장하려면 SQL로 ReplicatedMergeTree 엔진을 사용해 테이블을 다음과 같이 만들 수 있어요.
CREATE TABLE table_name ( ... ) ENGINE = ReplicatedMergeTree('zookeeper_name_configured_in_auxiliary_zookeepers:path', 'replica_name') ...
기존 ZooKeeper 클러스터를 아무거나 지정할 수 있고 시스템은 자체 데이터를 위해 그 위의 디렉터리를 사용해요 (디렉터리는 복제 가능 테이블을 만들 때 지정됨).
구성 파일에 ZooKeeper가 설정되지 않으면 복제 테이블을 만들 수 없고 기존 복제 테이블은 읽기 전용이 돼요.
SELECT 쿼리에는 ZooKeeper가 사용되지 않아요. 복제가 SELECT 성능에 영향을 주지 않고 쿼리가 비복제 테이블과 똑같이 빠르게 실행되기 때문이에요. 분산 복제 테이블을 조회할 때 ClickHouse 동작은 max_replica_delay_for_distributed_queries와 fallback_to_stale_replicas_for_distributed_queries 설정으로 제어돼요.
각 INSERT 쿼리에 대해 대략 10개의 항목이 여러 트랜잭션을 통해 ZooKeeper에 추가돼요. (더 정확히는 삽입된 각 데이터 블록에 대해서이고, INSERT 쿼리는 하나의 블록 또는 max_insert_block_size = 1048576행당 하나의 블록을 포함해요.) 이는 비복제 테이블보다 INSERT 지연이 약간 길어지게 해요. 하지만 초당 하나 이하의 INSERT 배치로 데이터를 삽입하라는 권장 사항을 따른다면 문제가 생기지 않아요. 하나의 ZooKeeper 클러스터를 조정하는 데 사용되는 전체 ClickHouse 클러스터는 총 초당 수백 개의 INSERT를 처리해요. 데이터 삽입 처리량(초당 행 수)은 비복제 데이터만큼 높아요.
매우 큰 클러스터의 경우 다른 샤드에 다른 ZooKeeper 클러스터를 사용할 수 있어요. 그러나 우리 경험상 약 300개 서버가 있는 프로덕션 클러스터에 기반해 볼 때 필요하지 않았어요.
복제는 비동기적이며 멀티 마스터예요. INSERT 쿼리(ALTER도)는 사용 가능한 아무 서버에나 보낼 수 있어요. 데이터는 쿼리가 실행되는 서버에 삽입된 다음 다른 서버로 복사돼요. 비동기적이므로 최근 삽입된 데이터는 약간의 지연과 함께 다른 복제본에 나타나요. 일부 복제본을 사용할 수 없으면 데이터는 사용 가능해질 때 쓰여져요. 복제본이 사용 가능하면 지연은 압축된 데이터 블록을 네트워크로 전송하는 데 걸리는 시간이에요. 복제 테이블에 대한 백그라운드 작업을 수행하는 스레드 수는 background_schedule_pool_size 설정으로 설정할 수 있어요.
ReplicatedMergeTree 엔진은 복제 fetch를 위해 별도의 스레드 풀을 사용해요. 풀 크기는 서버 재시작으로 조정할 수 있는 background_fetches_pool_size 설정으로 제한돼요.
기본적으로 INSERT 쿼리는 하나의 복제본에서만 데이터 쓰기 확인을 기다려요. 데이터가 하나의 복제본에만 성공적으로 쓰였고 그 복제본이 있는 서버가 사라지면 저장된 데이터가 손실돼요. 여러 복제본에서 데이터 쓰기 확인을 받으려면 insert_quorum 옵션을 사용해요.
각 데이터 블록은 원자적으로 쓰여져요. INSERT 쿼리는 max_insert_block_size = 1048576행까지의 블록으로 나뉘어요. 즉, INSERT 쿼리에 1048576행 미만이 있으면 원자적으로 수행돼요.
데이터 블록은 중복 제거돼요. 같은 데이터 블록을 여러 번 쓰면(같은 크기이고 같은 순서로 같은 행을 포함하는 데이터 블록) 블록은 한 번만 쓰여져요. 이유는 네트워크 실패 시 클라이언트 애플리케이션이 데이터가 DB에 쓰였는지 알지 못하므로 INSERT 쿼리를 단순히 반복할 수 있기 때문이에요. 동일한 데이터를 가진 INSERT가 어떤 복제본에 보내졌는지는 중요하지 않아요. INSERT는 멱등(idempotent)해요. 중복 제거 매개변수는 merge_tree 서버 설정으로 제어돼요.
복제 중에는 삽입할 소스 데이터만 네트워크로 전송돼요. 추가 데이터 변환(병합)은 모든 복제본에서 같은 방식으로 조정되고 수행돼요. 이는 네트워크 사용을 최소화하므로 복제본이 다른 데이터센터에 있을 때 복제가 잘 동작한다는 뜻이에요. (서로 다른 데이터센터에 데이터를 복제하는 것이 복제의 주요 목표라는 점을 유의해요.)
같은 데이터의 복제본은 몇 개든 가질 수 있어요. 우리 경험에 기반하면 상대적으로 안정적이고 편리한 해결책은 각 서버가 RAID-5 또는 RAID-6 (그리고 일부 경우 RAID-10)을 사용하는 프로덕션에서 이중 복제(double replication)를 사용하는 것이에요.
시스템은 복제본의 데이터 동기성을 모니터링하고 실패 후 복구할 수 있어요. 장애 조치는 자동(데이터 차이가 작을 때) 또는 반자동(데이터 차이가 너무 클 때, 구성 오류를 나타낼 수 있음)이에요.
출처: 문서
본문
복제 테이블 생성하기
ClickHouse Cloud에서는 복제가 자동으로 처리돼요. 복제 인자 없이 MergeTree로 테이블을 만들어요. 시스템은 내부적으로 복제와 데이터 분배를 위해 MergeTree를 SharedMergeTree로 다시 써요. ReplicatedMergeTree를 사용하거나 복제 매개변수를 지정하지 마세요. 복제는 플랫폼이 관리해요.
Replicated*MergeTree 매개변수
| Parameter | Description |
|---|---|
zoo_path |
ClickHouse Keeper에서 테이블의 경로 |
replica_name |
ClickHouse Keeper에서 복제본 이름 |
other_parameters |
복제 버전을 만드는 데 사용되는 엔진의 매개변수. 예: ReplacingMergeTree의 version |
예시:
CREATE TABLE table_name
(
EventDate DateTime,
CounterID UInt32,
UserID UInt32,
ver UInt16
)
ENGINE = ReplicatedReplacingMergeTree('/clickhouse/tables/{layer}-{shard}/table_name', '{replica}', ver)
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate, intHash32(UserID))
SAMPLE BY intHash32(UserID);
예시에서 볼 수 있듯이 이 매개변수들은 {} 안의 치환(substitution)을 포함할 수 있어요. 치환된 값은 구성 파일의 macros 섹션에서 가져와요.
예시:
<macros>
<shard>02</shard>
<replica>example05-02-1</replica>
</macros>
ClickHouse Keeper에서 테이블의 경로는 각 복제 테이블마다 고유해야 해요. 다른 샤드의 테이블은 다른 경로를 가져야 해요. 이 경우 경로는 다음 부분들로 구성돼요: /clickhouse/tables/는 공통 접두사예요. 정확히 이것을 사용할 것을 권장해요. {shard}는 샤드 식별자로 확장돼요. table_name은 ClickHouse Keeper에서 테이블을 위한 노드의 이름이에요. 테이블 이름과 같게 하는 것이 좋아요. 그것은 RENAME 쿼리 후에도 바뀌지 않기 때문에 명시적으로 정의돼요.
힌트: table_name 앞에 데이터베이스 이름을 추가할 수도 있어요. 예: db_name.table_name
두 개의 내장 치환 {database}와 {table}을 사용할 수 있고, 각각 테이블 이름과 데이터베이스 이름으로 확장돼요 (macros 섹션에 이 매크로가 정의되지 않은 경우). 그래서 zookeeper 경로를 '/clickhouse/tables/{shard}/{database}/{table}'로 지정할 수 있어요.
이 내장 치환을 사용할 때 테이블 이름 변경에 주의해요. ClickHouse Keeper의 경로는 변경할 수 없고, 테이블 이름이 바뀌면 매크로가 다른 경로로 확장되어 테이블이 ClickHouse Keeper에 존재하지 않는 경로를 참조하게 되고 읽기 전용 모드로 들어가요.
복제본 이름은 같은 테이블의 서로 다른 복제본을 식별해요. 예시처럼 서버 이름을 사용할 수 있어요. 이름은 각 샤드 안에서만 고유하면 돼요.
치환 대신 매개변수를 명시적으로 정의할 수 있어요. 테스트와 소규모 클러스터 구성에 편리할 수 있어요. 그러나 이 경우 분산 DDL 쿼리(ON CLUSTER)를 사용할 수 없어요.
대규모 클러스터로 작업할 때는 치환 사용을 권장해요. 오류 확률을 줄여주기 때문이에요.
서버 구성 파일에서 Replicated 테이블 엔진의 기본 인자를 지정할 수 있어요. 예:
<default_replica_path>/clickhouse/tables/{shard}/{database}/{table}</default_replica_path>
<default_replica_name>{replica}</default_replica_name>
이 경우 테이블을 만들 때 인자를 생략할 수 있어요.
CREATE TABLE table_name (
x UInt32
) ENGINE = ReplicatedMergeTree
ORDER BY x;
이것은 다음과 동일해요.
CREATE TABLE table_name (
x UInt32
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/{database}/table_name', '{replica}')
ORDER BY x;
각 복제본에서 CREATE TABLE 쿼리를 실행해요. 이 쿼리는 새 복제 테이블을 만들거나 기존 것에 새 복제본을 추가해요. 다른 복제본에 테이블에 이미 일부 데이터가 있으면 새 복제본을 추가한 후 그 데이터가 다른 복제본에서 새 복제본으로 복사돼요. 즉, 새 복제본이 다른 것들과 동기화돼요.
복제본을 삭제하려면 DROP TABLE을 실행해요. 그러나 하나의 복제본만 삭제돼요 — 쿼리를 실행하는 서버에 있는 것만요.
실패 후 복구
서버 시작 시 ClickHouse Keeper를 사용할 수 없으면 복제 테이블이 읽기 전용 모드로 전환돼요. 시스템은 ClickHouse Keeper에 주기적으로 연결을 시도해요.
INSERT 중 ClickHouse Keeper를 사용할 수 없거나 ClickHouse Keeper와 상호작용 중 오류가 발생하면 예외가 던져져요.
ClickHouse Keeper에 연결한 후 시스템은 로컬 파일시스템의 데이터 집합이 예상 데이터 집합(ClickHouse Keeper가 이 정보를 저장)과 일치하는지 확인해요. 사소한 불일치가 있으면 시스템이 복제본과 데이터를 동기화해 해결해요.
시스템이 손상된 데이터 파트(파일 크기가 잘못된) 또는 인식할 수 없는 파트(파일시스템에 기록되었지만 ClickHouse Keeper에 기록되지 않은 파트)를 감지하면 detached 하위 디렉터리로 이동해요 (삭제되지는 않음). 누락된 파트는 복제본에서 복사돼요.
ClickHouse는 대량의 데이터를 자동으로 삭제하는 것 같은 파괴적인 작업을 수행하지 않는다는 점을 유의해요.
서버가 시작될 때(또는 ClickHouse Keeper와 새 세션을 수립할 때) 모든 파일의 수량과 크기만 확인해요. 파일 크기가 일치하지만 중간 어딘가의 바이트가 변경된 경우 즉시 감지되지 않고 SELECT 쿼리로 데이터를 읽으려 할 때만 감지돼요. 쿼리는 압축 블록의 체크섬이나 크기 불일치에 대한 예외를 던져요. 이 경우 데이터 파트는 검증 큐에 추가되고 필요한 경우 복제본에서 복사돼요.
로컬 데이터 집합이 예상과 너무 많이 다르면 안전 메커니즘이 트리거돼요. 서버는 이를 로그에 기록하고 시작을 거부해요. 이유는 이 경우 구성 오류를 나타낼 수 있기 때문이에요. 예를 들어 샤드의 복제본이 실수로 다른 샤드의 복제본처럼 구성된 경우. 그러나 이 메커니즘의 임계값은 꽤 낮게 설정되어 있고 이 상황은 정상적인 실패 복구 중에도 발생할 수 있어요. 이 경우 데이터는 반자동으로 — "버튼을 눌러" 복원돼요.
복구를 시작하려면 ClickHouse Keeper에서 /path_to_table/replica_name/flags/force_restore_data 노드를 내용과 함께 만들거나, 모든 복제 테이블을 복원하는 명령을 실행해요.
sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data
그런 다음 서버를 재시작해요. 시작 시 서버는 이 플래그를 삭제하고 복구를 시작해요.
완전한 데이터 손실 후 복구
서버 중 하나에서 모든 데이터와 메타데이터가 사라졌다면 복구를 위해 다음 단계를 따르세요.
- 서버에 ClickHouse를 설치해요. 사용한다면 샤드 식별자와 복제본을 포함하는 구성 파일에서 치환을 올바르게 정의해요
- 서버에 수동으로 복제해야 하는 비복제 테이블이 있었다면 복제본에서 그것들의 데이터를 복사해요 (
/var/lib/clickhouse/data/db_name/table_name/디렉터리) - 복제본에서
/var/lib/clickhouse/metadata/에 있는 테이블 정의를 복사해요. 테이블 정의에 샤드나 복제본 식별자가 명시적으로 정의되어 있으면 이 복제본에 해당하도록 수정해요. (또는 서버를 시작하고/var/lib/clickhouse/metadata/의 .sql 파일에 있었어야 할ATTACH TABLE쿼리를 모두 실행해요.) - 복구를 시작하려면
/path_to_table/replica_name/flags/force_restore_dataClickHouse Keeper 노드를 내용과 함께 만들거나, 모든 복제 테이블을 복원하는 명령을 실행해요:sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data
그런 다음 서버를 시작해요 (이미 실행 중이라면 재시작). 데이터가 복제본에서 다운로드돼요.
대체 복구 옵션은 ClickHouse Keeper에서 손실된 복제본에 대한 정보를 삭제하고(/path_to_table/replica_name), 그런 다음 "Creating replicated tables"에서 설명한 대로 복제본을 다시 만드는 것이에요.
복구 중 네트워크 대역폭 제한은 없어요. 한 번에 많은 복제본을 복원한다면 이 점을 염두에 두세요.
MergeTree에서 ReplicatedMergeTree로 변환
우리는 MergeTree라는 용어를 MergeTree family의 모든 테이블 엔진을 가리키는 데 사용해요. ReplicatedMergeTree도 마찬가지예요.
수동으로 복제된 MergeTree 테이블이 있다면 복제 테이블로 변환할 수 있어요. 이미 MergeTree 테이블에 많은 데이터를 모았고 이제 복제를 활성화하려 할 때 필요할 수 있어요.
ATTACH TABLE … AS REPLICATED 문은 분리된 MergeTree 테이블을 ReplicatedMergeTree로 붙일 수 있게 해줘요.
MergeTree 테이블은 테이블의 데이터 디렉터리(Atomic 데이터베이스의 경우 /store/xxx/xxxyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/)에 convert_to_replicated 플래그가 설정되어 있으면 서버 재시작 시 자동으로 변환될 수 있어요. 빈 convert_to_replicated 파일을 만들면 다음 서버 재시작 시 테이블이 복제된 것으로 로드돼요.
이 쿼리는 테이블의 데이터 경로를 얻는 데 사용할 수 있어요. 테이블에 데이터 경로가 여러 개 있으면 첫 번째를 사용해야 해요.
SELECT data_paths FROM system.tables WHERE table = 'table_name' AND database = 'database_name';
ReplicatedMergeTree 테이블이 default_replica_path와 default_replica_name 설정의 값으로 생성된다는 점을 유의해요. 다른 복제본에 변환된 테이블을 만들려면 ReplicatedMergeTree 엔진의 첫 번째 인자에 그 경로를 명시적으로 지정해야 해요. 다음 쿼리로 경로를 얻을 수 있어요.
SELECT zookeeper_path FROM system.replicas WHERE table = 'table_name';
수동으로 하는 방법도 있어요. 여러 복제본에서 데이터가 다르면 먼저 동기화하거나 하나의 복제본을 제외한 모든 복제본에서 이 데이터를 삭제해요. 기존 MergeTree 테이블 이름을 바꾸고, 옛 이름으로 ReplicatedMergeTree 테이블을 만들어요. 새 테이블 데이터가 있는 디렉터리(/var/lib/clickhouse/data/db_name/table_name/) 안의 detached 하위 디렉터리로 옛 테이블의 데이터를 이동해요. 그런 다음 복제본 중 하나에서 ALTER TABLE ATTACH PARTITION을 실행해 이 데이터 파트를 작업 집합에 추가해요.
ReplicatedMergeTree에서 MergeTree로 변환
ATTACH TABLE … AS NOT REPLICATED 문을 사용해 분리된 ReplicatedMergeTree 테이블을 단일 서버에서 MergeTree로 붙여요.
이것을 하는 또 다른 방법은 서버 재시작을 포함해요. 다른 이름으로 MergeTree 테이블을 만들어요. ReplicatedMergeTree 테이블 데이터가 있는 디렉터리의 모든 데이터를 새 테이블의 데이터 디렉터리로 이동해요. 그런 다음 ReplicatedMergeTree 테이블을 삭제하고 서버를 재시작해요.
서버를 시작하지 않고 ReplicatedMergeTree 테이블을 없애려면:
- 메타데이터 디렉터리(
/var/lib/clickhouse/metadata/)에서 해당.sql파일을 삭제해요 - ClickHouse Keeper에서 해당 경로(
/path_to_table/replica_name)를 삭제해요
그 후 서버를 시작하고 MergeTree 테이블을 만들고 데이터를 그 디렉터리로 이동한 다음 서버를 재시작할 수 있어요.
ClickHouse Keeper 클러스터의 메타데이터가 손실되거나 손상된 경우의 복구
ClickHouse Keeper의 데이터가 손실되거나 손상되면 위에서 설명한 대로 비복제 테이블로 이동해 데이터를 저장할 수 있어요.
함께 보기
- background_schedule_pool_size
- background_fetches_pool_size
- execute_merges_on_single_replica_time_threshold
- max_replicated_fetches_network_bandwidth
- max_replicated_sends_network_bandwidth