ClickHouse 설정: 운영 환경을 구성하면서 실수하지 않는 방법
오타 하나가 만든 대참사: 300GB 로그와 다운된 서버
기본적으로 ClickHouse는 로그를 /var/log/clickhouse-server/에 기록하며 로테이션을 하지 않습니다. 출시 2주 후, 로그 파일이 300GB로 불어나 루트 파티션을 가득 채웠습니다. 서버가 다운되었고, 분석가들은 SELECT를 실행할 수 없었으며, 운영이 중단되었습니다.
ClickHouse 문서는 방대하지만, 운영 환경에서 실제로 변경해야 할 파라미터는 약 20개에 불과합니다. 아래는 1노드에서 12노드까지 클러스터를 운영하며 5년간 쌓은 체크리스트입니다.
1. config.xml: 운영 설정의 뼈대
주 설정 파일은 /etc/clickhouse-server/config.xml에 있습니다. 모든 프로젝트에서 건드리는 섹션은 다음과 같습니다.
<clickhouse>
<!-- 로깅 — 로테이션을 추가하여 실수 반복 방지 -->
<logger>
<level>information</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>10</count>
<!-- 디스크를 절약합니다. 각각 1GB 파일 10개 — 크기 기반 로테이션 -->
</logger>
<!-- 포트 — 표준이지만 운영 환경에서는 변경 -->
<tcp_port>9000</tcp_port> <!-- 네이티브 클라이언트 -->
<http_port>8123</http_port> <!-- HTTP API -->
<interserver_http_port>9009</interserver_http_port> <!-- 복제 -->
<!-- 수신 인터페이스 — 운영 환경에서는 방화벽 없이 0.0.0.0 설정 금지 -->
<listen_host>0.0.0.0</listen_host> <!-- 모든 인터페이스 — 주의 -->
<!-- <listen_host>::</listen_host> IPv6 -->
0.0.0.0을 무분별하게 사용하지 말아야 하는 이유: 공인 IP를 가진 운영 환경에서 ClickHouse는 포트 스캐닝의 대상이 됩니다. VPN이나 방화벽을 사용하는 것이 좋습니다.
2. 데이터 경로: ClickHouse가 모든 것을 저장하는 곳
<path>/var/lib/clickhouse/</path> <!-- 주요 데이터 -->
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
<format_schema_path>/var/lib/clickhouse/format_schemas/</format_schema_path>
내가 당한 문제: 시스템의 /tmp가 메모리(tmpfs)에 마운트되어 용량이 2GB에 불과했습니다. ClickHouse가 대규모 GROUP BY 쿼리를 위해 임시 파일을 쓰려다 오류와 함께 다운되었습니다. tmp_path를 50GB 디스크로 옮겼습니다:
<tmp_path>/data/clickhouse_tmp/</tmp_path>
3. MergeTree 설정: 재앙 방지
모든 운영 서버에 다음 파라미터를 설정합니다:
<merge_tree>
<!-- 파트가 10GB 누적될 때까지 병합하지 않음 — 백그라운드 부하 감소 -->
<min_bytes_for_wide_part>10000000000</min_bytes_for_wide_part>
<!-- 병합할 최대 파트 크기 (100GB) -->
<max_bytes_to_merge_at_max_space_in_pool>107374182400</max_bytes_to_merge_at_max_space_in_pool>
<!-- 파트가 300개 초과 시 새 INSERT 거부 -->
<parts_to_throw_insert>300</parts_to_throw_insert>
<!-- 파트 200개에서 경고 -->
<parts_to_delay_insert>200</parts_to_delay_insert>
<!-- 파티션 내 최대 파트 수 -->
<max_parts_in_total>10000</max_parts_in_total>
</merge_tree>
parts_to_throw_insert = 300인 이유: 파트가 300개 이상이면 SELECT가 느려지고 INSERT는 상황을 악화시킵니다. INSERT를 거부하고 원인을 조사하는 것이 낫습니다.
4. users.xml: 사용자, 프로필, 할당량
/etc/clickhouse-server/users.xml 파일은 접근 제어입니다. 세 명의 사용자를 생성합니다:
<clickhouse>
<!-- 1. 분석가용 사용자 (읽기 전용) -->
<analyst>
<password>analyst_secure_password</password>
<networks>
<ip>10.0.0.0/8</ip> <!-- 내부 네트워크만 -->
</networks>
<profile>readonly_profile</profile>
<quota>analyst_quota</quota>
</analyst>
<!-- 2. 애플리케이션 (리소스 제한) -->
<app_user>
<password>${CLICKHOUSE_APP_PASSWORD}</password> <!-- 환경 변수에서 -->
<networks>
<ip>::/0</ip> <!-- 주의, 특정 서브넷 사용 권장 -->
</networks>
<profile>app_profile</profile>
</app_user>
<!-- 3. 관리자 (전체 접근) -->
<admin>
<password>admin_strong_password</password>
<networks>
<host>localhost</host>
<host>10.0.0.50</host> <!-- 배스천 호스트만 -->
</networks>
<profile>admin_profile</profile>
</admin>
</clickhouse>
중요한 세부사항: 기본 사용자의 비밀번호는 기본적으로 비어 있습니다. 설치 후 가장 먼저 변경하는 부분입니다.
5. 설정 프로필: 무분별한 쿼리로부터 보호
프로필은 SELECT * FROM huge_table CROSS JOIN 같은 쿼리로부터 클러스터를 보호하는 제약 조건 집합입니다.
<profiles>
<!-- 분석가: 무거운 쿼리 가능하지만 제한 있음 -->
<readonly_profile>
<readonly>1</readonly> <!-- SELECT만 -->
<max_memory_usage>10000000000</max_memory_usage> <!-- 10GB -->
<max_execution_time>300</max_execution_time> <!-- 5분 -->
<max_rows_to_read>50000000000</max_rows_to_read> <!-- 500억 행 -->
<max_bytes_to_read>107374182400</max_bytes_to_read> <!-- 100GB -->
<prefer_global_in_and_join>1</prefer_global_in_and_join>
</readonly_profile>
<!-- 애플리케이션: 빠른 쿼리, 작은 제한 -->
<app_profile>
<readonly>0</readonly>
<max_memory_usage>1000000000</max_memory_usage> <!-- 1GB -->
<max_execution_time>10</max_execution_time> <!-- 10초 -->
<max_rows_to_read>100000000</max_rows_to_read> <!-- 1억 -->
<timeout_before_checking_execution_speed>0</timeout_before_checking_execution_speed>
</app_profile>
<!-- 관리자: 거의 제한 없음 (주의) -->
<admin_profile>
<readonly>0</readonly>
<max_memory_usage>0</max_memory_usage> <!-- 제한 없음 -->
<max_execution_time>0</max_execution_time>
</admin_profile>
</profiles>
할당량 — 한 분석가가 모두를 죽이지 않도록:
<quotas>
<analyst_quota>
<interval>
<duration>3600</duration> <!-- 시간당 -->
<queries>100</queries> <!-- 최대 100개 쿼리 -->
<errors>0</errors> <!-- 오류 없음 -->
<result_rows>100000000</result_rows> <!-- 1억 결과 행 -->
<read_rows>10000000000</read_rows> <!-- 100억 읽기 -->
</interval>
</analyst_quota>
</quotas>
6. 기본 압축 설정
ClickHouse는 LZ4(빠름) 또는 ZSTD(강력)로 데이터를 압축합니다. 데이터 유형에 따라 선택합니다:
<compression>
<!-- 신규 데이터는 LZ4 (속도) -->
<case>
<last_level>1</last_level> <!-- 압축 레벨 -->
<method>LZ4</method>
</case>
<!-- 30일 이상 된 파티션은 ZSTD (공간 절약) -->
<case>
<min_part_size>10737418240</min_part_size> <!-- 10GB -->
<method>ZSTD</method>
<level>3</level>
</case>
</compression>
운영 환경에서의 선택: 모든 데이터에 LZ4를 사용합니다. ZSTD는 20-30% 공간을 절약하지만 쿼리 속도가 최대 10% 느려집니다.
7. TLS/SSL — 격리된 네트워크가 아니라면
<https_port>8443</https_port>
<tcp_port_secure>9440</tcp_port_secure>
<openSSL>
<server>
<certificateFile>/etc/clickhouse-server/ssl/server.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-server/ssl/server.key</privateKeyFile>
<verificationMode>none</verificationMode>
<caConfig>/etc/clickhouse-server/ssl/CA.pem</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3,tlsv1,tlsv1_1</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
</openSSL>
내가 당한 문제: 검증 없는 자체 서명 인증서는 신뢰할 수 있는 네트워크 내에서만 안전합니다. 외부 접근에는 Let's Encrypt 또는 유료 인증서를 사용하세요.
8. config.d/ — 고통 없는 오버라이드
config.xml을 직접 편집하지 마세요. 모든 변경 사항은 /etc/clickhouse-server/config.d/에 넣으세요.
config.d/memory.xml 파일:
<clickhouse>
<max_server_memory_usage>0.75</max_server_memory_usage> <!-- 전체 RAM의 75% -->
<max_concurrent_queries>100</max_concurrent_queries>
</clickhouse>
config.d/networks.xml 파일:
<clickhouse>
<listen_host>0.0.0.0</listen_host>
<max_connections>4096</max_connections>
</clickhouse>
장점: ClickHouse 업데이트 시 config.xml이 덮어쓰이지 않고 오버라이드가 유지됩니다. 22.x에서 23.x로 업그레이드할 때 설정을 잃어버린 경험으로 배웠습니다.
9. 베팅 플랫폼을 위한 보안 체크리스트
ClickHouse를 외부에 열기 전에 다음을 확인합니다:
✅ 기본 사용자 비밀번호 변경
clickhouse-client --password
ALTER USER default IDENTIFIED BY 'new_strong_password';
✅ 기본 사용자 제거 또는 제한
<!-- users.xml에서 default 섹션을 주석 처리 -->
<!-- <default>
<password></password>
</default> -->
✅ 외부 접근 포트 차단 (UFW)
sudo ufw default deny incoming
sudo ufw allow from 10.0.0.0/8 to any port 9000 proto tcp # 내부 네트워크만
sudo ufw allow from 10.0.0.0/8 to any port 8123 proto tcp
sudo ufw allow ssh
✅ 호스트 수준 방화벽 활성화
sudo iptables -A INPUT -p tcp --dport 9000 -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9000 -j DROP
✅ 하나의 쿼리가 서버를 죽이지 않도록 max_memory_usage 설정
<max_memory_usage>10000000000</max_memory_usage> <!-- 10GB -->
✅ 실험적 기능 비활성화 (필요하지 않은 경우)
<allow_experimental_geo_types>0</allow_experimental_geo_types>
<allow_experimental_window_functions>1</allow_experimental_window_functions> <!-- 23.8+ -->
✅ 모니터링을 위한 query_log 및 slow_log 활성화
<query_log>
<database>system</database>
<table>query_log</table>
<partition_by>toYYYYMM(event_date)</partition_by>
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
</query_log>
<query_thread_log>
<database>system</database>
<table>query_thread_log</table>
</query_thread_log>
✅ IP로 접근 제한 (화이트리스트)
<analyst>
<networks>
<ip>10.0.0.100</ip> <!-- 특정 분석가 IP만 -->
<ip>10.0.0.101</ip>
<ip>192.168.1.0/24</ip>
</networks>
</analyst>
다음은?
이제 ClickHouse가 전투 준비를 마쳤습니다. 다음 글은 운영 환경에서의 모니터링과 백업에 관한 것입니다.
← 이전 글: ClickHouse 집계 함수: uniqHLL12와 quantileTDigest에 대한 두려움을 극복한 방법 → 다음 글: ReplacingMergeTree: ClickHouse에서 중복을 고통 없이 제거하는 방법
— Editorial Team
아직 댓글이 없습니다.