Перейти к основному содержимому
Перейти к основному содержимому

Выбор стратегии вставки

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

примечание

Предполагается, что вы отправляете данные в ClickHouse через клиента. Если вы извлекаете данные в ClickHouse, например, используя встроенные табличные функции, такие как s3 и gcs, мы рекомендуем вам обратиться к нашему руководству "Оптимизация для скорости вставки и чтения через S3".

Синхронные вставки по умолчанию

По умолчанию, вставки в ClickHouse являются синхронными. Каждый запрос на вставку немедленно создает часть хранилища на диске, включая метаданные и индексы.

Используйте синхронные вставки, если вы можете пакетировать данные на стороне клиента

Если нет, см. Асинхронные вставки ниже.

Мы кратко рассмотрим механику вставки MergeTree в ClickHouse ниже:

Процессы вставки

Этапы на стороне клиента

Для оптимальной производительности данные должны быть ① пакетированы, таким образом размер пакета становится первым решением.

ClickHouse хранит вставленные данные на диске, упорядоченные по первичному ключу таблицы. Второе решение — это ② предварительная сортировка данных перед передачей на сервер. Если пакет приходит предварительно отсортированным по первичному ключу, ClickHouse может пропустить шаг ⑨ сортировки, ускоряя прием данных.

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

Следующее основное решение — ④ нужно ли сжимать данные перед передачей на сервер ClickHouse. Сжатие уменьшает размер передаваемых данных и повышает сетевую эффективность, что приводит к более быстрым передачам данных и меньшему использованию пропускной способности, особенно для крупных наборов данных.

Данные ⑤ передаются на сетевой интерфейс ClickHouse — либо нативный, либо HTTP интерфейс (который мы сравниваем позже в этом посте).

Этапы на стороне сервера

После ⑥ получения данных, ClickHouse ⑦ распаковывает их, если было использовано сжатие, а затем ⑧ разбирает их из первоначально отправленного формата.

Используя значения из этих отформатированных данных и заявление DDL целевой таблицы, ClickHouse ⑨ создает в памяти блок в формате MergeTree, ⑩ сортирует строки по столбцам первичного ключа, если они еще не отсортированы, ⑪ создает разреженный первичный индекс, ⑫ применяет сжатие по колонкам и ⑬ записывает данные как новую ⑭ часть данных на диск.

Пакетные вставки, если синхронные

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

Мы рекомендуем вставлять данные пакетами по крайней мере по 1,000 строк, а в идеале от 10,000 до 100,000 строк. Меньшее количество, но более крупные вставки снижает количество записанных частей, минимизирует нагрузку на слияние и снижает общее использование ресурсов системы.

Для эффективной стратегии синхронной вставки требуется пакетирование на стороне клиента.

Если вы не можете пакетировать данные на стороне клиента, ClickHouse поддерживает асинхронные вставки, которые переносят пакетирование на сервер (см.).

подсказка

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

Обеспечьте идемпотентные повторные попытки

Синхронные вставки также являются идемпотентными. При использовании движков MergeTree ClickHouse по умолчанию будет удалять дубликаты вставок. Это защищает от неоднозначных случаев сбоя, таких как:

  • Вставка прошла успешно, но клиент никогда не получил подтверждение из-за сетевого сбоя.
  • Вставка не удалась на стороне сервера и вышла за пределы времени ожидания.

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

Выберите правильную цель вставки

Для шардированных кластеров у вас есть два варианта:

  • Вставлять данные непосредственно в таблицу MergeTree или ReplicatedMergeTree. Это наиболее эффективный вариант, когда клиент может выполнять нагрузочное распределение по шардированным узлам. При internal_replication = true ClickHouse обрабатывает репликацию прозрачно.
  • Вставлять данные в распределенную таблицу. Это позволяет клиентам отправлять данные любому узлу и позволяет ClickHouse перенаправлять их к правильному шардированному узлу. Это проще, но немного менее эффективно из-за дополнительного этапа перенаправления. Рекомендуется использовать internal_replication = true.

В ClickHouse Cloud все узлы читают и записывают данные в один и тот же шард. Вставки автоматически распределяются по узлам. Пользователи могут просто отправлять вставки на открытый конечный узел.

Выберите правильный формат

Выбор правильного формата ввода имеет решающее значение для эффективного приема данных в ClickHouse. С более чем 70 поддерживаемыми форматами, выбор наиболее производительного варианта может значительно повлиять на скорость вставки, использование CPU и памяти, а также общую эффективность системы.

Хотя гибкость полезна для обработки данных и импорта на основе файлов, приложения должны придавать приоритет форматам, ориентированным на производительность:

  • Нативный формат (рекомендуется): Наиболее эффективный. Ориентирован на столбцы, минимальное парсинг требуется на стороне сервера. Используется по умолчанию в клиентах Go и Python.
  • RowBinary: Эффективный формат на основе строк, идеален, если преобразование на колонках сложно для клиента. Используется клиентом Java.
  • JSONEachRow: Легок в использовании, но дорогостоящий в парсинге. Подходит для случаев с низким объемом данных или быстрых интеграций.

Используйте сжатие

Сжатие играет критическую роль в уменьшении сетевой нагрузки, ускорении вставок и снижении затрат на хранение в ClickHouse. Эффективно использованное, оно улучшает производительность приема, не требуя изменений в формате данных или схеме.

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

Для вставок сжатие особенно эффективно при использовании нативного формата, который уже соответствует внутренней модели столбцового хранения ClickHouse. В этой настройке сервер может эффективно распаковывать и напрямую хранить данные с минимальной трансформацией.

Используйте LZ4 для скорости, ZSTD для коэффициента сжатия

ClickHouse поддерживает несколько кодеков сжатия во время передачи данных. Два распространенных варианта:

  • LZ4: Быстрый и легковесный. Значительно уменьшает размер данных при минимальных затратах CPU, что делает его идеальным для вставок с высокой пропускной способностью и используется по умолчанию в большинстве клиентов ClickHouse.
  • ZSTD: Высокий коэффициент сжатия, но более затратный по CPU. Полезен, когда затраты на перенос данных через сеть высоки — например, в сценариях межрегиональных или облачных провайдеров — хотя это немного увеличивает время вычислений на стороне клиента и распаковки на стороне сервера.

Лучшие практики: Используйте LZ4, если у вас нет ограниченной ширины канала или если возникают затраты на выход данных — тогда рассмотрите использование ZSTD.

примечание

В тестах из бенчмарка FastFormats, вставки нативного формата, сжатые с помощью LZ4, уменьшили размер данных более чем на 50%, сократив время приема с 150 секунд до 131 секунд для набора данных в 5.6 ГиБ. Переход на ZSTD сжал тот же набор данных до 1.69 ГиБ, но немного увеличил время обработки на стороне сервера.

Сжатие уменьшает использование ресурсов

Сжатие не только снижает сетевой трафик, но и улучшает эффективность CPU и памяти на сервере. С сжатыми данными ClickHouse получает меньше байтов и тратит меньше времени на разбор больших входных данных. Это преимущество особенно важно при приеме данных от нескольких одновременно работающих клиентов, например, в сценариях наблюдения.

Влияние сжатия на CPU и память скромное для LZ4 и умеренное для ZSTD. Даже под нагрузкой эффективность на стороне сервера улучшается за счет уменьшенного объема данных.

Совмещение сжатия с пакетированием и эффективным форматом ввода (таким как нативный) дает наилучшие результаты по производительности приема.

При использовании нативного интерфейса (например, clickhouse-client) сжатие LZ4 включено по умолчанию. Вы можете опционально переключиться на ZSTD через настройки.

С HTTP интерфейсом используйте заголовок Content-Encoding для применения сжатия (например, Content-Encoding: lz4). Вся полезная нагрузка должна быть сжата до отправки.

Предварительная сортировка, если низкая стоимость

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

Когда данные приходят предварительно отсортированными, ClickHouse может пропустить или упростить внутренний шаг сортировки во время создания частей, уменьшая использование CPU и ускоряя процесс вставки. Предварительная сортировка также улучшает эффективность сжатия, поскольку схожие значения группируются вместе, позволяя кодекам, таким как LZ4 или ZSTD, достигать лучшего коэффициента сжатия. Это особенно полезно в сочетании с большими пакетными вставками и сжатием, так как это уменьшает как накладные расходы на обработку, так и объем передаваемых данных.

Тем не менее, предварительная сортировка является необязательной оптимизацией — не требуемой. ClickHouse сортирует данные с высокой эффективностью, используя параллельную обработку, и во многих случаях сортировка на стороне сервера быстрее или удобнее, чем предварительная сортировка на стороне клиента.

Рекомендуем предварительную сортировку только в том случае, если данные уже почти упорядочены или если ресурсы на стороне клиента (CPU, память) достаточны и недостаточно используются. В сценариях, чувствительных к задержкам или с высокой пропускной способностью, таких как наблюдение, где данные приходят вне порядка или от многих агентов, часто лучше пропускать предварительную сортировку и полагаться на встроенные возможности ClickHouse.

Асинхронные вставки

Асинхронные вставки в ClickHouse предоставляют мощную альтернативу, когда пакетирование на стороне клиента невозможно. Это особенно полезно в рабочих нагрузках наблюдаемости, когда сотни или тысячи агентов непрерывно отправляют данные - логи, метрики, трассировки - часто в небольших, реальных нагрузках. Буферизация данных на стороне клиента в этих условиях увеличивает сложность, требуя центральной очереди для обеспечения возможности отправки достаточно крупных пакетов.

примечание

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

Асинхронные вставки переносят ответственность за пакетирование с клиента на сервер, записывая входящие данные в буфер в памяти, а затем сбрасывая их на хранение на основе настраиваемых пороговых значений. Этот подход значительно снижает накладные расходы на создание частей, уменьшает использование CPU и обеспечивает эффективность приема - даже при высокой конкурентной загрузке.

Основное поведение контролируется с помощью настройки async_insert.

Асинхронные вставки

Когда включено (1), вставки буферизуются и записываются на диск только после того, как выполнено одно из условий сброса:

(1) буфер достигает указанного размера (async_insert_max_data_size) (2) истекает временной порог (async_insert_busy_timeout_ms) или (3) накапливается максимальное количество запросов вставки (async_insert_max_query_number).

Этот процесс пакетирования невидим для клиентов и помогает ClickHouse эффективно объединять вставочный трафик из нескольких источников. Тем не менее, до выполнения сброса данные нельзя запрашивать. Важно, что существует несколько буферов на комбинацию формы и настроек вставки, а в кластерах буферы поддерживаются на каждом узле - что позволяет осуществлять детальный контроль в многопользовательских средах. Механика вставки в остальном идентична описанной для синхронных вставок.

Выбор режима возврата

Поведение асинхронных вставок дополнительно уточняется с помощью настройки 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 должен замедлить записи и создать некоторое обратное давление для обеспечения надежности сервиса.

Дедупликация и надежность

По умолчанию ClickHouse выполняет автоматическую дедупликацию для синхронных вставок, что делает повторные попытки безопасными в сценариях сбоев. Однако это отключено для асинхронных вставок, если не будет явно включено (это не следует включать, если у вас есть зависимые материализованные представления - см. проблему).

На практике, если дедупликация включена и та же вставка повторяется - например, из-за таймаута или сетевого разрыва - ClickHouse может безопасно игнорировать дубликат. Это помогает поддерживать идемпотентность и избегать двойной записи данных. Тем не менее, стоит отметить, что проверка вставки и парсинг схемы происходят только во время сброса буфера - поэтому ошибки (например, несовпадение типов) появятся только в этот момент.

Включение асинхронных вставок

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

  • Включение асинхронных вставок на уровне пользователя. В этом примере используется пользователь default, если вы создаете другого пользователя, замените это имя:
ALTER USER default SETTINGS async_insert = 1
  • Вы можете указать настройки асинхронной вставки, используя оператор SETTINGS в запросах вставки:
INSERT INTO YourTable SETTINGS async_insert=1, wait_for_async_insert=1 VALUES (...)
  • Вы также можете указать настройки асинхронной вставки в качестве параметров соединения, используя клиент программного языка ClickHouse.

    Например, так вы можете сделать это в строке подключения JDBC, когда вы используете драйвер ClickHouse Java JDBC для подключения к ClickHouse Cloud:

"jdbc:ch://HOST.clickhouse.cloud:8443/?user=default&password=PASSWORD&ssl=true&custom_http_params=async_insert=1,wait_for_async_insert=1"

Выберите интерфейс - HTTP или нативный

Нативный

ClickHouse предлагает два основных интерфейса для приема данных: нативный интерфейс и HTTP интерфейс - каждый из которых имеет компромиссы между производительностью и гибкостью. Нативный интерфейс, используемый клиентом clickhouse-client и некоторыми клиентами языков программирования, такими как Go и C++, специально разработан для производительности. Он всегда передает данные в высокоэффективном нативном формате ClickHouse, поддерживает блочное сжатие с LZ4 или ZSTD и минимизирует обработку на стороне сервера, сокращая такие задачи, как разбор и преобразование формата, до клиента.

Он даже позволяет вычислять значения MATERIALIZED и DEFAULT для колонок на стороне клиента, позволяя серверу пропускать эти шаги целиком. Это делает нативный интерфейс идеальным для сценариев высокой пропускной способности, где эффективность имеет решающее значение.

HTTP

В отличие от многих традиционных баз данных, ClickHouse также поддерживает HTTP интерфейс. Это, напротив, придает приоритет совместимости и гибкости. Он позволяет отправлять данные в любом поддерживаемом формате - включая JSON, CSV, Parquet и другие - и широко поддерживается большинством клиентов ClickHouse, включая Python, Java, JavaScript и Rust.

Это часто предпочтительнее для нативного протокола ClickHouse, поскольку позволяет легко переключать трафик с помощью балансировщиков нагрузки. Мы ожидаем небольшие различия в производительности вставки с нативным протоколом, который требует чуть меньших накладных расходов.

Однако в нем отсутствует более глубокая интеграция нативного протокола, и он не может выполнять клиентские оптимизации, такие как вычисление значений materialized или автоматическое преобразование в нативный формат. Хотя вставки HTTP все еще могут быть сжаты с использованием стандартных заголовков HTTP (например, Content-Encoding: lz4), сжатие применяется ко всей полезной нагрузке, а не к отдельным блокам данных. Этот интерфейс часто предпочитают в средах, где простота протокола, балансировка нагрузки или широкая совместимость форматов важнее, чем чистая производительность.

Для более подробного описания этих интерфейсов см. здесь.