Перейти к содержимому
Последнее обновление

Compaction

Doris записывает данные через структуру, похожую на LSM-Tree, и в фоновом режиме непрерывно объединяет небольшие файлы в большие упорядоченные файлы с помощью Compaction. Compaction обрабатывает такие операции, как удаление и обновление.

Правильная настройка стратегии Compaction может значительно повысить эффективность загрузки и запросов. Doris предоставляет следующие стратегии Compaction для настройки:

Vertical compaction​

Vertical compaction — новый алгоритм Compaction, реализованный в Doris 1.2.2 и предназначенный для оптимизации эффективности выполнения Compaction и затрат ресурсов в сценариях с большими широкими таблицами. Он может существенно снизить накладные расходы памяти Compaction и повысить скорость её выполнения. Результаты тестирования показывают, что потребление памяти при Vertical compaction составляет лишь 1/10 от исходного алгоритма Compaction, а скорость Compaction увеличивается на 15%.

В Vertical compaction объединение по строкам заменяется объединением по группам столбцов. Гранулярность каждого объединения меняется на группу столбцов, что уменьшает объем данных, участвующих в одной операции Compaction, и снижает использование памяти во время Compaction.

Конфигурация BE:

  • enable_vertical_compaction = true включает Vertical compaction
  • vertical_compaction_num_columns_per_group = 5 — количество столбцов в каждой группе столбцов; согласно тестам, группа из 5 столбцов по умолчанию обеспечивает более удачное сочетание эффективности и использования памяти
  • vertical_compaction_max_segment_size используется для настройки размера дискового файла после Vertical compaction; значение по умолчанию — 268435456 (байт)

Segment compaction​

Segment compaction в основном предназначена для загрузки больших объемов данных. Segment compaction выполняется во время загрузки и объединяет сегменты внутри задания, в отличие от обычной Compaction и Vertical compaction. Этот механизм эффективно сокращает количество создаваемых сегментов и помогает избежать ошибок -238 (OLAP_ERR_TOO_MANY_SEGMENTS).

Segment compaction имеет следующие особенности:

  • уменьшает количество сегментов, создаваемых при загрузке
  • процесс объединения выполняется параллельно загрузке, поэтому время загрузки не увеличивается
  • во время загрузки увеличиваются потребление памяти и вычислительные ресурсы, но рост относительно невелик, поскольку нагрузка равномерно распределяется по длительному процессу загрузки
  • данные после Segment compaction получают преимущества по ресурсам и производительности при последующих запросах и обычной Compaction

Конфигурация BE:

  • enable_segcompaction=true включает эту функцию
  • segcompaction_batch_size используется для настройки интервала объединения. Значение по умолчанию 10 означает, что Segment compaction запускается после каждых 10 файлов сегментов. Рекомендуется задавать значение от 10 до 30. Большее значение увеличивает использование памяти Segment compaction.

Ситуации, в которых рекомендуется Segment compaction:

  • Загрузка больших объемов данных завершается ошибкой OLAP_ ERR_ TOO_ MANY_ SEGMENTS (errcode - 238). В этом случае рекомендуется включить Segment compaction, чтобы сократить количество сегментов в процессе загрузки.
  • Во время загрузки создается слишком много небольших файлов: хотя объем загружаемых данных разумен, большое количество небольших файлов сегментов также может привести к сбою задания загрузки из-за низкой кардинальности или ограничений памяти, из-за которых memtable преждевременно сбрасывается. В этом случае рекомендуется включить эту функцию.
  • Запрос сразу после загрузки. Когда загрузка только что завершена, а стандартная Compaction ещё не завершилась, большое количество файлов сегментов снижает эффективность последующих запросов. Если нужно выполнять запрос сразу после загрузки, рекомендуется включить эту функцию.
  • Высокая нагрузка на обычную Compaction после загрузки: Segment compaction равномерно переносит часть нагрузки обычной Compaction в процесс загрузки. В этом случае рекомендуется включить эту функцию.

Ситуации, в которых Segment compaction не рекомендуется:

  • Если сама операция загрузки уже исчерпала ресурсы памяти, Segment compaction использовать не рекомендуется, чтобы не усиливать давление на память и не приводить к сбою задания загрузки.

Дополнительные сведения о реализации и результатах тестирования см. в этой ссылке.

Стратегия Compaction​

Стратегия Compaction определяет, когда и какие небольшие файлы объединяются в более крупные. В настоящее время Doris предлагает две стратегии Compaction, задаваемые параметром compaction_policy в свойствах таблицы.

Стратегия Compaction на основе размера​

Стратегия Compaction на основе размера является стратегией по умолчанию и подходит для большинства сценариев.

"compaction_policy" = "size_based"

Стратегия Compaction для временных рядов​

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

"compaction_policy" = "time_series"

Стратегия Compaction для временных рядов запускается при выполнении любого из следующих условий:

  • Размер необъединённых файлов превышает time_series_compaction_goal_size_mbytes (по умолчанию 1 GB).
  • Количество необъединённых файлов превышает time_series_compaction_file_count_threshold (по умолчанию 2000).
  • Время с момента последней Compaction превышает time_series_compaction_time_threshold_seconds (по умолчанию 1 час).

Эти параметры задаются в PROPERTIES таблицы; их можно указать при создании таблицы или изменить позже с помощью:

ALTER TABLE table_name SET("name" = "value");

Управление параллелизмом Compaction​

Compaction выполняется в фоновом режиме и потребляет ресурсы CPU и IO. Потребление ресурсов можно контролировать, изменяя число одновременно работающих потоков Compaction.

Число параллельных потоков Compaction настраивается в конфигурационном файле BE; доступны следующие параметры:

  • max_base_compaction_threads: число потоков base compaction, по умолчанию 4.
  • max_cumu_compaction_threads: число потоков cumulative compaction, по умолчанию -1, то есть 1 поток на диск.

Накладные расходы памяти Compaction для больших MOW Tablet​

Таблицы Unique Key, использующие merge-on-write (MOW), во время Compaction поддерживают в памяти карту преобразования rowid (rowid conversion map). Эта карта связывает расположение строк во входных Rowset с их новыми расположениями в выходном Rowset, чтобы можно было обновить delete bitmap. Для Tablet с большим числом строк, особенно при Base Compaction, включающей большие объемы исторических данных, карта может потреблять значительный объем памяти и привести к сбою Compaction при нехватке памяти.

Как использование памяти растёт с числом строк​

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

Main mapping storage ≈ Total physical input rows participating in this compaction × 8 bytes

Физические входные строки включают исторические версии, которые Compaction ещё не удалила. Даже если старая строка помечена как удалённая и не будет записана в выходной Rowset, заранее выделенная запись всё равно занимает память. Поэтому число действительных строк, возвращаемых запросом, нельзя напрямую подставлять вместо числа физических входных строк в этой оценке. Карта хранится до завершения задачи Compaction и не освобождается после каждого пакета чтения.

Эта оценка охватывает только основное хранилище карты. Фактическое потребление памяти Compaction также включает накладные расходы контейнеров, буферы чтения и записи и индексы. Фиксированного соотношения между сжатым размером данных Tablet и числом физических строк нет. Поэтому узкая таблица или таблица с высокой степенью сжатия может потребовать большую карту, даже если её размер на диске относительно мал.

Расчётный пример​

Предположим, что базовый Rowset MOW Tablet содержит 1 миллиард физических строк, а эта Base Compaction также объединяет инкрементальные Rowset, содержащие 100 миллионов физических строк. Даже если все 100 миллионов инкрементальных строк обновляют существующие ключи и в выходных данных остаётся только 1 миллиард действительных строк, карта всё равно выделяется для 1.1 миллиарда физических входных строк:

Physical input rows = 1 billion + 100 million = 1.1 billion
Main mapping storage ≈ 1.1 billion × 8 bytes = 8.8 × 10^9 bytes ≈ 8.2 GiB

Если тот же BE одновременно выполняет четыре задачи Compaction с таким размером входных данных, только основное хранилище этих карт использует примерно 32.8 GiB. Это не включает другую память Compaction и память, используемую запросами, загрузками и другими задачами. Это расчётный пример; фактическое использование зависит от размера входных данных каждой задачи и параллелизма.

Устранение неполадок и меры снижения нагрузки​

  • При создании таблицы или добавлении партиций выбирайте число партиций и бакетов с учетом ожидаемого количества строк и сжатого размера данных. Выбирайте ключи бакетов, равномерно распределяющие данные, чтобы отдельный Tablet не накапливал слишком много строк. См. Бакетирование данных. Число бакетов существующей партиции нельзя изменить напрямую; для уже существующего слишком крупного Tablet рассмотрите пересоздание таблицы и перенос данных.
  • При ограниченной памяти рассмотрите снижение параллелизма Base Compaction, чтобы оставить больше памяти для каждой задачи. Это лишь уменьшает общий пик памяти нескольких задач на одном BE; размер карты отдельной задачи не уменьшается. Если одна карта уже превышает доступную память, одного снижения параллелизма может быть недостаточно.
  • Vertical compaction, меньшее значение compaction_batch_size или меньшее число столбцов в vertical_compaction_num_columns_per_group могут уменьшить память, используемую для чтения и обработки групп столбцов, но не уменьшают размер полной карты rowid. compaction_memory_bytes_limit используется для оценки размера пакета чтения и не устанавливает жесткий предел для карты rowid или всей задачи Compaction.