ClickHouse on EKS 실측 벤치마크 퀴즈
- 벤치마크에서 1시간 창의
namespace + timestamp범위 카운트(Q1)가 1억 행 테이블에서 4ms 만에 끝난 핵심 이유는 무엇인가요?- A) 결과가 이미 쿼리 캐시에 저장되어 있었기 때문에
- B) PARTITION BY(일)와 ORDER BY(namespace, timestamp)의 프루닝으로 1억 행 중 16,385행만 읽었기 때문에
- C) gp3 볼륨의 3,000 IOPS가 충분히 높았기 때문에
- D) LowCardinality 타입이 비교 연산을 벡터화했기 때문에
정답 보기
정답: B) PARTITION BY(일)와 ORDER BY(namespace, timestamp)의 프루닝으로 1억 행 중 16,385행만 읽었기 때문에
설명: 쿼리 조건이 파티션 키(일 단위)와 정렬 키(namespace, timestamp)에 정확히 겹치면 ClickHouse는 primary index로 granule 단위 프루닝을 수행합니다. 이 벤치마크에서 쿼리 결과는 59,916행이었지만 실제로 읽은 행은 16,385행(0.016%)뿐이었습니다. primary key 범위 안에 완전히 들어가는 granule은 인덱스만으로 개수를 세고(ClickHouse 24.6+ 최적화), 범위 양끝에 걸친 granule만 압축을 풀어 읽기 때문입니다. ClickHouse 성능의 대부분은 이런 "읽지 않는 설계"에서 나옵니다.
- 컬럼별 압축 결과에서 trace_id는 1.0×(압축 불가), namespace는 약 201×로 나타났습니다. 이 차이를 만든 원인으로 옳은 것은?
- A) trace_id 컬럼에만 압축 코덱이 지정되지 않았기 때문에
- B) namespace가 문자열 길이가 더 짧기 때문에
- C) 이 실행의 LZ4에서 trace_id는 반복 패턴이 적어 거의 줄지 않았고, namespace는 카디널리티가 낮은 데다 ORDER BY 첫 키라 같은 값이 길게 이어지기 때문에
- D) namespace만 사전(dictionary) 파일이 별도로 생성되기 때문에
정답 보기
정답: C) 이 실행의 LZ4에서 trace_id는 반복 패턴이 적어 거의 줄지 않았고, namespace는 카디널리티가 낮은 데다 ORDER BY 첫 키라 같은 값이 길게 이어지기 때문에
설명: 이 실행의 LZ4에서 trace_id는 원시 약 3.07 GiB → 압축 후 약 3.08 GiB였습니다. hex 문자열은 한 문자에 4비트 정보만 담으므로 다른 코덱이나 바이너리 표현으로 줄일 여지가 있습니다. 반면 namespace는 값이 10종뿐인 LowCardinality 컬럼이며 정렬 첫 키라서 동일 값이 연속 블록으로 저장되어 95.72 MiB가 488.63 KiB(201×)로 줄었습니다. 로그 스키마에서 "ID를 어떻게 저장할 것인가"가 저장 비용의 최대 변수인 이유입니다.
- LZ4(기본)와 ZSTD(3)의 실측 비교 결과로 옳은 것은?
- A) ZSTD(3)가 저장 공간과 스캔 속도 모두 우수했다
- B) 저장 공간은 ZSTD(3)가 47% 작았지만, CPU-bound 풀스캔은 LZ4보다 약 1.9배 느렸다
- C) 두 코덱의 저장 공간 차이는 5% 이내였다
- D) LZ4가 저장 공간은 작았지만 스캔이 더 느렸다
정답 보기
정답: B) 저장 공간은 ZSTD(3)가 47% 작았지만, CPU-bound 풀스캔은 LZ4보다 약 1.9배 느렸다
설명: 실측에서 LZ4는 7.82 GiB(1.97×), ZSTD(3)는 4.16 GiB(3.7×)로 저장이 47% 절감됐지만, LIKE '%timeout%' warm 풀스캔은 2.63초 → 4.9초로 느려졌습니다. 최근 LZ4 + 오래된 파티션 TTL ZSTD는 후보 조합이며, 실제 데이터·CPU·I/O 비중으로 검증해야 합니다.
LIKE '%timeout%'풀스캔(Q3)이 페이지 캐시를 우회한 디스크 직행에서 31.5초 걸렸습니다. 이 수치가 말해주는 병목은 무엇인가요?- A) ClickHouse의 문자열 검색 알고리즘이 비효율적이다
- B) message 컬럼 압축본 약 4 GiB ÷ 31.5초 ≈ 130 MiB/s로, 볼륨·인스턴스 EBS 경로의 처리량 제약과 일치하지만 단독 병목은 이 값만으로 구분할 수 없다
- C) m5.xlarge의 4 vCPU가 포화된 것이다
- D) EBS CSI 드라이버의 오버헤드가 지배적이다
정답 보기
정답: B) message 컬럼 압축본 약 4 GiB ÷ 31.5초 ≈ 130 MiB/s로, 볼륨·인스턴스 EBS 경로의 처리량 제약과 일치하지만 단독 병목은 이 값만으로 구분할 수 없다
설명: 같은 쿼리가 페이지 캐시에서는 2.63초(CPU-bound, 초당 약 3,800만 행)로 끝났습니다. 12배 차이는 캐시와 스토리지 경로의 영향을 보여 주지만, 물리 I/O와 CPU 지표 없이 gp3만 단독 병목이라고 증명할 수는 없습니다. gp3는 추가 비용으로 처리량을 최대 2,000 MiB/s까지 프로비저닝할 수 있습니다(그 수치에 닿으려면 IOPS도 8,000 이상이어야 합니다). 다만 이 m5.xlarge에서는 인스턴스의 EBS 베이스라인 약 137 MiB/s와 버스트 상태도 확인해야 합니다. 지속 수요가 이를 넘으면 노드와 볼륨을 함께 검토합니다.
- trace_id 점 조회(Q5)에 bloom filter skip index를 추가했을 때의 실측 변화로 옳은 것은?
- A) 조회 시간 1.13초 → 0.036초(31배), 읽은 행 1억 → 108만(98.9% 스킵), 인덱스 크기는 테이블의 약 1.5%
- B) 조회 시간은 그대로였지만 메모리 사용량만 줄었다
- C) 조회 시간이 절반이 되었고 인덱스가 테이블 크기의 30%를 차지했다
- D) ORDER BY 키를 바꾼 것과 동일한 효과로, 저장 공간도 함께 줄었다
정답 보기
정답: A) 조회 시간 1.13초 → 0.036초(31배), 읽은 행 1억 → 108만(98.9% 스킵), 인덱스 크기는 테이블의 약 1.5%
설명:bloom_filter(0.01) GRANULARITY 4 skip index는 각 granule 묶음에 대해 음성 결과가 나온 블록에는 해당 값이 없음을 판정하고, 양성은 false positive일 수 있어 대부분의 granule을 건너뜁니다. 실측에서 읽은 데이터가 3.82 GiB → 42.6 MiB로 줄었고, 인덱스 자체는 119.7 MiB(테이블의 1.5%), 기존 데이터 적용(MATERIALIZE)은 약 20초였습니다.
- 이 벤치마크의 ingest 수치(초당 약 94만 행)를 해석할 때 반드시 붙여야 하는 단서는 무엇인가요?
- A) 복제본 3개 구성에서 측정한 값이라는 것
- B) 서버 내부 INSERT…SELECT로 측정했으므로 외부 네트워크·파싱을 포함한 ingest 처리량을 직접 측정한 것은 아니라는 것
- C) 메모리에만 쓰고 디스크에는 기록하지 않았다는 것
- D) 압축을 끄고 측정한 값이라는 것
정답 보기
정답: B) 서버 내부 INSERT…SELECT로 측정했으므로 외부 네트워크·파싱을 포함한 ingest 처리량을 직접 측정한 것은 아니라는 것
설명: 데이터를 서버 안에서 생성해 바로 삽입했기 때문에 실제 외부 클라이언트가 TSV/Native로 밀어넣는 경로보다 유리한 조건입니다. 디스크 기록·정렬·압축은 모두 포함된 값이지만, 데이터 생성 CPU 비용도 포함하므로 외부 ingest의 수학적 상한은 아닙니다. 외부 클라이언트·배치·동시성·포맷으로 따로 측정해야 합니다.
- Q4(namespace별 duration p50/p99)는 1억 행 전체를 스캔하는데도 warm 기준 약 1초에 끝났습니다. 어떤 특성 덕분인가요?
- A) 쿼리 결과가 머티리얼라이즈드 뷰에 미리 계산되어 있었기 때문에
- B) 컬럼 지향 저장이라 duration_ms(289 MiB)와 namespace(0.5 MiB) 두 컬럼만 읽고, 테이블 전체 7.8 GiB는 읽지 않기 때문에
- C) quantile이 디스크에서 8,192행만 읽고 나머지 행은 전혀 처리하지 않기 때문에
- D) 파티션 프루닝으로 하루치 데이터만 읽었기 때문에
정답 보기
정답: B) 컬럼 지향 저장이라 duration_ms(289 MiB)와 namespace(0.5 MiB) 두 컬럼만 읽고, 테이블 전체 7.8 GiB는 읽지 않기 때문에
설명: 행 지향 데이터베이스라면 전체 행을 읽어야 하는 쿼리지만, 컬럼 지향에서는 집계에 필요한 컬럼만 읽습니다. 전 기간 스캔(1억 행)이어서 파티션 프루닝은 없었고(D 오답), quantile은 모든 입력 행을 처리하며 최대 8,192개 reservoir 표본으로 근사치를 계산합니다. 샘플링은 필요한 컬럼의 전체 입력 스캔을 없애지 않습니다. 정확한 분위수는 quantileExact 계열을 별도로 검토합니다.
- 이 가이드북의 판단 기준에 따를 때, ClickHouse를 관리형 서비스가 아니라 EKS에 self-hosted로 운영하는 선택이 특히 설득력을 갖는 경우는?
- A) 전담 플랫폼 팀이 없고 데이터베이스 운영 경험이 전무할 때
- B) 표준 관리형 서비스가 충분하고 테넌트가 하나뿐일 때
- C) 관리형 제공이 제한적이거나 비용 배수가 크고, 플랫폼 팀이 Operator 기반 운영(백업·복구 리허설 포함)을 감당할 수 있을 때
- D) 데이터가 100 GiB 미만으로 작을 때
정답 보기
정답: C) 관리형 제공이 제한적이거나 비용 배수가 크고, 플랫폼 팀이 Operator 기반 운영(백업·복구 리허설 포함)을 감당할 수 있을 때
설명: 이 판단 기준은 벤치마크 문서가 아니라 데이터베이스 섹션 개요의 관리형 vs 셀프호스팅 프레임워크에서 나온 것입니다. ClickHouse는 Apache-2.0 라이선스에 성숙한 커뮤니티 Operator(Altinity)가 있어 셀프호스팅이 현실적인 선택지가 됩니다 — 다만 Operator의 기능 범위와 백업·복구·업그레이드를 실제로 운영할 팀을 검증해야 합니다. 반대로 운영 인력이 부족하거나 관리형으로 충분하면 관리형이 정답입니다 — 직접 StatefulSet을 운영한다면 같은 백업·복구·업그레이드 책임을 직접 구현해야 합니다.