Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Эксплуатация ClickHouse
production

Эксплуатация ClickHouse

SLO, встроенные BACKUP/RESTORE, проверка RPO/RTO, безопасные обновления, масштабирование и разбор инцидентов

Эксплуатация ClickHouse

SLO, резервное копирование, безопасные обновления и восстановление после сбоев

#Результат урока

Вы подготовите эксплуатационный контракт: измеримые SLO, модель отказов, процедуру обновления и проверенный сценарий BACKUP/RESTORE. Универсального набора настроек нет: значения зависят от нагрузки, бюджета и допустимого риска.

#Конфигурация рабочего кластера

#Рекомендуемая архитектура

Пример отказоустойчивого кластера (6 серверов ClickHouse):

Шард 1 (2 реплики):     Шард 2 (2 реплики):     Шард 3 (2 реплики):
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ clickhouse-01-1 │     │ clickhouse-02-1 │     │ clickhouse-03-1 │
│ clickhouse-01-2 │     │ clickhouse-02-2 │     │ clickhouse-03-2 │
└─────────────────┘     └─────────────────┘     └─────────────────┘

Keeper/ZooKeeper (3 узла):
┌─────────┐ ┌─────────┐ ┌─────────┐
│ keeper1 │ │ keeper2 │ │ keeper3 │
└─────────┘ └─────────┘ └─────────┘

Это не минимальная конфигурация для любого проекта. Число шардов определяется объёмом и пропускной способностью, а число реплик — моделью отказа и требованиями доступности.

Принципы:

  • две реплики позволяют пережить потерю одного сервера, если оставшаяся реплика доступна и согласованность настроена под этот сценарий;
  • Реплики в разных стойках/DC
  • Отдельные узлы для Keeper/ZooKeeper

#Конфигурация сервера

<!-- config.xml --> <clickhouse> <!-- Порты --> <http_port>8123</http_port> <tcp_port>9000</tcp_port> <https_port>8443</https_port> <tcp_port_secure>9440</tcp_port_secure> <!-- Пути --> <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> <!-- Логирование --> <logger> <level>information</level> <log>/var/log/clickhouse-server/clickhouse-server.log</log> <errorlog>/var/lib/clickhouse-server/clickhouse-server.err.log</errorlog> <size>100M</size> <count>3</count> </logger> <!-- DNS кэширование --> <dns_cache_disabled>true</dns_cache_disabled> <!-- Максимальные настройки --> <max_concurrent_queries>100</max_concurrent_queries> <max_connections>4096</max_connections> <!-- Keep-alive --> <keep_alive_timeout>3</keep_alive_timeout> <!-- Сжатие --> <compression> <case> <min_part_size>10000000000</min_part_size> <min_part_size_ratio>0.01</min_part_size_ratio> <method>zstd</method> </case> </compression> <!-- Грациозная остановка --> <max_thread_pool_size>16000</max_thread_pool_size> <shutdown_wait_unfinished>5</shutdown_wait_unfinished> </clickhouse>

#Настройки пользователей

<!-- users.xml --> <clickhouse> <profiles> <!-- Default профиль --> <default> <max_memory_usage>10000000000</max_memory_usage> <max_execution_time>60</max_execution_time> <max_rows_to_read>100000000</max_rows_to_read> <max_bytes_to_read>100000000000</max_bytes_to_read> <max_result_rows>1000000</max_result_rows> <max_result_bytes>1000000000</max_result_bytes> <readonly>0</readonly> <!-- Оптимизации --> <optimize_read_in_order>1</optimize_read_in_order> <optimize_aggregation_in_order>1</optimize_aggregation_in_order> <!-- JOIN --> <join_algorithm>auto</join_algorithm> <max_bytes_in_join>10000000000</max_bytes_in_join> <!-- Агрегация --> <max_bytes_before_external_group_by>20000000000</max_bytes_before_external_group_by> <!-- Сортировка --> <max_bytes_before_external_sort>20000000000</max_bytes_before_external_sort> <!-- Сетевые настройки --> <max_streams_to_max_threads_ratio>4</max_streams_to_max_threads_ratio> </default> <!-- Readonly профиль --> <readonly> <readonly>1</readonly> <max_memory_usage>20000000000</max_memory_usage> <max_execution_time>300</max_execution_time> </readonly> <!-- Heavy queries профиль --> <heavy_queries> <max_memory_usage>50000000000</max_memory_usage> <max_execution_time>600</max_execution_time> <max_bytes_before_external_group_by>50000000000</max_bytes_before_external_group_by> </heavy_queries> </profiles> <quotas> <default> <interval> <duration>3600</duration> <queries>1000</queries> <errors>100</errors> <result_rows>10000000</result_rows> <read_rows>1000000000</read_rows> <execution_time>36000</execution_time> </interval> </default> </quotas> <users> <default> <password></password> <networks> <ip>::1</ip> <ip>127.0.0.1</ip> </networks> <profile>default</profile> <quota>default</quota> <access_management>1</access_management> </default> <!-- Production приложение --> <app_user> <!-- Пароль передаётся через поддерживаемое секрет-хранилище, не хранится в репозитории с конфигурацией. --> <password_sha256_hex>REDACTED_HASH</password_sha256_hex> <networks> <ip>10.0.0.0/8</ip> <ip>192.168.0.0/16</ip> </networks> <profile>default</profile> <quota>default</quota> <default_role>app_role</default_role> </app_user> </users> </clickhouse>

#Резервное копирование и восстановление

Репликация защищает от части аппаратных отказов, но не от ошибочного DROP, неверной мутации или повреждённых данных, которые разойдутся по репликам. Основной путь в актуальном ClickHouse — встроенные команды BACKUP и RESTORE.

Сначала администратор настраивает диск резервных копий или доступ к S3. Учётные данные лучше хранить в named collection: так они не оказываются в тексте запроса и system.query_log.

-- Полная копия базы в заранее настроенный диск BACKUP DATABASE analytics TO Disk('backups', 'analytics-full.zip') SETTINGS id = 'analytics-full-20260810'; -- Асинхронная копия для долгой операции BACKUP DATABASE analytics TO Disk('backups', 'analytics-async.zip') ASYNC SETTINGS id = 'analytics-async-20260810';

Статус операции проверяется по ID:

SELECT id, name, status, start_time, end_time, error FROM system.backups WHERE id IN ('analytics-full-20260810', 'analytics-async-20260810');

#Инкрементальная копия

BACKUP DATABASE analytics TO Disk('backups', 'analytics-inc-20260811.zip') SETTINGS id = 'analytics-inc-20260811', base_backup = Disk('backups', 'analytics-full.zip');

Инкрементальная цепочка экономит место, но увеличивает число зависимостей при восстановлении. Политика хранения должна сохранять все необходимые базовые копии.

#Проверка восстановления

Не восстанавливайте учебную копию поверх рабочей базы. Используйте отдельный кластер или другое имя:

RESTORE DATABASE analytics AS analytics_restore_test FROM Disk('backups', 'analytics-full.zip') SETTINGS id = 'restore-drill-20260810'; SELECT (SELECT count() FROM analytics.events) AS source_rows, (SELECT count() FROM analytics_restore_test.events) AS restored_rows;

Сравните не только число строк, но и контрольные агрегаты, DDL, словари и сущности доступа. Зафиксируйте фактические RPO и RTO. Бэкап, который ни разу не восстанавливали, остаётся непроверенной гипотезой.

RESTORE не охватывает всю базу одной транзакцией. При ошибке часть таблиц или частей уже может стать видимой, а автоматического отката нет. Поэтому восстановление выполняют в изоляции, проверяют статус каждой операции и только затем переключают приложение.

system.backups хранит операции только с последнего запуска сервера. Для долговременного аудита сохраняйте system.backup_log и внешние метрики.

FREEZE, снимки файловой системы и сторонние инструменты могут быть оправданы существующей инфраструктурой или специальными требованиями. Их нужно рассматривать как отдельный проект с тестом согласованности и восстановления, а не как автоматическую рекомендацию.

#Обновления

#Rolling update

#!/bin/bash # rolling_update.sh CLUSTER_NODES=("ch-01" "ch-02" "ch-03" "ch-04" "ch-05" "ch-06") for node in "${CLUSTER_NODES[@]}"; do echo "Updating $node..." # Исключить из балансировщика disable_in_loadbalancer $node # Остановить репликацию ssh $node "clickhouse-client --query 'SYSTEM STOP FETCHES'" # Дождаться завершения текущих запросов ssh $node "clickhouse-client --query \"SELECT sleep(5)\"" # Остановить сервер ssh $node "systemctl stop clickhouse-server" # Обновить пакет ssh $node "apt-get update && apt-get install -y clickhouse-server clickhouse-client" # Запустить сервер ssh $node "systemctl start clickhouse-server" # Проверить статус ssh $node "clickhouse-client --query 'SELECT 1'" # Включить в балансировщик enable_in_loadbalancer $node # Дождаться синхронизации ssh $node "clickhouse-client --query 'SYSTEM SYNC REPLICA'" echo "Node $node updated successfully" done

#Проверка совместимости

-- Проверить версию перед обновлением SELECT version(); -- Проверить совместимость версий -- https://clickhouse.com/docs/en/whats-new/changelog/ -- Проверить статус реплик перед обновлением SELECT database, table, total_replicas, active_replicas, absolute_delay FROM system.replicas;

#Масштабирование

#Горизонтальное масштабирование (шардирование)

-- Добавить новый шард в кластер -- 1. Обновить remote_servers.xml на всех узлах -- 2. Создать таблицы на новых узлах CREATE TABLE events_local ON CLUSTER cluster_default ( event_time DateTime, user_id UInt64 ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/events', '{replica}') ORDER BY (event_time, user_id); -- 3. Перераспределить данные (опционально) INSERT INTO events_all SELECT * FROM events_all SETTINGS insert_distributed_sync = 1;

#Вертикальное масштабирование

<!-- Увеличить лимиты для мощного сервера --> <max_concurrent_queries>200</max_concurrent_queries> <max_memory_usage>100000000000</max_memory_usage> <!-- 100 GB --> <max_threads>64</max_threads>

#Балансировка нагрузки

<!-- users.xml --> <profiles> <default> <!-- Распределение запросов по репликам --> <load_balancing>round_robin</load_balancing> <!-- Предпочтение локальной реплике --> <prefer_localhost_replica>1</prefer_localhost_replica> </default> </profiles>

#Мониторинг и оповещения

#Ключевые метрики

МетрикаПорогОписание
OSFreePhysicalMemory< 10%Свободная память
FilesystemFree< 10%Свободное место на диске
ReplicasStatusAbsoluteDelay> 60sОтставание реплик
MergesMutations> 10Долгие слияния/мутации
QueryLatencyP99 > 1sЗадержка запросов

#Правила оповещений Prometheus

# clickhouse_alerts.yml groups: - name: clickhouse rules: - alert: ClickHouseLowDiskSpace expr: clickhouse_filesystem_free / clickhouse_filesystem_total < 0.1 for: 5m labels: severity: critical annotations: summary: "Low disk space on {{ $labels.instance }}" - alert: ClickHouseReplicaDelay expr: clickhouse_replicas_status_absolute_delay > 60 for: 5m labels: severity: warning annotations: summary: "Replica delay on {{ $labels.instance }}" - alert: ClickHouseHighMemory expr: clickhouse_memory_tracking / clickhouse_max_memory_usage > 0.9 for: 5m labels: severity: warning annotations: summary: "High memory usage on {{ $labels.instance }}"

#Разбор неполадок

#Медленные запросы

-- Найти медленные запросы SELECT query, avg(elapsed) AS avg_elapsed, max(elapsed) AS max_elapsed, count() AS executions FROM system.query_log WHERE event_date = today() GROUP BY query HAVING avg_elapsed > 1.0 ORDER BY avg_elapsed DESC LIMIT 20; -- Анализ плана EXPLAIN PIPELINE SELECT ...;

#Проблемы с памятью

-- Запросы с большим потреблением памяти SELECT query, max(memory_usage) AS max_memory, event_time FROM system.query_log WHERE event_date = today() AND memory_usage > 10000000000 -- 10 GB ORDER BY max_memory DESC; -- Убить запрос KILL QUERY WHERE query_id = '...';

#Проблемы с репликацией

-- Проверить статус реплик SELECT database, table, is_readonly, is_session_expired, absolute_delay, last_queue_update_exception FROM system.replicas; -- Проверить очередь репликации SELECT database, table, position, type, create_time, latest_fail_reason FROM system.replication_queue WHERE latest_fail_reason != ''; -- Перезапустить репликацию SYSTEM RESTART REPLICA table_name;

#SLO/SLA

Пример SLO для ClickHouse:

МетрикаЦельПериод
Доступность99.9%Месяц
Задержка запросов (P99)< 1sДень
Отставание реплик< 60sЧас
Потеря данных0Постоянно

Расчёт доступности:

Доступность = (Время работы / Общее время) × 100%
99.9% = ~43 минуты простоя в месяц

#Практика: восстановление по таймеру

  1. Задайте RPO и RTO для учебной базы.
  2. Создайте встроенный BACKUP с явным ID и дождитесь статуса BACKUP_CREATED.
  3. Добавьте новые данные после точки копирования.
  4. Восстановите копию в базу с другим именем.
  5. Сверьте DDL, число строк и три контрольных агрегата.
  6. Запишите фактические RPO/RTO и одно изменение, которое сократит время восстановления.

Наличие архива без успешного RESTORE не засчитывается.

#Итоговая работа

Переходите к итоговому практикуму: там схема, загрузка, оптимизация, безопасность и восстановление собираются в один проверяемый проект.

Далее: Итоговый практикум