컴퓨트와 스케일링 (수직, 수평, 유휴 종료, 웨어하우스로 compute-compute 분리)
ClickHouse Cloud 서비스의 컴퓨트 단위와 레플리카 개념을 잡고, 수직 오토스케일링, 수평 스케일링, Make Before Break, 스케줄 스케일링, 유휴 종료, 웨어하우스(compute-compute 분리), On-Demand Compute 를 운영자 관점에서 정리합니다.
한 줄 정리
ClickHouse Cloud 의 컴퓨트는 "레플리카 몇 개 x 레플리카당 메모리" 로 정해지고, 저장은 오브젝트 스토리지에 한 벌만 있습니다. 그래서 레플리카를 늘리거나 줄여도 데이터를 다시 복사할 필요가 없고, 서비스를 멈춘 동안에는 컴퓨트 요금이 나가지 않습니다. 이 글은 그 컴퓨트를 어떻게 키우고, 줄이고, 나누는지 다룹니다. 저장 구조 자체는 ClickHouse Cloud 개요 를 먼저 보시면 좋습니다.
서비스, 레플리카, 컴퓨트 단위
| 용어 | 뜻 | 기억할 수치 |
|---|---|---|
| 서비스 | 한 ClickHouse 클러스터. 엔드포인트 하나, 데이터 한 벌 | 티어는 조직 단위, 서비스는 티어 안에서 여러 개 |
| 레플리카 | 서비스 안의 노드 하나. 같은 데이터를 함께 읽고 쓰는 컴퓨트 | 기본 3개(Scale, Enterprise), Basic 은 1개 |
| 컴퓨트 단위 | 과금과 크기의 기본 단위 | 메모리 8 GiB + vCPU 2 개가 1 단위 |
| 레플리카 메모리 | 레플리카 하나의 RAM | 8 GiB 부터 236 GiB 까지 4 GiB 단위 |
Basic 티어의 단일 레플리카는 8 GiB 또는 12 GiB 고정이고 오토스케일링이 없습니다. Scale 과 Enterprise 는 레플리카 메모리 범위를 정해 두면 그 안에서 자동으로 오르고 내립니다. Enterprise 에는 메모리와 vCPU 비율이 다른 프로파일이 있어서, 표준 1:4(vCPU 1 에 메모리 4 GiB) 는 수직 오토스케일링이 되고, highMemory(1:8) 와 highCPU 같은 커스텀 프로파일은 지원팀을 통해 수직 조정합니다.
참고 레플리카 수가 같아도 레플리카 메모리가 커지면 그 안의 vCPU 도 비례해 늘어납니다. "메모리가 부족해서" 뿐 아니라 "CPU 가 부족해서" 도 수직 확장이 답인 경우가 많습니다.
수직 오토스케일링
레플리카 메모리의 최솟값과 최댓값을 콘솔이나 API 에서 정해 두면, 지난 사용량(메모리와 CPU)을 보고 그 범위 안에서 크기를 바꿉니다. 올릴 때는 비교적 빠르게 반응하고, 내릴 때는 한동안 여유가 확인된 뒤에 내립니다. 모든 레플리카가 같은 크기로 함께 움직입니다.
# Cloud API 로 수직 범위 조정 (조직, 서비스 ID 는 콘솔에서 확인)
curl -u "$KEY_ID:$KEY_SECRET" -X PATCH \
"https://api.clickhouse.cloud/v1/organizations/$ORG/services/$SVC/replicaScaling" \
-H 'Content-Type: application/json' \
-d '{"minReplicaMemoryGb": 16, "maxReplicaMemoryGb": 64}'팁 최솟값을 너무 낮게 두면 새벽 배치가 시작될 때 작은 크기에서 출발해 첫 몇 분이 느립니다. 배치 시간이 정해져 있으면 아래의 스케줄 스케일링으로 그 시간대만 최솟값을 올려 두는 편이 비용 대비 안정적입니다.
수평 스케일링
레플리카 수를 바꾸는 것입니다. 콘솔의 서비스 설정 화면이나 API 의 numReplicas 로 조정하고, 요청을 여러 번 보내도 마지막 값으로 수렴합니다. 레플리카가 늘어나면 동시 쿼리 처리량과 INSERT 흡수량이 늘고, 병렬 레플리카 읽기를 켜면 큰 단일 쿼리도 여러 레플리카가 나눠 읽습니다.
# 레플리카 3개에서 5개로
curl -u "$KEY_ID:$KEY_SECRET" -X PATCH \
"https://api.clickhouse.cloud/v1/organizations/$ORG/services/$SVC/replicaScaling" \
-H 'Content-Type: application/json' \
-d '{"numReplicas": 5}'- 수평 오토스케일링(부하에 따라 레플리카 수 자동 조정)은 PrPr 입니다. 지금은 수동이나 스케줄로 바꾸는 것이 기본입니다.
- 웨어하우스 안의 첫 서비스는 레플리카가 2개 이상이어야 하고, 한 웨어하우스에 속한 모든 서비스의 레플리카 합은 50개를 넘지 못합니다.
- 레플리카를 줄이면 그 레플리카로 가던 연결이 끊기므로, 클라이언트 쪽에 재시도가 있는지 먼저 확인합니다.
참고 어느 쪽을 먼저 키울지는 병목이 무엇인지에 따릅니다. 한 쿼리가 메모리 초과로 죽으면 수직, 쿼리가 많이 몰려서 대기가 생기면 수평입니다. 메모리 문제 해결 과 느린 쿼리 진단 에 진단 순서가 있습니다.
Make Before Break
크기 변경과 버전 업그레이드는 "새 레플리카를 먼저 띄우고(Make), 준비가 끝나면 옛 레플리카를 내리는(Break)" 방식으로 진행됩니다. 그래서 작업 중에 레플리카 수가 잠시 설정값보다 많아질 수 있고, 그 시간만큼 요금이 조금 더 나옵니다. 옛 레플리카에서 돌던 쿼리는 최대 1시간까지 끝나기를 기다렸다가 내려가며, 옛 레플리카의 시스템 테이블 데이터는 30일 동안 보존됩니다.
주의 1시간을 넘는 장기 쿼리는 Make Before Break 때 끊길 수 있습니다. 긴 배치는 조각으로 나누거나, 업그레이드 창(Enterprise 의 예약 업그레이드) 과 겹치지 않게 잡습니다.
스케줄 스케일링
요일, 시작 시각(UTC 정시 단위), 레플리카 수, 레플리카 메모리 최소와 최대, 유휴 종료 여부를 묶은 규칙을 여러 개 등록할 수 있습니다. 규칙이 적용되는 시간에는 스케줄 값이 일반 설정보다 우선합니다.
| 상황 | 규칙 예 |
|---|---|
| 매일 새벽 2시 대량 적재 | 월~일 02:00 UTC 부터 3시간, 최소 메모리 64 GiB, 레플리카 3 |
| 평일 업무시간 대시보드 | 월~금 00:00 UTC(한국 09시) 부터 9시간, 레플리카 4 |
| 주말 | 레플리카 2, 유휴 종료 켬 |
팁 한국 시간 기준으로 생각하다가 UTC 변환을 빠뜨리는 실수가 잦습니다. 규칙 이름에 "KST 11시 배치" 처럼 현지 시각을 함께 적어 두면 뒤에 보는 사람이 덜 헷갈립니다.
유휴 종료
쿼리가 없으면 서비스가 자동으로 멈추고, 다음 연결이 오면 다시 깨어납니다. 멈춘 동안 컴퓨트 요금은 나가지 않고 저장과 백업 요금만 나갑니다. 깨어나는 데 수 초에서 수십 초가 걸리므로 첫 쿼리가 느린 것은 정상입니다.
- 유휴까지의 시간은 서비스가 깨어나는 데 걸린 시간에 따라 자동 조정됩니다. 기동이 15분 미만이면 설정값대로, 15분에서 30분이면 15분, 30분에서 1시간이면 30분, 1시간을 넘으면 1시간이 됩니다.
- 파트가 10,000개를 넘거나 머지가 진행 중이면 유휴로 들어가지 않습니다. 파트 수가 많은 서비스는 멈추지 않는 셈이라, 파트가 너무 많을 때 를 먼저 정리해야 비용이 줍니다.
- 네트워크 접근을 "어디서나 허용" 으로 두면 인터넷 크롤러나 포트 스캐너가 연결을 시도하는 것만으로 서비스가 깨어날 수 있습니다. 개발 서비스도 IP 목록을 두는 것이 좋습니다. 방법은 네트워크와 보안 에 있습니다.
- Enterprise 의 Private Region(전용 리전) 서비스에는 오토스케일링과 유휴 종료가 없습니다.
-- 유휴 종료를 막는 요인 점검: 파트 수와 진행 중 머지
SELECT database, table, count() AS parts
FROM system.parts WHERE active
GROUP BY database, table ORDER BY parts DESC LIMIT 10;
SELECT count() AS running_merges FROM system.merges;주의 상용 서비스에 유휴 종료를 켜 두면 새벽 첫 알람 쿼리가 수십 초 걸려 모니터링이 오탐을 냅니다. 상용은 유휴 종료를 끄고, 개발과 스테이징은 켜는 것이 보통의 선택입니다.
웨어하우스로 compute-compute 분리
웨어하우스(warehouse)는 같은 데이터를 여러 서비스가 각자의 컴퓨트로 쓰는 묶음입니다. 처음 만든 서비스가 주(primary) 서비스가 되고, 같은 데이터에 붙는 부(secondary) 서비스를 추가합니다. 저장은 한 벌이라 저장 요금이 두 배가 되지 않고, 서비스마다 크기와 유휴 설정이 따로입니다.
| 항목 | 내용 |
|---|---|
| 공유하는 것 | 데이터, 데이터베이스 사용자와 권한, 리전과 클라우드, ClickHouse 버전, Keeper |
| 서비스마다 다른 것 | 레플리카 수와 크기, 유휴 종료, IP 액세스 리스트, 엔드포인트 |
| 읽기 쓰기 서비스 | INSERT 와 머지를 수행. 리프레시 MV 도 여기서만 동작 |
| 읽기 전용 서비스 | 머지를 하지 않고 즉시 유휴 가능. 종류는 만들 때 정하며 뒤에 바꿀 수 없음 |
전형적인 쓰임은 "적재와 머지를 맡는 쓰기 서비스 하나, BI 대시보드용 읽기 서비스 하나, 데이터 과학용 임시 읽기 서비스 하나" 입니다. 대시보드가 무거운 쿼리를 던져도 적재 서비스의 INSERT 지연이 늘지 않습니다.
-- 웨어하우스 안 모든 서비스의 실행 중 쿼리를 한 번에 보기
SELECT hostName(), user, elapsed, query_id, left(query, 80) AS q
FROM clusterAllReplicas('all_groups.default', system, processes)
ORDER BY elapsed DESC;팁 읽기 전용 서비스는 쿼리가 끝나면 바로 유휴로 들어가므로, 하루 두 시간만 쓰는 분석가용 서비스를 큼직하게 만들어도 요금은 두 시간치만 나갑니다. 반대로 상시 대시보드용은 작게 여러 레플리카로 두는 편이 응답이 고릅니다.
On-Demand Compute (PrPr)
쿼리 하나를 돌릴 때만 임시 워커(vCPU 8, 메모리 32 GiB 단위)를 빌려 와 분산 실행하고, 끝나면 반납하는 기능입니다. 레플리카를 영구적으로 늘리지 않고도 가끔 오는 아주 큰 SELECT 를 처리할 수 있습니다. 현재는 SELECT 만 지원하고, 임대는 최소 60초 단위로 과금됩니다.
-- 세션 단위로 On-Demand Compute 사용 (Private Preview, 활성화된 조직만)
SET make_distributed_plan = 1,
distributed_plan_workers_num = 8,
enable_parallel_replicas = 0,
distributed_plan_fallback_to_local_execution = 1;
SELECT toStartOfHour(ts) AS h, count()
FROM events WHERE ts >= now() - INTERVAL 90 DAY
GROUP BY h ORDER BY h;참고 폴백 설정을 켜 두면 워커를 못 받았을 때 서비스 자체 레플리카에서 그대로 실행됩니다. 아직 PrPr 이므로 상용 경로에 넣기보다 월말 결산처럼 드물고 큰 쿼리에 먼저 써 보는 것이 좋습니다.
큰 단일 레플리카와 사용 한도
고가용성이 필요 없는 개발용이나 일회성 분석용으로 레플리카 1개짜리 큰 서비스를 만들 수 있습니다. 단일 레플리카는 데이터베이스 100개, 테이블 500개 같은 더 낮은 한도가 적용되고, 업그레이드 때 짧은 중단이 있습니다.
일반 서비스에도 안전 한도가 있습니다. 넘어도 바로 막히지는 않지만 경고가 뜨고, 성능이 떨어지기 시작하는 지점으로 보시면 됩니다.
| 항목 | 한도 | 비고 |
|---|---|---|
| 데이터베이스 | 1,000 | 단일 레플리카는 100 |
| 테이블 | 5,000 | 단일 레플리카는 500 |
| 뷰 | 15,000 | MV 포함 |
| 딕셔너리 | 5,000 | |
| 테이블당 파티션 | 50,000 | 보통 월, 일 단위면 충분 |
| 인스턴스 전체 파트 | 10,000 | max_parts_in_total |
| 파트 하나 크기 | 150 GB | |
| LowCardinality 고유값 | 10,000 이하 권장 | 넘으면 일반 String 이 빠름 |
| 기본 키 컬럼 | 4~5개 | 키와 파티션 참고 |
| 레플리카당 동시 쿼리 | 1,000 | |
| 한 INSERT 배치 | 100만 행 넘으면 나눠서 | INSERT 모범 사례 |
-- 경고 임계값 확인
SELECT name, value FROM system.server_settings
WHERE name IN ('max_table_num_to_warn', 'max_database_num_to_warn',
'max_part_num_to_warn', 'max_view_num_to_warn');실전 팁
- 첫 크기는 "압축 후 데이터의 1/10 정도를 메모리로" 에서 출발해 조정합니다. 쿼리 패턴을 모르는 상태에서 처음부터 크게 잡으면 내리기 어렵습니다.
- 메모리 최댓값을 높이기 전에
max_memory_usage초과가 정말 한 쿼리 때문인지, 동시 쿼리 합 때문인지system.query_log로 가립니다. 전자는 수직, 후자는 수평 또는 웨어하우스 분리가 맞습니다. - 적재와 대시보드가 한 서비스에 있으면 가장 먼저 웨어하우스로 나눕니다. 비용은 거의 그대로이고 장애 전파가 끊깁니다.
- 스케줄 스케일링과 유휴 종료를 조합하면 개발 서비스 비용이 보통 절반 아래로 내려갑니다. 비용 계산은 비용 구조와 절감 에서 이어집니다.
- 크기 변경 뒤에는
system.clusters로 레플리카 수가 기대와 같은지, 클라이언트 연결 풀이 새 레플리카를 보고 있는지 확인합니다.