Поддержка транзакционности (ACID)
Случай 1: INSERT в один раздел одной таблицы семейства MergeTree*
Операция является транзакционной (ACID), если вставляемые строки упакованы и вставляются одним блоком (см. примечания):
- Atomic (атомарность): операция INSERT либо полностью завершается успешно, либо полностью отклоняется: если клиенту отправлено подтверждение, то вставлены все строки; если клиенту отправлена ошибка, то ни одна строка не вставлена.
- Consistent (согласованность): если не нарушены ограничения таблицы, то все строки в операции INSERT вставляются и INSERT завершается успешно; если ограничения нарушены, то ни одна строка не вставляется.
- Isolated (изолированность): параллельные клиенты наблюдают согласованный снимок таблицы — состояние таблицы либо таким, каким оно было до попытки INSERT, либо после успешного INSERT; промежуточное состояние не видно. Клиенты, работающие внутри транзакции, используют уровень изоляции snapshot isolation, а клиенты вне транзакции — уровень изоляции read uncommitted.
- Durable (долговечность): успешный INSERT записывается в файловую систему до ответа клиенту, на одну реплику или несколько реплик (управляется настройкой
insert_quorum), и ClickHouse может попросить ОС синхронизировать данные файловой системы с носителем (управляется настройкойfsync_after_insert). - INSERT в несколько таблиц одним оператором возможен, если задействованы материализованные представления (INSERT от клиента выполняется в таблицу, у которой есть связанные материализованные представления).
Случай 2: INSERT в несколько партиций одной таблицы семейства MergeTree*
Аналогично случаю 1 выше, с таким уточнением:
- Если таблица имеет много партиций и INSERT затрагивает многие из них, то вставка в каждую партицию является самостоятельной транзакцией
Случай 3: INSERT в одну распределённую таблицу семейства MergeTree*
Аналогичен случаю 1 выше, но с одной особенностью:
- операция INSERT в таблицу движка Distributed не является транзакционной в целом, тогда как вставка в каждый шард — транзакционная
Случай 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 с snapshot isolation для конкурентных транзакций
- все ACID-свойства сохраняются даже в случае принудительного завершения или сбоя сервера
- для обеспечения надёжной фиксации вставок в типовой конфигурации должно быть включено либо insert_quorum для разных зон доступности (AZ), либо fsync
- «согласованность» в терминах ACID не охватывает семантику распределённых систем, см. https://jepsen.io/consistency; она управляется другими настройками (select_sequential_consistency)
- это объяснение не охватывает новую функциональность транзакций, которая позволяет использовать полнофункциональные транзакции над несколькими таблицами, материализованными представлениями, для нескольких SELECT и т. д. (см. следующий раздел о Transactions, Commit и Rollback)
Транзакции, фиксация (commit) и откат (rollback)
В дополнение к функциональности, описанной в начале этого документа, ClickHouse экспериментально поддерживает транзакции, фиксацию (commit) и откат (rollback).
Требования
- Разверните ClickHouse Keeper или ZooKeeper для отслеживания транзакций
- Только база данных типа Atomic (по умолчанию)
- Только нереплицированный движок таблицы 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, чтобы запрашивать эту таблицу.
Подробности
Ознакомьтесь с этой мета‑задачей, чтобы найти гораздо более обширные тесты и быть в курсе прогресса.