Синхронные и асинхронные вставки данных в ClickHouse

ClickHouse примеры курсы обучение, архитектура данных примеры курсы обучение, вставка данных в ClickHouse, инженерия данных ClickHouse

Чем синхронная вставка в ClickHouse отличается от асинхронной и как это настроить: лучшие практики и риски загрузки данных в колоночное хранилище.

Синхронная вставка данных в ClickHouse

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

По умолчанию, когда настройка async_insert=0, ClickHouse записывает данные синхронно, отправляя подтверждение (ack) клиенту. При этом каждая вставка приводит к тому, что ClickHouse немедленно создает часть, которые потом объединяет в фоновом режиме.

Синхронная вставка данных в ClickHouse
Синхронная вставка данных в ClickHouse

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

Технически синхронная вставка данных в ClickHouse реализуется следующими способами:

  • через HTTP-интерфейса, когда данные отправляются POST-запросом, а клиентское приложение ждет ответа от сервера, подтверждающего завершение операции;
  • с использованием нативного протокола и клиента ClickHouse;
  • с применением специальных библиотек для различных языков программирования, например, clickhouse-driver для Python, когда вставка выполняется в рамках транзакции и клиентское приложение ожидает ее подтверждения.

Для таблиц MergeTree-семейства ClickHouse по умолчанию автоматически дедуплицирует синхронные вставки, удаляя дубли. При реплицированной вставке в ClickHouse Keeper создаются записи для каждой части данных. Кроме того, данные сортируются и сжимаются при записи новой части. Когда части объединяются, данные необходимо распаковать и отсортировать с помощью слияния. Также применяются оптимизации, специфичные для движка таблиц, перед тем как объединенные данные будут сжаты и снова записаны в хранилище.

Поэтому рекомендуется избегать создания слишком большого количества небольших вставок и слишком большого количества небольших начальных частей, т.к. это создает накладные расходы на создание файлов, увеличивает потребление ЦП и ресурсов ввода-вывода, а также накладные расходы на запросы к ClickHouse Keeper. Все это снижает производительность приема данных. Чтобы предотвратить это, в ClickHouse есть встроенные механизмы защиты: СУБД вернет ошибку Too many parts на запрос вставки для таблицы, когда в одном разделе более 300 активных частей.

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

Асинхронная вставка

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

Для асинхронных вставок нужно задать параметру async_insert значение 1. Тогда ClickHouse сначала сохраняет входящие данные в буфер памяти, а затем регулярно сбрасывает их на диск при достижении одного из следующих условий:

  • размер буфера достиг N байт, что настраивается в параметре async_insert_max_data_size, по умолчанию равному 10 МБ;
  • с момента последней очистки буфера прошло не менее N мс, что задается в параметре

С помощью параметра wait_for_async_insert можно указать, нужно ли возвращать подтверждение после вставки данных в буфер, задав ему значение 0 или делать это по умолчанию после записи части данных после очистки буфера, установив wait_for_async_insert = 1.

Асинхронная вставка данных в ClickHouse
Асинхронная вставка данных в ClickHouse

Рекомендуется использовать async_insert=1 и wait_for_async_insert=1 при асинхронных вставках. Использование wait_for_async_insert=0 очень рискованно, поскольку клиент может не знать об ошибках, а также может вызвать потенциальную перегрузку при интенсивной записи. Подробнее об этом поговорим в следующий раз.

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

  • если узел, содержащий буфер, по какой-то причине выйдет из строя до очистки буфера, запрос на вставку истечет по тайм-ауту и не получит подтверждения;
  • если данные были сброшены, но подтверждение не может быть возвращено отправителю запроса из-за сбоев в работе сети, отправитель получит тайм-аут или сетевую ошибку.

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

Ошибка Too many parts также может случиться и при асинхронных вставках. Например, при неудачно выбранном ключе партиционирования или при возникновении проблем на узле, где происходит очистка буфера в момент этой очистки. Данные из асинхронного запроса на вставку анализируются и проверяются на соответствие схеме целевой таблицы только при очистке буфера. Если некоторые значения строк из запроса на вставку не могут быть вставлены из-за ошибок парсинга или некорректного типа данных, то никакие данные из этого запроса не сбрасываются. Причем на очистку буфера из других запросов это не влияет. ClickHouse будет записывать подробные сообщения об ошибках вставки во время очистки буфера в файлы журналов и системные таблицы.

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

Буферные таблицы как альтернатива асинхронным вставкам

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

  • буферные таблицы надо явно создавать на каждом узле кластера Clickhouse и подключать к целевой таблице. Асинхронные вставки можно включать и выключать простым изменением настроек.
  • Запросы на вставку должны явно указывать на буферную таблицу, а не на реальную целевую таблицу. С асинхронными вставками это не так.
  • Буферные таблицы требуют изменений DDL-запросов каждый раз при изменении DDL целевой таблицы. Это не требуется при асинхронных вставках.
  • Данные в буферной таблице будут потеряны при сбое узла, аналогично асинхронным вставкам в режиме wait_for_async_insert = 0. Это не относится к асинхронным вставкам в режиме по умолчанию.
  • Асинхронные вставки предоставляют буфер для каждого запроса вставки и настройки, даже если все запросы нацелены на одну и ту же таблицу. Можно включить разные политики очистки буфера для различных данных в одной и той же таблице. Буферные таблицы не имеют такого механизма.

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

Освойте ClickHouse на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:

Источники

  1. https://clickhouse.com/docs/cloud/bestpractices/asynchronous-inserts
  2. https://clickhouse.com/blog/clickhouse-input-format-matchup-which-is-fastest-most-efficient
  3. https://clickhouse.com/blog/asynchronous-data-inserts-in-clickhouse
Я даю свое согласие на обработку персональных данных и соглашаюсь с политикой конфиденциальности.