Асинхронные вставки (async_insert)
Асинхронные вставки в ClickHouse предоставляют мощную альтернативу в случаях, когда пакетирование на стороне клиента невозможно. Это особенно ценно в нагрузках по наблюдаемости (observability), где сотни или тысячи агентов непрерывно отправляют данные — логи, метрики, трейсы — часто небольшими порциями в режиме реального времени. Буферизация данных на стороне клиента в таких средах повышает сложность и требует централизованной очереди, чтобы обеспечивать отправку достаточно крупных пакетов.
Отправка множества маленьких батчей в синхронном режиме не рекомендуется, поскольку приводит к созданию большого количества частей (части). Это ухудшит производительность запросов и приведёт к ошибкам "too many part".
Асинхронные вставки переносят ответственность за пакетирование с клиента на сервер, записывая входящие данные в буфер в памяти, а затем сбрасывая их в хранилище при достижении настраиваемых порогов. Такой подход существенно снижает накладные расходы на создание частей, уменьшает использование CPU и обеспечивает эффективную ингестию даже при высокой степени параллелизма.
Базовое поведение управляется настройкой async_insert.

Асинхронные вставки поддерживаются как через HTTP, так и через нативный интерфейс TCP.
Когда включено (async_insert = 1), вставки буферизуются и записываются на диск только после выполнения одного из условий сброса:
- Буфер достигает заданного размера данных (
async_insert_max_data_size, по умолчанию 100 MiB). - Истекает порог времени (
async_insert_busy_timeout_ms, по умолчанию 200 мс или 1000 мс в Cloud). - Накапливается максимальное число запросов вставки (
async_insert_max_query_number, по умолчанию 450).
Сброс выполняется при достижении первого из этих порогов.
Этот процесс пакетирования прозрачен для клиентов и помогает ClickHouse эффективно объединять трафик вставок из нескольких источников. Однако до момента сброса данные недоступны для запросов. Важно, что существует несколько буферов для каждой комбинации типа вставки (insert shape) и настроек, а в кластерах буферы поддерживаются на каждом узле — это обеспечивает тонкий контроль в многопользовательских средах. Механика вставок в остальном идентична описанной для синхронных вставок.
Выбор режима возврата
Поведение асинхронных вставок дополнительно уточняется с помощью настройки wait_for_async_insert.
При значении 1 (по умолчанию) ClickHouse подтверждает вставку только после того, как данные успешно сброшены на диск. Это обеспечивает сильные гарантии надёжного сохранения данных и упрощает обработку ошибок: если что-то идёт не так во время сброса, ошибка возвращается клиенту. Этот режим рекомендуется для большинства продукционных сценариев, особенно когда отказы вставок должны надёжно отслеживаться.
Результаты бенчмарков показывают, что он хорошо масштабируется при высокой конкурентности — независимо от того, запускаете ли вы 200 или 500 клиентов — благодаря адаптивным вставкам и стабильному поведению по созданию частей.
Установка wait_for_async_insert = 0 включает режим "fire-and-forget". В этом случае сервер подтверждает вставку сразу после буферизации данных, не дожидаясь их записи в хранилище.
Это обеспечивает вставки с ультранизкой задержкой и максимальную пропускную способность, что идеально для данных с высокой скоростью поступления и низкой критичностью. Однако это сопряжено с компромиссами: нет гарантии, что данные будут сохранены, ошибки проявляются только во время сброса, и для неудачных вставок нет очереди недоставленных сообщений — для трассировки сбоев требуется постфактум проверять журналы сервера и системные таблицы. Используйте этот режим только если ваша рабочая нагрузка допускает потерю данных.
Бенчмарки также демонстрируют значительное сокращение числа частей и снижение использования CPU при редких сбросах буфера (например, каждые 30 секунд), но риск «тихих» сбоев при этом сохраняется.
Мы настоятельно рекомендуем использовать async_insert=1,wait_for_async_insert=1, если вы применяете асинхронные вставки. Использование wait_for_async_insert=0 очень рискованно, поскольку ваш клиент INSERT может не узнать о возникших ошибках, а также может привести к потенциальной перегрузке, если клиент продолжит быстро записывать данные в ситуации, когда сервер ClickHouse должен замедлить запись и создать некоторое обратное давление (backpressure), чтобы обеспечить надёжность сервиса.
Адаптивные асинхронные вставки
Начиная с версии 24.2, ClickHouse по умолчанию использует адаптивные таймауты сброса (async_insert_use_adaptive_busy_timeout). Вместо фиксированного интервала сброса таймаут динамически регулируется в диапазоне от минимального значения (async_insert_busy_timeout_min_ms, по умолчанию 50 мс) до максимального (async_insert_busy_timeout_max_ms, по умолчанию 200 мс или 1000 мс в Cloud) в зависимости от скорости поступления данных.
Когда данные поступают часто, таймаут остается ближе к минимуму, чтобы выполнять сброс раньше и снижать общую задержку. Когда данные поступают редко, он увеличивается в сторону максимума, чтобы накапливать более крупные пакеты. Это особенно полезно в режиме по умолчанию (wait_for_async_insert=1), где фиксированный высокий таймаут заставлял бы клиентов ждать весь интервал, даже если данные уже готовы к сбросу.
Обработка ошибок
Проверка schema и разбор данных происходят при сбросе буфера, а не при получении запроса на вставку. Если в какой-либо строке запроса на вставку возникает ошибка разбора или несоответствие типа, данные из этого запроса не сбрасываются вообще — отклоняется всё содержимое запроса. В режиме по умолчанию (wait_for_async_insert=1) ошибка возвращается клиенту. В режиме fire-and-forget ошибки записываются в логи сервера и в таблицу system.asynchronous_inserts.
Каждый сброс создаёт как минимум одну часть для каждого отдельного значения ключа партиционирования в буфере. Даже для таблиц без ключа партиционирования один сброс может создать несколько частей, если объём буферизованных данных превышает max_insert_block_size (по умолчанию ~1 миллион строк).
Даже при использовании асинхронных вставок вы всё равно можете столкнуться с ошибками "слишком большое количество частей", если ключ партиционирования имеет высокую кардинальность.
Дедупликация и надёжность
По умолчанию ClickHouse выполняет автоматическую дедупликацию для синхронных вставок, что делает повторные попытки безопасными в случае сбоев. Однако для асинхронных вставок она отключена, если только не включена явно (её не следует включать, если у вас есть зависимые материализованные представления — см. issue).
На практике, если дедупликация включена и одна и та же вставка повторяется — например, из-за тайм-аута или обрыва сети — ClickHouse может безопасно проигнорировать дубликат. Это помогает сохранять идемпотентность и избегать повторной записи данных.
Включение асинхронных вставок
Асинхронные вставки можно включить для конкретного пользователя или для определённого запроса:
-
Включение асинхронных вставок на уровне пользователя. В этом примере используется пользователь
default; если вы создадите другого пользователя, подставьте его имя пользователя: -
Вы можете указать настройки асинхронной вставки, используя предложение SETTINGS в запросах INSERT:
-
Вы также можете указать настройки асинхронной вставки как параметры подключения при использовании клиентской библиотеки ClickHouse для языка программирования.
В качестве примера ниже показано, как это можно сделать в строке подключения JDBC при использовании драйвера ClickHouse Java JDBC для подключения к ClickHouse Cloud:
Асинхронные вставки не применяются к запросам INSERT INTO ... SELECT. Если вставка содержит предложение SELECT, запрос всегда выполняется синхронно независимо от настройки async_insert.
Сброс буферов при завершении работы
Чтобы сбросить все буферы асинхронной вставки, ожидающие записи, — например, при корректном завершении работы или перед метенансом, — выполните:
Это гарантирует, что все буферизованные данные будут записаны в хранилище перед остановкой сервера.
Сравнение с Buffer tables
Асинхронные вставки — современная замена Buffer tables. Ключевые различия:
- Изменения DDL не требуются. Асинхронные вставки прозрачны: вы просто включаете настройку, а не создаёте дополнительные таблицы.
- Буферизация по шаблону запроса. Для каждой уникальной структуры запроса и комбинации настроек асинхронные вставки поддерживают отдельные буферы, что позволяет точнее настраивать политики сброса. Buffer tables используют один буфер на каждую целевую таблицу.
- Надёжность. В режиме по умолчанию (
wait_for_async_insert=1) данные записываются на диск до того, как клиент получит подтверждение. Buffer tables работают по принципу fire-and-forget — при сбое буферизованные данные теряются. - Поведение в кластере. В кластерах буферы асинхронных вставок поддерживаются отдельно на каждом узле. Buffer tables нужно явно создавать на каждом узле.