Konfiguracja ClickHouse: jak skonfigurowałem prod i nie postrzeliłem się w stopę
Historia jednej literówki: 300 GB logów i padnięty serwer
ClickHouse domyślnie zapisuje logi do /var/log/clickhouse-server/ i nigdy ich nie rotuje. Dwa tygodnie po uruchomieniu odkryliśmy, że plik logu urósł do 300 GB i zajął całą partycję root. Serwer padł. Analitycy nie mogli zrobić SELECT, prod legł.
Dokumentacja ClickHouse jest ogromna, ale w produkcji naprawdę trzeba zmienić nie więcej niż 20 parametrów. Poniżej mój checklist z 5 lat eksploatacji klastrów od 1 węzła do 12.
1. config.xml: szkielet konfiguracji produkcyjnej
Główny konfig leży w /etc/clickhouse-server/config.xml. Oto sekcje, które ruszam w każdym projekcie:
<clickhouse>
<!-- Logowanie – dodaj rotację, żeby nie powtórzyć mojego błędu -->
<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>
<!-- To ratuje dyski. 10 plików po 1 GB – rotacja według rozmiaru -->
</logger>
<!-- Porty – standardowe, ale na prodzie zmieniam -->
<tcp_port>9000</tcp_port> <!-- Natywny klient -->
<http_port>8123</http_port> <!-- HTTP API -->
<interserver_http_port>9009</interserver_http_port> <!-- Replikacja -->
<!-- Słuchanie interfejsów – na prodzie NIE USTAWIAJCIE 0.0.0.0 bez firewalla -->
<listen_host>0.0.0.0</listen_host> <!-- Wszystkie interfejsy – ostrożnie -->
<!-- <listen_host>::</listen_host> IPv6 -->
Dlaczego nie radzę bezmyślnie 0.0.0.0: na prodzie z publicznym IP Twój ClickHouse stanie się celem skanowania portów. Lepiej użyj VPN lub zapór sieciowych.
2. Ścieżki danych: gdzie ClickHouse kładzie wszystko
<path>/var/lib/clickhouse/</path> <!-- Główne dane -->
<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>
Na czym się sparzyłem: /tmp w systemie był zamontowany w pamięci (tmpfs) tylko na 2 GB. ClickHouse próbował zapisać tam pliki tymczasowe dla dużych GROUP BY i padał z błędem. Przeniosłem tmp_path na dysk z 50 GB:
<tmp_path>/data/clickhouse_tmp/</tmp_path>
3. Ustawienia MergeTree: zapobieganie katastrofom
Te parametry ustawiam na wszystkich serwerach produkcyjnych:
<merge_tree>
<!-- Część nie jest scalana, dopóki nie uzbiera 10 GB – zmniejsza obciążenie tła -->
<min_bytes_for_wide_part>10000000000</min_bytes_for_wide_part>
<!-- Maksymalny rozmiar części do scalenia (100 GB) -->
<max_bytes_to_merge_at_max_space_in_pool>107374182400</max_bytes_to_merge_at_max_space_in_pool>
<!-- Jeśli części > 300, nowe INSERT będą odrzucane -->
<parts_to_throw_insert>300</parts_to_throw_insert>
<!-- Ostrzeżenie przy 200 częściach -->
<parts_to_delay_insert>200</parts_to_delay_insert>
<!-- Maksymalna liczba części w partycji -->
<max_parts_in_total>10000</max_parts_in_total>
</merge_tree>
Dlaczego parts_to_throw_insert = 300: jeśli nagromadziło się 300+ części, SELECT zwalnia, a INSERT tylko pogarszają sytuację. Lepiej odrzucić wstawkę i ogarnąć.
4. users.xml: użytkownicy, profile, limity
Plik /etc/clickhouse-server/users.xml to kontrola dostępu. Tworzę trzech użytkowników:
<clickhouse>
<!-- 1. Użytkownik dla analityków (tylko do odczytu) -->
<analyst>
<password>analyst_secure_password</password>
<networks>
<ip>10.0.0.0/8</ip> <!-- Tylko sieć wewnętrzna -->
</networks>
<profile>readonly_profile</profile>
<quota>analyst_quota</quota>
</analyst>
<!-- 2. Aplikacja (ograniczone zasoby) -->
<app_user>
<password>${CLICKHOUSE_APP_PASSWORD}</password> <!-- Ze zmiennej środowiskowej -->
<networks>
<ip>::/0</ip> <!-- Tu ostrożnie, lepiej konkretne podsieci -->
</networks>
<profile>app_profile</profile>
</app_user>
<!-- 3. Administrator (wszystko wolno) -->
<admin>
<password>admin_strong_password</password>
<networks>
<host>localhost</host>
<host>10.0.0.50</host> <!-- Tylko bastion-host -->
</networks>
<profile>admin_profile</profile>
</admin>
</clickhouse>
Ważny niuans: hasło domyślnego użytkownika default jest puste. To pierwsza rzecz, którą zmieniam po instalacji.
5. Profile ustawień: ochrona przed szalonymi zapytaniami
Profile to zestawy ograniczeń, które ratują klaster przed SELECT * FROM huge_table CROSS JOIN.
<profiles>
<!-- Analitycy: mogą robić ciężkie zapytania, ale z limitami -->
<readonly_profile>
<readonly>1</readonly> <!-- Tylko SELECT -->
<max_memory_usage>10000000000</max_memory_usage> <!-- 10 GB -->
<max_execution_time>300</max_execution_time> <!-- 5 minut -->
<max_rows_to_read>50000000000</max_rows_to_read> <!-- 50 mld wierszy -->
<max_bytes_to_read>107374182400</max_bytes_to_read> <!-- 100 GB -->
<prefer_global_in_and_join>1</prefer_global_in_and_join>
</readonly_profile>
<!-- Aplikacja: szybkie zapytania, małe limity -->
<app_profile>
<readonly>0</readonly>
<max_memory_usage>1000000000</max_memory_usage> <!-- 1 GB -->
<max_execution_time>10</max_execution_time> <!-- 10 sekund -->
<max_rows_to_read>100000000</max_rows_to_read> <!-- 100 mln -->
<timeout_before_checking_execution_speed>0</timeout_before_checking_execution_speed>
</app_profile>
<!-- Admin: prawie bez ograniczeń (ale ostrożnie) -->
<admin_profile>
<readonly>0</readonly>
<max_memory_usage>0</max_memory_usage> <!-- bez limitu -->
<max_execution_time>0</max_execution_time>
</admin_profile>
</profiles>
Limity – żeby jeden analityk nie zabił wszystkich:
<quotas>
<analyst_quota>
<interval>
<duration>3600</duration> <!-- na godzinę -->
<queries>100</queries> <!-- nie więcej niż 100 zapytań -->
<errors>0</errors> <!-- bez błędów -->
<result_rows>100000000</result_rows> <!-- 100 mln wierszy wyniku -->
<read_rows>10000000000</read_rows> <!-- 10 mld odczytanych -->
</interval>
</analyst_quota>
</quotas>
6. Domyślna kompresja
ClickHouse kompresuje dane LZ4 (szybko) lub ZSTD (mocniej). Wybieram w zależności od typu danych:
<compression>
<!-- LZ4 dla świeżych danych (szybkość) -->
<case>
<last_level>1</last_level> <!-- Poziom kompresji -->
<method>LZ4</method>
</case>
<!-- ZSTD dla partycji starszych niż 30 dni (oszczędność miejsca) -->
<case>
<min_part_size>10737418240</min_part_size> <!-- 10 GB -->
<method>ZSTD</method>
<level>3</level>
</case>
</compression>
Mój wybór na prodzie: LZ4 dla wszystkich danych. ZSTD oszczędza 20-30% miejsca, ale na zapytaniach traci się do 10% szybkości.
7. TLS/SSL – jeśli nie jesteś w izolowanej sieci
<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>
Na czym się sparzyłem: samopodpisany certyfikat bez weryfikacji jest bezpieczny tylko w zaufanej sieci wewnętrznej. Do dostępu zewnętrznego używaj Let's Encrypt lub płatnego certyfikatu.
8. config.d/ – nadpisywanie bez męczarni
Nigdy nie edytuj config.xml bezpośrednio. Wszystkie zmiany wkładaj do /etc/clickhouse-server/config.d/.
Plik config.d/memory.xml:
<clickhouse>
<max_server_memory_usage>0.75</max_server_memory_usage> <!-- 75% całego RAM -->
<max_concurrent_queries>100</max_concurrent_queries>
</clickhouse>
Plik config.d/networks.xml:
<clickhouse>
<listen_host>0.0.0.0</listen_host>
<max_connections>4096</max_connections>
</clickhouse>
Zalety: przy aktualizacji ClickHouse Twój config.xml nie zostanie nadpisany, a nadpisy pozostaną. Tego nauczyła mnie utrata konfigu po aktualizacji z 22.x na 23.x.
9. Security checklist dla platformy bettingowej
Zanim otworzę dostęp do ClickHouse ze świata zewnętrznego, sprawdzam:
✅ Zmiana hasła domyślnego użytkownika default
clickhouse-client --password
ALTER USER default IDENTIFIED BY 'new_strong_password';
✅ Usunięcie lub ograniczenie domyślnego użytkownika default
<!-- W users.xml zakomentować sekcję default -->
<!-- <default>
<password></password>
</default> -->
✅ Zamknięcie portów przed dostępem zewnętrznym (UFW)
sudo ufw default deny incoming
sudo ufw allow from 10.0.0.0/8 to any port 9000 proto tcp # tylko sieć wewnętrzna
sudo ufw allow from 10.0.0.0/8 to any port 8123 proto tcp
sudo ufw allow ssh
✅ Włączenie zapory sieciowej na poziomie hosta
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
✅ Ustawienie max_memory_usage, żeby jedno zapytanie nie zabiło serwera
<max_memory_usage>10000000000</max_memory_usage> <!-- 10 GB -->
✅ Wyłączenie eksperymentalnych funkcji (jeśli nie są potrzebne)
<allow_experimental_geo_types>0</allow_experimental_geo_types>
<allow_experimental_window_functions>1</allow_experimental_window_functions> <!-- 23.8+ -->
✅ Włączenie query_log i slow_log do monitorowania
<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>
✅ Ograniczenie dostępu po IP (biała lista)
<analyst>
<networks>
<ip>10.0.0.100</ip> <!-- Tylko konkretny IP analityka -->
<ip>10.0.0.101</ip>
<ip>192.168.1.0/24</ip>
</networks>
</analyst>
Co dalej
Teraz Twój ClickHouse jest skonfigurowany do boju. Następny artykuł – o monitorowaniu i backupach w produkcji.
← Poprzedni: Funkcje agregujące ClickHouse: jak przestałem bać się uniqHLL12 i quantileTDigest → Następny: ReplacingMergeTree: Jak pokonać duplikaty w ClickHouse bez bólu
— Editorial Team
Brak komentarzy.