Powrót do strony głównej

Konfiguracja ClickHouse: prod ustawienia config.xml i users.xml

Praktyczny przewodnik konfiguracji ClickHouse dla środowiska produkcyjnego. Omówione są główne sekcje config.xml: logger z rotacją według rozmiaru (10 plików po 1 GB), ścieżki danych i swap, parametry MergeTree (min_bytes_for_wide_part, parts_to_throw_insert=300). Pokazana jest struktura users.xml dla trzech typów użytkowników: analitycy (readonly=1, limity pamięci i czasu), aplikacja (ograniczone zasoby), administrator (dostęp lokalny). Ustawienia profili: max_memory_usage, max_execution_time, max_rows_to_read. Limity na liczbę zapytań i przeczytanych wierszy. Kompresja LZ4 (szybkość) vs ZSTD (oszczędność miejsca). TLS/SSL dla bezpiecznego dostępu. Zasada konfiguracji przez config.d/ w celu zachowania ustawień przy aktualizacji. Minimalna lista kontrolna bezpieczeństwa: zmiana hasła default, zamknięcie portów przez UFW/iptables, ograniczenie sieci w users.xml, włączenie query_log.

ClickHouse: jak skonfigurować prod i nie stracić danych
Advertisement 728x90

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:

Google AdInline article slot
<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:

Google AdInline article slot
<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.

Google AdInline article slot

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: Następny: ReplacingMergeTree: Jak pokonać duplikaty w ClickHouse bez bólu

— Editorial Team

Advertisement 728x90

Czytaj dalej