Поддержка транзакций (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
, чтобы запросить эту таблицу.
Дополнительные детали
Смотрите эту мета-проблему, чтобы найти более обширные тесты и быть в курсе прогресса.