Skip to Content
BlogClickHouse 알아보기 — 로그를 SQL로 분석한다는 것

ClickHouse 알아보기 — 로그를 SQL로 분석한다는 것

#ClickHouse#MergeTree

로그가 쌓이면 처음에는 에러 메시지를 검색한다.

조금 지나면 질문이 달라진다.

최근 한 시간 동안 어떤 서비스에서 오류가 늘었는지, 배포 이후 응답 시간이 얼마나 바뀌었는지, 특정 고객의 요청에서만 문제가 생기는지 알고 싶어진다.

이때 필요한 건 수많은 이벤트를 조건에 맞게 읽고 집계하는 일이다.

ClickHouse는 이런 분석을 위한 컬럼 지향 데이터베이스다.

실시간으로 들어오는 데이터를 SQL로 분석하는 데 초점을 맞추고 있으며, 관측성 외에도 제품 사용 분석이나 실시간 대시보드에 쓰인다. ClickHouse 소개 

왜 컬럼으로 저장할까

로그 한 건에 시간, 서비스 이름, 상태 코드, 응답 시간, 본문이 있다고 해보자.

서비스별 평균 응답 시간을 구할 때 긴 로그 본문까지 읽을 필요는 없다.

시간서비스상태 코드응답 시간본문
10:00:01checkout20042 ms주문 처리 완료…
10:00:02checkout500310 ms외부 결제 요청 실패…
10:00:03catalog20018 ms상품 목록 조회…

컬럼 저장은 같은 컬럼의 값들을 모아서 저장한다.

필요한 컬럼을 골라 읽을 수 있고, 같은 종류의 값이 이어져 압축에도 유리하다.

ClickHouse는 여기에 여러 값을 묶어 처리하는 실행 방식과 병렬 처리를 더한다. 컬럼 지향 저장과 쿼리 처리 

물론 컬럼 저장이라는 이유만으로 모든 쿼리가 빨라지는 건 아니다.

얼마나 많은 데이터를 건너뛸 수 있는지, 어떤 컬럼을 읽는지, 동시에 몇 개의 쿼리가 도는지가 함께 영향을 준다.

로그를 SQL로 본다면

앞의 로그가 request_events라는 테이블에 있다고 가정해보자.

아래는 개념 설명용 스키마이며, HyperDX가 만드는 테이블과는 별개다.

CREATE TABLE request_events ( timestamp DateTime, service LowCardinality(String), status UInt16, duration_ms UInt32, body String ) ENGINE = MergeTree ORDER BY (service, timestamp);

ORDER BY는 데이터가 저장될 때의 정렬 기준이다.

이 예제는 특정 서비스의 일정 시간 구간을 자주 조회한다는 가정으로 service를 앞에 뒀다.

SELECT toStartOfMinute(timestamp) AS minute, count() AS requests, countIf(status >= 500) AS errors, avg(duration_ms) AS avg_duration_ms FROM request_events WHERE service = 'checkout' AND timestamp >= now() - INTERVAL 1 HOUR GROUP BY minute ORDER BY minute;

결과의 한 행은 1분 동안의 요청 수, 오류 수, 평균 응답 시간이다.

본문을 읽지 않고도 오류 증가와 지연을 함께 볼 수 있다.

반대로 모든 서비스를 시간만으로 검색하는 쿼리가 대부분이라면, 이 정렬 키가 가장 좋은 선택이라고 단정할 수 없다.

ClickHouse의 기본 인덱스는 모든 행의 위치를 담는 대신 데이터 구간을 건너뛰도록 돕는 희소 인덱스다.

자주 쓰는 필터와 정렬 키가 잘 맞을수록 읽을 범위를 줄이기 쉬워진다. MergeTree의 정렬 키와 인덱스 

MergeTree는 데이터를 어떻게 쌓나

앞에서 지정한 MergeTree는 ClickHouse에서 널리 쓰이는 테이블 엔진 계열의 기반이다.

데이터를 넣으면 정렬된 part가 만들어지고, 백그라운드 작업이 작은 part들을 더 큰 part로 합친다.

이 병합 작업을 merge라고 부른다. MergeTree 저장 구조 

그래서 조회만 빠르면 끝나는 데이터베이스가 아니다.

지속적으로 들어오는 데이터를 쓰면서 기존 part를 읽고 다시 쓰는 작업도 해야 한다.

아주 작은 INSERT를 계속 보내면 part가 빠르게 늘어날 수 있어, 수집 단계의 배치나 ClickHouse의 비동기 INSERT를 함께 고려한다. 데이터 삽입 권장 사항 

디스크 용량도 최종 데이터 크기에 딱 맞출 수는 없다.

병합 중에는 새 part를 만드는 공간이 필요하고, 복제본을 복구할 때도 추가 I/O가 발생한다.

압축률 하나만 보고 서버 크기를 정하기 어려운 이유다.

어디에 잘 맞을까

ClickHouse의 장점이 잘 드러나는 건 이벤트를 계속 쌓고, 그중 많은 행을 읽어 패턴을 찾는 작업이다.

질문분석하는 데이터
배포 뒤 오류율이 늘었나로그·요청 이벤트
어떤 화면에서 사용자가 이탈하나제품 사용 이벤트
서비스별 지연이 어떻게 변했나트레이스·메트릭
시간대별 주문량은 얼마나 다른가분석용으로 적재한 주문 이벤트

한 주문의 상태를 트랜잭션 안에서 계속 바꾸는 업무라면, 애플리케이션의 트랜잭션 DB와 분석 저장소의 역할을 나눠 보는 편이 자연스럽다.

ClickHouse에도 데이터 변경 기능은 있지만, 주력은 대량 데이터의 분석이다. ClickHouse의 설계 목적 

그리고 ClickHouse를 설치했다고 로그 수집기나 장애 분석 화면이 함께 완성되지는 않는다.

어떤 데이터를 어떻게 넣을지, 어떤 화면에서 조사할지까지 이어져야 실제 관측성 도구가 된다.

그 연결을 제공하는 구성이 HyperDX와 ClickStack이다.

다음 글에서는 HyperDX가 ClickHouse 위에서 어떤 역할을 하는지 살펴본다.