Частые ошибки при работе с ClickHouse — симптомы, причины и пошаговые решения.
Слишком частые INSERT-операции без батчинга или async_insert создают новый кусок данных при каждой вставке. ClickHouse не успевает сливать куски быстрее, чем они создаются, и число активных кусков превышает порог parts_to_delay_insert.
Запрос превысил лимит max_memory_usage (по умолчанию 10 ГБ или настройка сервера). Чаще всего причина — агрегация или сортировка большого числа уникальных ключей, которые целиком помещаются в хеш-таблицу в оперативной памяти.
Для завершения кворумной вставки (insert_quorum) требуется подтверждение от заданного числа реплик, но часть реплик недоступна (упала, перезапускается, имеет сетевые проблемы). ClickHouse не завершает INSERT, пока не достигнут кворум.
Сессия ClickHouse Keeper (или ZooKeeper) не была корректно закрыта при предыдущей остановке сервера — ephemeral-узел /replicas/{replica}/is_active ещё существует в Keeper. При новом старте ClickHouse видит, что узел занят, и отказывается его захватить.
Диск исчерпал свободное место — ClickHouse не может записать новые куски или временные файлы слияний. TTL MOVE мог не сработать из-за неправильно сконфигурированной storage policy: нет маршрута перемещения, недоступен S3 endpoint или превышен размер буферной очереди.
Файлы куска данных повреждены на диске: аппаратный сбой (битый сектор, плохой RAID), аварийное отключение питания без flush на диск, или повреждение файловой системы. ClickHouse хранит контрольные суммы для каждого куска и при несоответствии считает кусок неисправным.
Источник данных словаря (MySQL, PostgreSQL, HTTP, ClickHouse remote table) недоступен: изменился хост, порт или учётные данные, источник перезапускается, или сетевые правила блокируют соединение из ClickHouse.
Реплика потеряла соединение с ClickHouse Keeper или сессия истекла. Без доступа к Keeper таблица не может координировать репликацию и переходит в режим readonly, чтобы не допустить несогласованных данных.
Настройка max_rows_to_read ограничивает число строк, которые запрос может прочитать с диска — механизм защиты production кластеров от несанкционированных full-scan запросов. Запрос читает больше строк, чем разрешено профилем пользователя или сессионной настройкой.
Создана цепочка материализованных представлений, где MV A пишет в таблицу B, из которой MV C читает и пишет обратно в таблицу A. ClickHouse выполняет MV-триггеры синхронно в рамках INSERT, что приводит к циклическому вызову и deadlock или Stack Overflow.
AggregatingMergeTree требует, чтобы в колонках хранились промежуточные состояния агрегатных функций типа AggregateFunction(func, ...). При вставке необходимо использовать func-State(), при чтении — func-Merge(). Нарушение этого контракта или опечатка в имени функции приводит к ошибке.
ClickHouse по умолчанию использует hash join, загружая всю правую таблицу в оперативную память. При большом размере правой таблицы хеш-таблица не помещается в max_bytes_in_join и запрос падает.
Реплика не успевает применять записи из лога репликации. Причины: перегруженный диск на реплике, недостаточное число background потоков репликации, или лидер выполнил большой batch слияний, которые реплика должна воспроизвести.
Синхронная вставка без батчинга: каждый INSERT создаёт новый кусок на диске с fsync. ClickHouse оптимизирован для вставки крупных батчей (от 10 000 строк), а не для высокочастотных мелких вставок — это фундаментальная разница между OLTP и OLAP паттернами.
OPTIMIZE FINAL принудительно сливает все куски таблицы в один, включая уже слитые куски. Для больших таблиц это создаёт огромную нагрузку: читаются и переписываются сотни гигабайт данных. Фоновые слияния ClickHouse были разработаны как инкрементальный процесс, а OPTIMIZE FINAL — экстренный инструмент, не для регулярного использования.
ClickHouse не может аутентифицироваться в S3: неправильные access_key_id/secret_access_key, credentials устарели, IAM роль не имеет прав на бакет, или named collection содержит старые учётные данные. Частая причина в Docker/Kubernetes: instance metadata endpoint недоступен для получения ролевых credentials.
DETACH PARTITION требует точного значения выражения partition key, которое совпадает с реальными partition ID кусков. Если в PARTITION BY используется toYYYYMM(date), нужно указывать числовое значение 202401, а не строку '2024-01'. Несоответствие приводит к тому, что партиция детачится, но ATTACH не может её найти.
Raft кворум Keeper потерян: недостаточно живых узлов (нужно > N/2) для избрания лидера и обработки записей в Raft log. Без работающего Keeper ClickHouse не может координировать репликацию и блокирует все записи для предотвращения split-brain.
DDL-операция ALTER TABLE выполнена без ON CLUSTER и не реплицировалась на все узлы. В ClickHouse каждый узел применяет DDL независимо — для синхронного изменения на всём кластере обязательно использование ON CLUSTER с именем кластера из config.xml.
ClickHouse не поддерживает формат 'JSON array of objects' напрямую — для построчной вставки используется JSONEachRow, где каждый JSON-объект на отдельной строке. Формат JSON в ClickHouse предназначен для вывода (SELECT), а не для INPUT массивов объектов.
Мутация в ClickHouse реализована как фоновый процесс перезаписи кусков — каждый кусок данных должен быть переписан с применением UPDATE/DELETE. При большом числе кусков или высокой нагрузке записи мутация конкурирует с фоновыми слияниями за ресурсы I/O и может зависнуть.
Запрос выполняется дольше лимита max_execution_time (по умолчанию 0 = без лимита, но часто устанавливается администратором в 30-300 секунд для production защиты). Причины: неоптимальный план запроса, отсутствие skip-индексов, большой full-scan или тяжёлый JOIN.
Клиент отключился в процессе передачи большого результата (network timeout на клиентской стороне или сам закрыл соединение), либо сервер достиг лимита max_concurrent_queries и отклонил новый запрос. ClickHouse по умолчанию не переотправляет результаты после разрыва соединения.
HTTP-соединение было разорвано до передачи всего тела INSERT-запроса: клиентский таймаут, проблема сети или прокси (nginx/HAProxy) закрыл соединение. ClickHouse не может восстановить незавершённый HTTP-запрос.
max_server_memory_usage_to_ram_ratio (по умолчанию 0.9) задаёт абсолютный лимит памяти всего сервера ClickHouse, в отличие от max_memory_usage, который ограничивает один запрос. При высокой конкурентности сумма памяти всех запросов превышает серверный порог.