Skip to Content
BlogClickHouse 업그레이드 전에 돌아갈 길부터 확인하기

ClickHouse 업그레이드 전에 돌아갈 길부터 확인하기

#ClickHouse#Kubernetes#업그레이드#백업

Kubernetes에서 애플리케이션 버전을 올렸다가 문제가 생기면 이미지 태그를 이전 값으로 되돌립니다.

ClickHouse도 같은 방법으로 끝날까요?

그럴 수도 있지만, 복구 계획을 그 가정 하나에 걸면 위험합니다.

새 버전이 디스크의 part를 다시 썼고 이전 바이너리가 그 형식을 읽지 못한다면 컨테이너만 내려도 돌아가지 않습니다.

ClickHouse 업그레이드는 바이너리 변경과 데이터 변경을 따로 추적하는 작업입니다.

이미지와 데이터는 수명이 다르다

ClickHouse 파드는 크게 세 종류의 상태를 사용합니다.

상태롤백 방법
이미지ClickHouse server, Keeper, operator이전 이미지로 교체 가능
설정profiles, users, storage policy이전 선언으로 되돌릴 수 있음
데이터MergeTree part, metadata, Keeper log백업·snapshot·replica에서 복원 필요할 수 있음

이미지는 immutable합니다.

이전 태그를 다시 실행하면 같은 바이너리로 돌아갈 수 있습니다.

데이터는 그렇지 않습니다.

업그레이드한 서버가 새 part를 만들거나 기존 part를 merge하면 영속 볼륨의 내용이 바뀝니다.

이전 바이너리로 돌아가도 그 변경은 그대로 남습니다.

그래서 ClickHouse의 self-managed update 가이드 는 릴리스 노트와 업그레이드 경로를 확인하고 백업을 준비하는 운영을 전제로 합니다.

compatibility가 해결하는 것

ClickHouse에는 compatibility 설정이 있습니다.

새 버전에서 변경된 일부 설정의 기본값을 지정한 과거 버전 수준으로 유지하는 장치입니다.

<clickhouse> <profiles> <default> <compatibility>24.8</compatibility> </default> </profiles> </clickhouse>

이 설정은 혼합 버전 구간에서 쿼리 동작의 변화를 줄이는 데 도움을 줍니다.

하지만 다음을 하지는 않습니다.

  • 이전 바이너리가 새 온디스크 포맷을 읽게 만들지 않습니다.
  • 이미 merge된 part를 과거 상태로 돌리지 않습니다.
  • 삭제되거나 mutation된 데이터를 복원하지 않습니다.
  • Keeper와 모든 주변 컴포넌트의 호환성을 자동으로 맞추지 않습니다.

compatibility는 동작 기본값의 안전장치입니다.

백업이나 downgrade 변환기가 아닙니다.

관찰 기간에도 디스크는 바뀐다

업그레이드 직후 쓰기 트래픽을 막지 않고 24시간 관찰한다고 가정해 봅니다.

새 INSERT는 당연히 새 part를 만듭니다.

직접 OPTIMIZE FINAL을 실행하지 않아도 백그라운드 merge가 기존 part를 새로 씁니다.

mutation과 TTL도 part를 변경할 수 있습니다.

따라서 “하루 동안 문제없으면 태그 롤백 가능”이라는 문장은 성립하지 않습니다.

관찰 시간이 길어질수록 새 버전이 쓴 데이터의 범위가 커질 수 있습니다.

롤백 창을 유지하려면 그 기간에 금지하거나 추적할 작업을 정해야 합니다.

작업롤백 창에 주는 영향
새 INSERT새 버전이 만든 part 증가
background merge기존 part도 새 바이너리로 재작성
mutation많은 part를 비동기로 재작성
TTL MOVE/DELETEpart 위치 또는 내용 변경
새 데이터 타입·codec이전 버전이 이해하지 못할 가능성
OPTIMIZE FINAL넓은 범위를 한 번에 다시 씀

완전한 쓰기 중단이 불가능하다면 snapshot과 replica를 이용한 복원 경계를 더 명확히 해야 합니다.

먼저 호환 행렬을 만든다

ClickStack처럼 여러 컴포넌트가 있는 환경에서는 ClickHouse server만 올리지 않습니다.

operator, Keeper, chart, OTel Collector, HyperDX app/API가 각자 버전을 가집니다.

업그레이드 전에 현재 값과 목표 값을 표로 고정합니다.

컴포넌트현재목표변경 단위되돌릴 상태
ClickHouse server고정 태그고정 태그replica별이미지 + 데이터
Keeper고정 태그고정 태그quorum 유지이미지 + Raft 상태
Altinity operator고정 버전고정 버전controllerCRD와 reconcile 동작
ClickStack chartchart versionchart versionHelm releaseDeployment, Config, schema
HyperDX app/API고정 태그고정 태그Deployment이미지와 MongoDB schema

latest 태그는 이 표를 만들 수 없게 합니다.

“어제 되던 이미지”를 다시 찾을 수 있도록 digest나 고정 버전을 기록합니다.

롤링 업그레이드의 네 규칙

replica가 있는 ClickHouse는 한 대씩 올릴 수 있습니다.

다만 단순히 StatefulSet의 기본 롤링을 믿기보다 다음 규칙을 확인합니다.

  1. 한 shard에서 동시에 여러 replica를 내리지 않습니다.
  2. 이전 replica가 Ready이고 replication queue가 안정된 뒤 다음으로 갑니다.
  3. 혼합 버전 구간을 가능한 짧게 유지합니다.
  4. Keeper는 항상 과반을 유지하며 한 대씩 올립니다.

업그레이드 전 상태를 저장합니다.

SELECT database, table, is_readonly, is_session_expired, queue_size, future_parts, parts_to_check, absolute_delay, total_replicas, active_replicas FROM system.replicas ORDER BY database, table;

다음 replica로 넘어가기 전 같은 쿼리를 다시 실행합니다.

active_replicas가 기대한 RF로 돌아오고 queue와 delay가 허용 범위에 들어왔는지 확인합니다.

서버 버전도 명시적으로 확인합니다.

SELECT hostName() AS host, version() AS version, uptime() AS uptime_seconds;

Distributed table을 통해 모든 host 결과를 모으거나, 각 replica에 직접 실행해 혼합 상태를 기록합니다.

EBS에서는 snapshot이 한 경로가 된다

EBS 기반 replica는 업그레이드 직전 볼륨 snapshot을 만들 수 있습니다.

일관성을 높이려면 대상 replica를 정상 종료한 상태에서 snapshot을 시작합니다.

그동안 다른 healthy replica가 서비스를 담당합니다.

alt[성공][else] 실패(포맷 손상/startup fatal)관찰 24~48h: OPTIMIZE FINAL·신규 타입 금지(롤백 창 유지)1. PDB 준수하며 이 replica만 stop2. stop 상태에서 데이터 볼륨 스냅샷(정합)3. 이미지 업그레이드 → 재기동 → readiness다음 replica로 진행create-volume --snapshot-id --volume-type gp3 → PV/PVC 교체Keeper 로그 델타만 catch-up운영자replica(대상)EBS/스냅샷나머지 healthyreplica
replica 단위 롤링 업그레이드 — stop→스냅샷→업그레이드, 실패 시 스냅샷 복원 + Keeper 델타 catch-up.

이 그림에서 중요한 점은 snapshot을 원래 볼륨 위에 “되감는” 것이 아니라는 점입니다.

문제가 생기면 snapshot으로 새 EBS 볼륨을 만들고, PV가 새 volume ID를 가리키도록 복구합니다.

그 replica가 올라오면 Keeper의 복제 로그를 따라 snapshot 이후 delta를 가져옵니다.

여기에도 전제가 있습니다.

  • 다른 replica가 정상이어야 합니다.
  • snapshot 시점 이후 필요한 part가 healthy replica에 남아 있어야 합니다.
  • PVC/PV 보존과 재바인딩 절차가 검증돼 있어야 합니다.
  • snapshot과 실제 테이블 데이터의 대응 시점을 기록해야 합니다.

snapshot은 백업 정책 전체를 대신하지 않습니다.

동일 리전·계정 장애, 논리 삭제의 발견 지연, Keeper와 MongoDB 같은 다른 저장소까지 별도로 봐야 합니다.

업그레이드와 볼륨 확장을 분리한다

이미지 태그, 설정, PVC 크기를 한 번에 바꾸면 실패 원인을 좁히기 어렵습니다.

특히 operator reconcile에서는 한 CR 변경이 StatefulSet과 PVC에 동시에 영향을 줄 수 있습니다.

변경을 다음처럼 나눕니다.

1. 현재 상태와 백업 검증 2. 이미지 변경 3. replica 정상화 확인 4. 설정 변경 5. 정상화 확인 6. 필요할 때 별도 PVC 확장

각 단계 사이에 관찰 가능한 성공 조건이 있어야 합니다.

“파드가 Running”만으로는 부족합니다.

readiness, replication queue, part 수, query error, ingest lag까지 확인합니다.

PDB가 롤링 순서를 만들지는 않는다

PDB는 Eviction API를 사용하는 계획된 중단에서 가용 파드 수를 보호합니다.

StatefulSet이나 operator가 반드시 원하는 순서로 한 대씩 바뀐다는 보장은 아닙니다.

노드 급사도 막지 못합니다.

따라서 PDB가 있다는 이유로 업그레이드 절차가 안전하다고 결론 내리지 않습니다.

실제 operator가 어떤 host를 먼저 reconcile하고, 실패 시 어디서 멈추는지 staging에서 확인해야 합니다.

실패 판정과 복원 판정을 미리 쓴다

업그레이드 중 언제 멈출지 정하지 않으면 오류가 보여도 계속 진행하기 쉽습니다.

예를 들어 다음을 중단 조건으로 둘 수 있습니다.

  • replica가 제한 시간 안에 Ready로 돌아오지 않음
  • system.replicas.is_readonly = 1
  • replication delay가 기준선을 계속 초과
  • 새 버전에서 query error 비율 증가
  • ingest lag가 복구 속도보다 빠르게 증가
  • 새로운 part 오류 또는 checksum 오류 발견

복원 완료 조건도 따로 둡니다.

  • 목표 버전 또는 복원 버전이 모든 대상에 명확함
  • shard마다 필요한 active replica 수가 회복됨
  • replication queue와 delay가 안정됨
  • 대표 SELECT와 INSERT가 성공함
  • 백업 이후 데이터 차이를 설명할 수 있음
  • 다음 replica로 넘어갈 근거가 기록됨

돌아갈 길은 명령이 아니라 데이터 경로다

ClickHouse 업그레이드에서 이미지 태그 롤백은 하나의 도구입니다.

데이터가 이전 바이너리와 호환될 때만 충분합니다.

실제 복구 경로는 replica, EBS snapshot, ClickHouse backup과 그 이후 delta 동기화로 만들어집니다.

업그레이드 전에 답해야 할 질문은 “어떤 태그로 돌아갈까”보다 다음에 가깝습니다.

새 버전이 이미 다시 쓴 part를 이전 버전이 읽지 못하면, 어느 시점의 어떤 사본을 어디에 복원할 것인가?

이 질문에 명령과 검증 조건으로 답할 수 있을 때 롤링 업그레이드를 시작할 수 있습니다.

자료 확인 기준: 2026-09-15. 실제 지원 업그레이드·다운그레이드 범위는 출발 버전과 목표 버전의 공식 release note에서 다시 확인해야 합니다.