Compaction
Doris записывает данные через структуру, аналогичную LSM-Tree, и в фоновом режиме непрерывно объединяет небольшие файлы в большие упорядоченные файлы с помощью Compaction. Compaction обрабатывает такие операции, как удаление и обновление.
При правильной настройке стратегии Compaction можно значительно повысить эффективность загрузки данных и запросов. Doris предоставляет следующие стратегии Compaction для настройки:
Vertical compaction
Vertical compaction — новый алгоритм Compaction, реализованный в Doris 1.2.2 и предназначенный для повышения эффективности выполнения Compaction и снижения накладных расходов на ресурсы в крупномасштабных сценариях и сценариях с широкими таблицами. Он позволяет существенно сократить потребление памяти Compaction и повысить скорость выполнения Compaction. Результаты тестов показывают, что потребление памяти при Vertical compaction составляет лишь 1/10 от исходного алгоритма Compaction, а скорость Compaction увеличивается на 15%.
В Vertical compaction объединение по строкам заменяется объединением по группам столбцов. Гранулярность каждой операции объединения становится равной группе столбцов, что уменьшает объем данных, участвующих в одной операции Compaction, и снижает использование памяти во время Compaction.
Конфигурация BE:
enable_vertical_compaction = trueвключает Vertical compactionvertical_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 только один раз, что уменьшает write amplification из-за повторяющегося 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 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 и количеством его физических строк нет фиксированного соотношения. Поэтому узкая таблица или таблица с высоким коэффициентом сжатия может потребовать большую карту, даже если ее размер на диске относительно мал.
Пример расчета
Предположим, что Base Rowset MOW Tablet содержит 1 млрд физических строк, а этот Base Compaction также объединяет инкрементальные Rowset, содержащие 100 млн физических строк. Даже если все 100 млн инкрементальных строк обновляют существующие ключи и выходной Rowset содержит только 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 одновременно выполняются 4 задания Compaction с таким размером входных данных, только основное хранилище этих карт использует примерно 32.8 GiB. Сюда не входят другая память Compaction, а также память, используемая запросами, загрузками и другими заданиями. Это расчетный пример; фактическое использование зависит от размера входных данных каждого задания и параллелизма.
Устранение неполадок и способы снижения нагрузки
- При создании таблицы или добавлении разделов выбирайте количество разделов и bucket на основе ожидаемого количества строк, а также сжатого размера данных. Выбирайте ключи bucket, равномерно распределяющие данные, чтобы один Tablet не накапливал слишком много строк. См. раздел Data Bucketing. Количество bucket существующего раздела нельзя изменить напрямую; для существующего слишком большого Tablet рассмотрите пересоздание таблицы и перенос данных.
- При ограниченной памяти рассмотрите снижение параллелизма Base Compaction, чтобы оставить больше памяти для каждой задачи. Это уменьшает только совокупный пик памяти нескольких задач на одном BE; размер карты отдельной задачи не уменьшается. Если одна карта уже превышает доступный объем памяти, одного снижения параллелизма может быть недостаточно.
- Vertical compaction, меньшее значение
compaction_batch_sizeили меньшее количество столбцов вvertical_compaction_num_columns_per_groupмогут уменьшить память, используемую для чтения и обработки групп столбцов, но не уменьшают размер полной rowid map.compaction_memory_bytes_limitиспользуется для оценки размера пакета чтения и не устанавливает жесткий предел для rowid map или всей задачи Compaction.