ClickHouse 사본을 몇 벌 둘까 — 재수화와 insert_quorum
로컬 NVMe는 빠르지만 노드와 운명을 같이합니다.
노드가 사라지면 볼륨을 다른 노드에 붙이는 대신, 새 디스크를 만들고 남은 replica에서 파트를 다시 받아야 합니다.
그래서 replica 수를 정할 때는 저장 가능한 TB보다 한 벌을 다시 만드는 동안 몇 벌이 남는가를 먼저 계산해야 합니다.
RF는 저장량 배수가 아니라 장애 예산이다
replication factor(RF)가 2이면 shard마다 파트 사본이 두 벌 있습니다.
한 노드를 잃어도 다른 한 벌에서 읽고 쓸 수 있지만, 재수화가 끝날 때까지는 더 잃을 여유가 없습니다.
RF3이면 한 벌을 복구하는 동안 두 벌이 남습니다.
| 구성 | 한 replica 장애 직후 | 복구 중 추가 장애 | 저장·컴퓨트 비용 |
|---|---|---|---|
| RF1 | shard 중단 또는 데이터 손실 | 해당 없음 | 1배 |
| RF2 | 한 벌로 서비스 | 같은 shard의 남은 벌이 죽으면 중단 | 2배 |
| RF3 | 두 벌로 서비스 | 한 벌을 더 잃어도 한 벌 남음 | 3배 |
여기서 RF3가 모든 쓰기 손실을 자동으로 막는 것은 아닙니다.
ClickHouse의 ReplicatedMergeTree 복제는 기본적으로 비동기입니다.
서버가 로컬 replica에 파트를 쓴 뒤 응답했지만 다른 replica가 가져가기 전에 그 노드가 사라지면, 그 파트의 유일한 사본을 잃을 수 있습니다.
공식 복제 문서 는 데이터 복제와 INSERT 확인 범위를 별개로 설명합니다.
RF와 insert_quorum은 다른 질문에 답한다
RF는 최종적으로 몇 벌을 유지할지 정합니다.
insert_quorum은 성공 응답 전에 몇 벌의 쓰기를 확인할지 정합니다.
RF3, insert_quorum=1
→ 최종 목표는 3벌
→ 응답 시점에는 1벌만 확정됐을 수 있음
RF3, insert_quorum=2
→ 최종 목표는 3벌
→ 응답 전에 2벌까지 기록 확인quorum을 올리면 확인 범위가 넓어지는 대신 쓰기 가용성이 줄어듭니다.
RF2에서 한 replica를 재수화하는 동안 사용할 수 있는 replica는 하나입니다.
이때 insert_quorum=2라면 정상적으로 쓰기를 완료할 수 없습니다.
RF3에서 quorum 2를 쓰면 한 replica 복구 중에도 남은 두 벌로 성공 응답을 만들 수 있습니다.
그래서 “정비 중에도 quorum 2 쓰기를 계속해야 한다”는 요구가 RF3를 고르는 명확한 조건이 됩니다.
RF2의 20%를 장애 확률로 읽으면 안 된다
3 shard × RF2를 생각해보겠습니다.
데이터 노드는 여섯 대이고 각 shard에 두 대씩 배치합니다.
두 대를 동시에 고르는 조합은 6C2 = 15개입니다.
그중 같은 shard의 두 replica를 함께 고르는 조합은 shard마다 하나씩, 모두 3개입니다.
같은 shard 두 벌을 잃는 조합 비율
= 3 / 15
= 20%이 20%는 모든 노드 쌍이 같은 확률로 동시에 고장난다고 가정한 조합 비율입니다.
실제 장애 확률이 아닙니다.
가용 영역, 랙, 인스턴스 세대, 배치 상관관계가 다르면 현실의 확률도 달라집니다.
이 계산이 알려주는 것은 RF2가 “아무 두 대나 잃어도 안전”하지 않다는 사실뿐입니다.
배치가 RF의 의미를 완성한다
같은 shard의 replica 두 벌이 같은 노드에 올라가면 RF2는 노드 장애를 견디지 못합니다.
같은 가용 영역에만 몰려도 AZ 장애에는 같은 문제가 생깁니다.
필요한 장치는 세 가지입니다.
| 장치 | 막는 것 | 막지 못하는 것 |
|---|---|---|
| hostname anti-affinity | 같은 노드에 replica 공존 | AZ 몰림 |
| topology spread | replica의 AZ 편중 | 독립 하드웨어 급사 |
| PDB | Eviction API를 통한 과도한 동시 중단 | 노드 급사, 모든 직접 삭제 |
PDB를 RF의 대체재로 보면 안 됩니다.
PDB는 계획된 중단의 일부 경로를 제한할 뿐 데이터 사본을 만들지 않습니다.
설정은 users profile에 둔다
insert_quorum은 쿼리 설정입니다.
Altinity CHI에서는 서버 설정인 configuration.settings보다 사용자 프로필인 configuration.profiles에 두는 편이 맞습니다.
spec:
configuration:
profiles:
observability/insert_quorum: 2
observability/insert_quorum_timeout: 60000
observability/insert_quorum_parallel: 1
users:
ingest/profile: observability실효값은 접속 사용자로 직접 확인합니다.
SELECT name, value, changed
FROM system.settings
WHERE name IN (
'insert_quorum',
'insert_quorum_timeout',
'insert_quorum_parallel'
);설정 파일에 문자열이 있다는 사실보다 실제 세션의 system.settings가 더 강한 증거입니다.
성공 응답 뒤 무엇이 남았는지 확인한다
quorum은 복제 지연을 없애지 않습니다.
장애 전후에는 replica 상태를 같이 봐야 합니다.
SELECT
database,
table,
replica_name,
is_readonly,
absolute_delay,
queue_size,
inserts_in_queue,
total_replicas,
active_replicas,
log_max_index - log_pointer AS log_behind
FROM system.replicas
ORDER BY database, table, replica_name;active_replicas가 RF와 같아졌다고 재수화가 끝났다고 단정하면 안 됩니다.
queue_size, inserts_in_queue, absolute_delay, log_behind가 함께 내려오는지 확인해야 합니다.
막힌 항목은 system.replication_queue에서 원인을 좁힙니다.
SELECT
database,
table,
replica_name,
type,
create_time,
num_tries,
last_exception
FROM system.replication_queue
WHERE num_tries > 0
ORDER BY create_time
LIMIT 100;재수화 시간을 먼저 재본다
로컬 디스크 사본을 다시 만드는 시간은 단순히 데이터량 ÷ 네트워크 대역폭이 아닙니다.
소스 replica의 읽기, 대상의 쓰기, 네트워크, ClickHouse fetch 동시성, 진행 중인 머지와 쿼리가 같은 자원을 나눠 씁니다.
따라서 계획된 시험에서 다음 시간을 따로 기록해야 합니다.
T0 노드 소실 판정
T1 새 노드와 PV 준비
T2 replica 프로세스 기동
T3 첫 part fetch 시작
T4 복제 queue 0
T5 absolute_delay 정상 범위RF2와 RF3의 비용 차이는 이 T0→T5 동안 한 벌만 남는 위험을 얼마에 줄일지에 대한 가격입니다.
Keeper 정족수는 별도 계산이다
데이터 replica를 세 벌 둬도 Keeper 과반을 잃으면 새 파트 등록과 복제 조정이 멈춥니다.
Keeper의 정족수는 floor(N/2) + 1입니다.
| Keeper 수 | 필요한 과반 | 견디는 동시 손실 |
|---|---|---|
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
4대는 3대보다 장애 허용 수가 늘지 않습니다.
RF를 늘릴지 Keeper를 늘릴지는 같은 버튼이 아닙니다.
RF는 데이터 사본과 재수화 위험을, Keeper 수는 조정 계층이 견딜 장애 수를 바꿉니다.
선택 기준
RF2는 다음 조건에서 합리적입니다.
- 한 replica 복구 중 단일 사본으로 서비스하는 시간을 받아들일 수 있다.
- quorum 2 쓰기를 상시 요구하지 않는다.
- 재수화 시간이 복구 목표 안에 들어온다는 측정이 있다.
- replica가 노드와 AZ에 실제로 분산돼 있다.
RF3는 다음 조건에서 비용을 설명하기 쉽습니다.
- 정비 중에도 두 사본을 유지해야 한다.
insert_quorum=2쓰기를 복구 중에도 계속해야 한다.- 재수화 창이 길어 두 번째 장애 위험을 받아들이기 어렵다.
- 노드 교체가 잦아 단일 사본 운영 시간이 누적된다.
결론 : 사본 수는 평상시 처리량보다 재수화 창의 허용 위험으로 정하고, 성공 응답의 내구성은 insert_quorum으로 따로 정해야 합니다.
설정과 동작 설명은 2026-09-15 스냅샷입니다.