В потоковом хранилище данных за сутки образуются тысячи мелких файлов. Какой механизм уменьшит издержки их обработки?
Нужна периодическая компакция: объединение множества мелких файлов в меньшее число крупных файлов с тем же логическим содержимым. Это снижает накладные расходы на открытие файлов, чтение метаданных и планирование запросов, но требует дополнительного вычислительного ресурса и корректной публикации результата.
Файловые аналитические хранилища появились как способ дешёво хранить большие объёмы данных и независимо масштабировать хранение и вычисления. Потоковая запись создаёт новые файлы часто и небольшими порциями, поскольку системе важно быстро зафиксировать поступившие данные, а не ждать накопления большого объёма.
Так возникает конфликт между низкой задержкой записи и эффективностью последующего чтения. Компакция появилась как фоновый механизм, который устраняет последствия дробной записи, не заставляя потоковый контур жертвовать оперативностью.
Каждый файл обычно требует обработки метаданных: его нужно найти, проверить доступность, определить подходящий диапазон данных и включить в план выполнения запроса. При тысячах мелких файлов эти накладные расходы могут стать сопоставимыми с затратами на чтение самих данных.
Кроме того, мелкие файлы хуже используют последовательное чтение и могут приводить к большому числу операций ввода-вывода. Запрос, которому нужен небольшой диапазон данных, иногда вынужден просматривать метаданные и открывать множество объектов, даже если общий объём полезных данных невелик.
Если бесконтрольно запускать компакцию, она начнёт конкурировать с потоковой записью и аналитическими запросами. Поэтому неверно считать, что любое уменьшение числа файлов автоматически улучшает систему: важны размер файлов, частота запуска, партиционирование и нагрузка на вычислительный контур.
Компактор выбирает группу небольших файлов, читает их логическое содержимое, объединяет записи в более крупные файлы и публикует новую версию набора данных. Старые файлы удаляются или помечаются для последующей очистки только после того, как система гарантирует, что активные читатели больше не используют их.
Размер целевых файлов выбирают компромиссно. Слишком маленькие файлы сохраняют проблему большого количества объектов, а слишком крупные ухудшают параллелизм и могут заставить запрос читать больше данных, чем ему нужно. Универсального размера нет: он зависит от формата, характера запросов, размера партиций и возможностей хранилища.
Компакцию обычно ограничивают одной или несколькими партициями, чтобы не переписывать весь набор данных. Полезно отделять часто изменяемые «горячие» партиции от редко меняющихся «холодных»: первые компактируют чаще, вторые — реже или только по расписанию.
Критически важна атомарная публикация. Читатель не должен увидеть только часть результата компакции или одновременно смешать несовместимые версии файлов. Обычно сначала создают новые файлы, затем одним согласованным изменением обновляют описание активного набора, а физическое удаление старых объектов выполняют позднее.
Компакция не исправляет плохое партиционирование и не заменяет управление схемой. Если записи распределяются по чрезмерному числу партиций или запросы не используют выбранный ключ, число файлов и объём чтения могут оставаться большими даже после объединения файлов.
Поток событий записывал данные в объектное хранилище каждые несколько секунд. За сутки в каждой часовой партиции появлялись тысячи файлов, и аналитические запросы стали заметно замедляться из-за большого числа операций чтения метаданных.
Рассматривались два варианта. Увеличить интервал накопления перед записью было бы проще и уменьшило бы число файлов, но повысило бы задержку появления данных и риск потери большего объёма при сбое. Полностью переписывать весь набор каждую ночь обеспечило бы хорошие размеры файлов, но создало бы избыточную нагрузку и длинное окно обработки.
Выбрали фоновую компакцию: новые данные продолжили записываться небольшими порциями, а завершённые часовые партиции периодически объединялись. Публикация новых файлов выполнялась атомарно, старые версии удалялись с задержкой, достаточной для завершения чтений. Это уменьшило число объектов и ускорило запросы без отказа от потоковой задержки; платой стали дополнительные вычислительные расходы и необходимость контролировать конкуренцию компакции с записью.
Вопрос: Может ли компакция ухудшить задержку потоковой обработки?
Ответ: Да. Она конкурирует за вычислительные ресурсы, сетевую пропускную способность и операции ввода-вывода с записью и чтением. Если компактор запускается без ограничения параллелизма или обрабатывает активно изменяемые партиции, поток может начать отставать. Поэтому задают бюджет ресурсов, приоритеты и критерии запуска, например минимальное число мелких файлов или допустимый возраст партиции.
Вопрос: Почему простого удаления исходных мелких файлов сразу после компакции недостаточно безопасно?
Ответ: Читатель мог начать работу со старой версией набора и всё ещё ссылаться на исходные файлы. Немедленное удаление способно привести к ошибке чтения или к неполному результату. Безопасная схема разделяет логическую публикацию новой версии и физическую очистку старых объектов; очистка выполняется после истечения периода, в течение которого старые снимки могут использоваться.
Вопрос: Почему компакция не гарантирует ускорение запроса, фильтрующего узкий диапазон данных?
Ответ: Объединённый файл может содержать широкий диапазон значений и плохо соответствовать фильтру запроса. Тогда чтение одного крупного файла окажется дороже, чем чтение нескольких небольших файлов с эффективным пропуском по метаданным. Поэтому при компакции учитывают порядок данных, статистику, партиционирование и типичные предикаты; цель — не только уменьшить число файлов, но и сохранить эффективное исключение ненужных данных.