Group Commit
Кратко Apache Doris Group Commit объединяет множество небольших операторов
INSERT VALUESили загрузок Stream Load в одну транзакцию на стороне сервера. Благодаря этому клиенты с частыми записями перестают перегружать FE разбором и планированием запросов, а BE мелкими rowset. Выберитеsync_mode, если загрузка должна ждать, пока данные станут видимыми, иasync_mode, если результат нужно вернуть сразу после надёжной записи строки в журнал упреждающей записи. С Group Commit та же нагрузка, которая приводила к ошибкам-235из-за перегрузки, достигает скорости более 100,000 строк в секунду на одном BE.

Зачем использовать Group Commit в Apache Doris?
Apache Doris Group Commit устраняет накладные расходы на каждую запись, которыми клиенты с частыми запросами нагружают планировщик FE и движок хранения BE. Построчные INSERT INTO ... VALUES и загрузки Stream Load крошечными пакетами используются для записи в Doris во многих реальных системах. Микросервис вызывает INSERT через JDBC каждый раз, когда пользователь на что-нибудь нажимает. Потребитель Kafka каждые несколько сотен миллисекунд отправляет всё, что успел накопить. Сборщик данных IoT передаёт каждое событие сразу после его поступления. Ни один из этих клиентов не может формировать более крупные пакеты, потому что следующих событий ещё нет. А без объединения в пакеты каждая загрузка открывает собственную транзакцию, отдельно проходит через планировщик FE и создаёт новую версию tablet. Именно такое сочетание создаёт проблемы для движка хранения Doris.
- Частые
INSERT VALUESисчерпывают ресурсы синтаксического анализатора и кеша планов FE раньше, чем ресурсы CPU на BE. - Небольшие загрузки Stream Load из потоковых конвейеров накапливают версии tablet, пока фоновая компакция не перестаёт справляться. Типичный симптом: ошибка
-235«слишком много сегментов». - Каждая загрузка становится отдельной транзакцией, которая тратит на согласование фиксации столько же времени, сколько на обработку самих данных.
Group Commit объединяет множество таких небольших записей в одну транзакцию на сервере, причём клиенту не нужно ничего об этом знать или учитывать.
Что такое Group Commit в Apache Doris?
Apache Doris Group Commit представляет собой серверный буфер для небольших записей. BE собирает строки из множества параллельных загрузок и фиксирует их в одной транзакции каждые несколько секунд или при заполнении буфера. Group Commit работает поверх INSERT INTO ... VALUES, Stream Load и подготовленных операторов JDBC, не меняя их публичный API. Он включается одним параметром: переменной сеанса для INSERT, HTTP-заголовком для Stream Load или свойством таблицы, задающим режим по умолчанию. Выбранный режим определяет момент возврата результата загрузки.
Основные термины
group_commit: переменная сеанса (для INSERT) и HTTP-заголовок (для Stream Load), определяющие режим. Значения:off_mode,sync_mode,async_mode.sync_mode: строки объединяются с данными параллельных загрузок на BE, а запрос блокируется, пока объединённая транзакция не будет зафиксирована и данные не станут видимыми.async_mode: строки записываются в журнал упреждающей записи на BE, запрос немедленно возвращает результат со статусомPREPARE, а объединённая транзакция фиксируется позже.WAL: отдельный для каждого BE журнал упреждающей записи, используемый вasync_mode. Имеет одну реплику и хранится на принимающем BE.group_commit_interval_msиgroup_commit_data_bytes: условия сброса буфера, задаваемые для каждой таблицы. Значения по умолчанию: 10s и 128 MB.
Как работает Group Commit в Apache Doris?
Apache Doris Group Commit направляет параллельные небольшие загрузки в общую очередь на BE для каждой таблицы, сбрасывает очередь по таймеру или при достижении порогового размера и фиксирует объединённый пакет как одну транзакцию FE.
- Создание очереди или присоединение к ней. Запрос поступает на BE. Вместо запуска новой транзакции BE помещает строки в
LoadBlockQueue, определяемую таблицей и текущей открытой транзакцией Group Commit. - Запись в WAL (только в асинхронном режиме). В
async_modeстроки также сохраняются в локальном WAL, поэтому запрос может вернуть результат сразу после их надёжной записи. Вsync_modeэтот шаг пропускается. - Ожидание условия сброса. BE сбрасывает очередь, когда истекает интервал
group_commit_interval_msили в очереди накапливается объём данныхgroup_commit_data_bytes. Оба свойства задаются для каждой таблицы. - Фиксация одной транзакции для всего пакета. BE передаёт объединённый пакет через движок хранения, а FE фиксирует ровно одну транзакцию. FE назначает одну метку Label с префиксом
group_commit_, общую для всех объединённых загрузок. - Возврат результата. Запросы
sync_modeдо этого момента оставались заблокированными и теперь возвращают результат. Запросыasync_modeуже вернули результат ранее; на этом этапе данные становятся доступны для запросов.
Если запрос соответствует условию перехода на обычный путь загрузки (явная транзакция, заданная пользователем метка Label, обновление части столбцов, выражения в VALUES, нехватка места на диске для WAL в async_mode), Doris автоматически использует обычный путь для этого запроса. Решение определяется только формой запроса.
Быстрый старт
CREATE TABLE events (
id BIGINT, ts DATETIME, payload STRING
)
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 4
PROPERTIES ("group_commit_interval_ms" = "1000");
SET group_commit = async_mode;
INSERT INTO events VALUES (1, NOW(), 'a');
INSERT INTO events VALUES (2, NOW(), 'b');
-- the second insert merges into the first one's transaction
Ожидаемый результат
Query OK, 1 row affected (0.01 sec)
{'label':'group_commit_a145ce07f1c972fc-bd2c54597052a9ad', 'status':'PREPARE', 'txnId':'181508'}
Обе вставки возвращают одинаковые label и txnId, что указывает на их объединение. Строки не видны, пока BE не сбросит буфер (в этом примере через секунду, поскольку для таблицы задано свойство group_commit_interval_ms со значением 1000). Для Stream Load замените переменную сеанса заголовком: -H "group_commit:async_mode".
Когда стоит использовать Group Commit в Apache Doris?
Используйте Apache Doris Group Commit, когда множество параллельных клиентов записывают небольшие пакеты и увеличить их размер на стороне клиента невозможно.
Подходящие сценарии
- Микросервисы, выполняющие
INSERT INTO ... VALUESдля каждого события через JDBC с частотой в десятки TPS и выше. - Приёмники Kafka или Flink, которые могут формировать только пакеты размером меньше мегабайта и сталкиваются с ошибками
-235на BE. - Конвейеры IoT или потоков кликов, в которых каждое событие должно поступить в течение нескольких секунд, но объединить клиентов невозможно.
- Таблицы, в которых частое появление новых версий tablet из-за отдельных загрузок перегружает фоновую компакцию.
Неподходящие сценарии
- Загрузки, которые должны выполняться строго в одной транзакции с учётными операциями вызывающего кода. Group Commit автоматически переходит на обычный путь загрузки при использовании явного
BEGIN ... COMMIT. Для транзакционных приёмников используйте непосредственно транзакции загрузки. - Stream Load 2PC и записи с собственной меткой Label. Оба варианта обходят Group Commit; если нужна семантика exactly-once с контрольными точками, продолжайте использовать Stream Load 2PC.
- Обновления части столбцов. Group Commit не поддерживает
partial_columns: trueи переходит на обычный путь загрузки. - Таблицы Unique Key, которым требуется строгое соблюдение порядка фиксации. Group Commit не сохраняет порядок между объединёнными загрузками; задайте
function_column.sequence_col, чтобы актуальная версия определялась по временной метке, предоставленной пользователем. - Загрузки, пакеты которых уже достаточно велики (сотни MB и больше). По сравнению с обычной загрузкой координация Group Commit создаёт лишнюю работу. Просто отправьте загрузку напрямую.
Производительность / показатели
Из примечаний к выпуску Apache Doris 2.1.0:
- JDBC, 1 FE + 1 BE, TPC-H SF10 Lineitem, параллелизм 20, менее 100 строк на вставку: 106,900 строк/с в
async_mode. - Stream Load, 3 BE, параллелизм 10, пакеты меньше 1 MB: 810,000 строк/с, 104 MB/с. Без Group Commit та же нагрузка приводит к ошибкам
-235и остановке загрузки. - Stream Load, 3 BE, пакеты по 1 MB при параллелизме 30: 2,077,723 строк/с.
Источник: примечания к выпуску Apache Doris 2.1.0.
Дополнительные материалы
- Оптимизация загрузки при высоком параллелизме (Group Commit)
- Справочник HTTP-заголовков Stream Load
- Загрузка с помощью INSERT INTO
- Транзакции загрузки: когда нужны явный
BEGIN ... COMMITили 2PC - Stream Load: синхронный способ загрузки по HTTP, запросы которого Group Commit объединяет в пакеты на стороне сервера.
- Apache Doris 2.1.0: тесты производительности Group Commit
- Unique Key: модель таблиц с частыми однострочными UPDATE, которые и призван объединять в пакеты Group Commit.