Поддержка транзакций (ACID)
Случай 1: INSERT в одну партицию одной таблицы семейства MergeTree*
Это транзакционно (ACID), если вставляемые строки упакованы и вставляются как единый блок (см. Заметки):
- Атомарность: запрос INSERT либо завершается успешно, либо отклоняется полностью: если клиенту отправляется подтверждение, значит, все строки были вставлены; если клиенту отправляется ошибка, значит, ни одна строка не была вставлена.
- Согласованность: если не нарушены ограничения таблицы, значит, все строки в запросе INSERT вставлены, и INSERT завершается успешно; если ограничения нарушены, то строки не вставляются.
- Изолированность: параллельные клиенты наблюдают согласованный снимок таблицы – состояние таблицы либо до попытки INSERT, либо после успешного INSERT; частичное состояние не наблюдается. Клиенты внутри другой транзакции имеют изолированность по снимку, в то время как клиенты вне транзакции имеют уровень изолированности чтения неподтвержденного.
- Долговечность: успешный запрос INSERT записывается в файловую систему перед ответом клиенту, на одной реплике или нескольких репликах (управляется настройкой
insert_quorum), и ClickHouse может запросить у ОС синхронизацию данных файловой системы на носителе (управляется настройкойfsync_after_insert). - INSERT в несколько таблиц с одним запросом возможен, если вовлечены материализованные представления (запрос INSERT от клиента относится к таблице, которая имеет ассоциированные материализованные представления).
Случай 2: INSERT в несколько партиций одной таблицы семейства MergeTree*
То же самое, что и в Случае 1 выше, с этим уточнением:
- Если таблица имеет много партиций и INSERT охватывает множество партиций, то вставка в каждую партицию транзакционна сама по себе.
Случай 3: INSERT в одну распределенную таблицу семейства MergeTree*
То же самое, что и в Случае 1 выше, с этим уточнением:
- INSERT в распределенную таблицу не является транзакционным в целом, в то время как вставка в каждый шард транзакционна.
Случай 4: Использование таблицы Buffer
- вставка в таблицы Buffer не является ни атомарной, ни изолированной, ни согласованной, ни долговечной.
Случай 5: Использование async_insert
То же самое, что и в Случае 1 выше, с этим уточнением:
- атомарность гарантируется даже если
async_insertвключен, аwait_for_async_insertустановлен в 1 (по умолчанию), но еслиwait_for_async_insertустановлен в 0, то атомарность не гарантируется.
Заметки
- строки, вставляемые от клиента в каком-либо формате данных, упаковываются в единый блок, когда:
- формат вставки основан на строках (например, CSV, TSV, Values, JSONEachRow и т.д.) и данные содержат менее чем
max_insert_block_sizeстрок (~1 000 000 по умолчанию) или менее чемmin_chunk_bytes_for_parallel_parsingбайт (10 МБ по умолчанию) в случае использования параллельного парсинга (включен по умолчанию) - формат вставки основан на колонках (например, Native, Parquet, ORC и т.д.) и данные содержат только один блок данных
- формат вставки основан на строках (например, CSV, TSV, Values, JSONEachRow и т.д.) и данные содержат менее чем
- размер вставляемого блока может зависеть от множества настроек (например:
max_block_size,max_insert_block_size,min_insert_block_size_rows,min_insert_block_size_bytes,preferred_block_size_bytesи т.д.) - если клиент не получил ответа от сервера, клиент не знает, завершилась ли транзакция успешно, и он может повторить транзакцию, используя свойства вставки точно один раз
- ClickHouse использует MVCC с изолированностью по снимку для параллельных транзакций
- все свойства ACID действительны даже в случае завершения/сбоя сервера
- либо insert_quorum в разные AZ, либо fsync должен быть включен для обеспечения долговечных вставок в типичной конфигурации
- "согласованность" в терминах ACID не охватывает семантику распределенных систем, см. https://jepsen.io/consistency, что контролируется различными настройками (select_sequential_consistency)
- это объяснение не охватывает новую функцию транзакций, которая позволяет иметь полнофункциональные транзакции над несколькими таблицами, материализованными представлениями, для нескольких SELECT и т.д. (см. следующий раздел о Транзакциях, Подтверждении и Откате)
Транзакции, Подтверждение и Откат
В дополнение к описанной выше функциональности, ClickHouse имеет экспериментальную поддержку транзакций, подтверждений и функциональности отката.
Требования
- Разверните ClickHouse Keeper или ZooKeeper для отслеживания транзакций
- Только атомарная БД (по умолчанию)
- Только движок таблицы Non-Replicated MergeTree
- Включите экспериментальную поддержку транзакций, добавив эту настройку в
config.d/transactions.xml:
Заметки
- Это экспериментальная функция, и изменения следует ожидать.
- Если во время транзакции происходит исключение, вы не можете подтвердить транзакцию. Это касается всех исключений, включая исключения
UNKNOWN_FUNCTION, вызванные опечатками. - Вложенные транзакции не поддерживаются; завершите текущую транзакцию и начните новую.
Конфигурация
Эти примеры относятся к серверу ClickHouse с одним узлом с включенным ClickHouse Keeper.
Включение экспериментальной поддержки транзакций
Основная конфигурация для одного узла сервера ClickHouse с включенным ClickHouse Keeper
Смотрите документацию по развёртыванию для получения подробностей о развертывании сервера ClickHouse и надлежащем кворуме узлов ClickHouse Keeper. Конфигурация, представленная здесь, предназначена для экспериментальных целей.
Пример
Проверьте, что экспериментальные транзакции включены
Выполните BEGIN TRANSACTION или START TRANSACTION, за которым следует ROLLBACK, чтобы проверить, что экспериментальные транзакции включены, и что ClickHouse Keeper включен, поскольку он используется для отслеживания транзакций.
Если вы видите следующую ошибку, проверьте ваш файл конфигурации, чтобы убедиться, что allow_experimental_transactions установлен в 1 (или любое значение, отличное от 0 или false).
Вы также можете проверить ClickHouse Keeper, выполнив
ClickHouse Keeper должен ответить imok.
Создайте таблицу для тестирования
Создание таблиц не является транзакционным. Выполните этот DDL-запрос вне транзакции.
Начните транзакцию и вставьте строку
Вы можете запрашивать таблицу из транзакции и увидеть, что строка была вставлена, даже если она еще не была подтверждена.
Откатить транзакцию и снова запросить таблицу
Убедитесь, что транзакция была отменена:
Завершить транзакцию и снова запросить таблицу
Инспекция транзакций
Вы можете просматривать транзакции, запрашивая таблицу system.transactions, но учтите, что вы не можете запрашивать эту таблицу из сессии, находящейся в транзакции. Откройте вторую сессию clickhouse client, чтобы запросить эту таблицу.
Дополнительные детали
Смотрите эту мета-проблему, чтобы найти более обширные тесты и быть в курсе прогресса.