Skip to content
hello tis
Go back

[26.10.01] ClickHouse로 적재 구조 단순화하기

기존 구조

로그 적재 서버마다 로그 적재 서비스가 로그 파일을 씁니다. 집계 서버의 스크립트 세 개가 이 로그를 하둡 클러스터에 적재하고 집계합니다.

집계 서버의 적재 스크립트가 로그 적재 서버 두 대의 로그 파일을 가져와 하둡 클러스터에 적재하고, 집계 스크립트가 집계 결과를 BI 서버의 bi DB에 쓰며, 용량정리 스크립트가 하둡 클러스터의 용량을 정리하는 흐름

하둡 클러스터는 하둡 메인과 하둡 서버 두 대로 구성됩니다. bi는 bi DB에 저장된 집계 결과를 조회합니다.

바꾸려는 이유

하둡은 통계를 집계하기 전에 로그를 잠시 두는 저장소인데, 운영하면서 아래 문제를 확인했습니다.

하둡을 유지하려고 파일을 직접 지우고, OOM으로 실패한 크론 작업을 직접 다시 실행하고, 집계마다 스크립트를 추가했습니다. 이런 수작업이 계속 운영 부담으로 이어졌습니다.

그래서 Vector로 ClickHouse에 바로 적재하고, 보관 기간은 ClickHouse의 TTL로 관리하는 구조로 바꾸려고 합니다.

바꿀 구조

로그 적재 서버마다 Vector를 두고, Vector가 로그 파일을 읽어 ClickHouse에 적재합니다. bi는 ClickHouse를 직접 조회합니다.

로그 적재 서버마다 Vector가 로그 파일을 읽어 ClickHouse에 적재하고, BI 서버의 bi가 ClickHouse를 조회하는 흐름

서버별로 달라지는 점

로그 적재 서버

AS-ISTO-BE
로그 적재 서비스가 로그 파일을 쓰고, 집계 서버의 적재 스크립트가 로그 파일을 가져가는 구조같은 서버의 Vector가 로그 파일을 읽어 ClickHouse로 보내는 구조

하둡 클러스터와 ClickHouse

AS-ISTO-BE
집계 서버의 스크립트 세 개가 하둡 메인에 접근하는 하둡 클러스터 구조Vector가 원본 로그 테이블에 적재하고 Materialized View가 일별 집계 테이블을 만들며 bi가 두 테이블을 조회하는 구조

BI 서버

AS-ISTO-BE
집계 스크립트가 bi DB에 쓰고 bi가 bi DB를 조회하는 구조bi DB가 없어지고 bi가 ClickHouse를 직접 조회하는 구조

참고한 사례: Uber의 로그 분석 플랫폼

곧바로 바꾸면 좋지만, 게으른 엔지니어가 되자는 목표에 맞게 바꿀 구조가 최종적으로 어떤 모습이 될지 먼저 그려서 데이터 증가에 대한 확장성을 고려해야 했습니다. Uber의 아키텍처를 기준으로 어떻게 확장할지 정리했습니다.

Uber의 Fast and reliable schema-agnostic log analytics platform(2021년 2월)은 ELK로 운영하던 로그 플랫폼을 ClickHouse로 옮긴 사례입니다. 기존 저장소는 하둡이 아니라 Elasticsearch입니다. 이 구조에서는 ClickHouse 노드를 추가해 클러스터를 선형으로 확장합니다.

Kafka Clusters의 로그를 Log Ingester가 읽고 Log Batcher가 묶어 ClickHouse Cluster에 쓰며, Log Admin이 ClickHouse Cluster를 관리하고, UI와 API의 요청을 Query Service가 ClickHouse Cluster에 조회하는 구조

Uber 구조를 기준으로 확장하기

지금은 Uber처럼 역할마다 서버를 두지 않습니다. 한 서버에 여러 역할이 함께 있고, 역할은 시스템 내부 디렉토리와 코드로 구분합니다. 데이터가 늘면 이 구분을 따라 역할을 서버로 나눠 다음과 같이 확장합니다.

데이터가 늘 때의 확장 구조. 로그 적재 서버의 Vector는 로그 파일을 읽어 배치 서버로 보내고, 배치 서버의 Vector가 로그를 모아 샤드 두 개와 샤드별 복제본 두 개로 구성된 ClickHouse에 쓴다. 테이블 정의와 TTL은 Log Admin 역할로 관리하고, bi는 조회 계층을 거쳐 ClickHouse를 조회한다

Uber가 ClickHouse로 옮긴 뒤 확인한 결과

성능 테스트

바꿀 구조가 지금 로그 양을 처리할 수 있는지 로컬에서 확인했습니다. 적재는 튜닝하지 않고 결과만 참고했고, 조회는 기준을 넘겨 튜닝했습니다.

테스트 조건

k6가 nginx로 요청을 보내고, nginx가 요청 본문을 로그 파일에 쓰면 Vector가 파일을 읽어 ClickHouse에 적재하며 대시보드 조회를 함께 실행하는 테스트 구성과, 워밍업 5분, 증가 10분, 피크 20분, 회복 10분의 진행 순서

적재 성능

적재는 기준 7개를 모두 통과해 튜닝하지 않았습니다.

1차 테스트의 단계별 초당 처리량. nginx 수신, Vector가 로그 파일에서 읽은 건수, ClickHouse 저장 건수가 구간 내내 같은 선을 따라 움직이고, 피크에서 초당 약 2,500건까지 오른다

조회 성능

문제: 30일 고유 기기 수 조회가 기준 2초를 넘었다

대시보드 조회 3종 중 30일 고유 기기 수 조회만 기준 p95 2초를 넘었습니다.

부하가 없을 때도 평균 1.95초가 걸렸습니다. 적재 부하보다 조회할 때마다 원본 6.09억 건(13.75GB)을 읽는 것이 원인이었습니다.

적용: 일별 고유 기기 수를 미리 집계했다

AS-ISTO-BE
대시보드가 원본 events 6.09억 건을 uniq(uuid)로 매번 집계해 13.75GB를 읽는 구조Materialized View가 INSERT마다 daily_app_stats에 요약을 쌓고, 대시보드가 요약 780행을 uniqMerge(devices)로 읽어 70KB를 읽는 구조

원리: 숫자 대신 집계 상태를 저장한다

INSERT 묶음마다 날짜와 앱별 고유 기기 집계 상태를 만들고, 병합 때 같은 날짜와 앱의 상태를 합쳐 기기 a, b, c, d 네 대로 센다. 숫자로 저장했다면 3대와 2대를 더해 5대로 잘못 계산된다

주의점: Materialized View는 원본 INSERT와 함께 실행된다

수집 계정에 권한이 없으면 Materialized View가 실패해 INSERT가 실패 응답을 받지만 원본에는 이미 기록돼 재시도마다 중복이 쌓이고, 백필은 Materialized View 생성 이전 데이터만 하는 그림

결과

피크 중 조회 p95. 30일 고유 기기 수는 AS-IS 2.49초에서 TO-BE 0.17초, 대시보드 조회 3종 전체는 2.33초에서 0.97초로 줄었다

항목AS-ISTO-BE
30일 고유 기기 수 단독 조회 (부하 없음)2,144ms, 13.75GB 읽음152ms, 70KB 읽음
30일 고유 기기 수 p95 (피크)2.49초0.17초
대시보드 조회 3종 p95 (피크)2.33초0.97초
2초 초과 조회 (피크)41/199회0/199회
ClickHouse CPU 피크 평균 / 최대1.27 / 1.86코어0.70 / 1.24코어
합격 기준7/88/8

30일 고유 기기 수 조회가 읽는 데이터는 13.75GB에서 70KB로 줄었고, 피크 중에도 0.17초 안에 끝났습니다. 대시보드 조회 3종 모두 기준 2초 안에 들어와 합격 기준 8개를 모두 통과했습니다. 같은 부하에서 ClickHouse CPU 피크 평균도 1.27코어에서 0.70코어로 줄었습니다.


Share this post:

Previous Post
[26.10.02] ClickHouse Merge 증가 원인 분석하기
Next Post
[26.09.30] 로그 수집 방식을 최상·평균·최악의 경우로 나눠 비교하기