1. Начало проблемы: увеличение затрат на хранение
По мере увеличения срока эксплуатации сервиса объем хранения MongoDB также продолжал расти.
Согласно бизнес-требованиям, удалить уже созданные данные было невозможно, но хранение всех данных в общем хранилище начало сильно увеличивать затраты.
Особенно конкретные коллекции, ставшие объектом применения Online Archive, содержали ключевые данные сервиса, и данные продолжали накапливаться,Увеличенный до уровня примерно 1.2TBбыло.
В результате этого возникла ситуация, когда необходимо пересмотреть не только проблему простых затрат на хранение, но и саму стратегию долгосрочного управления данными.
В связи с этим было решено рассмотреть возможность переноса данных, которые устарели через определённый период времени, в отдельное хранилище, и было принято решение о внедрении MongoDB Online Archive.
- Данные, старше 365 дней после создания, будут перенесены в Online Archive. -
Эта метрика была скорее близка к операционной политике оптимизации затрат на хранение, чем тщательно спроектированному значению на основе анализа паттернов запроса.
Однако Online Archive имеет преимущество в снижении затрат на хранение, в то время как при запросе необходимо учитывать отдельную структуру расходов.
то есть,
Что архивировать?
не только,
Как просмотреть архивированные данные?
Это действительно была ситуация, в которой нужно было подумать вместе.
2. Проектирование Online Archive
Политика Archive была составлена следующим образом.
Критерий Archive: данные, прошедшие более 365 дней по полю time
Конструкция Partition: dataId → time
Основные паттерны запросов реального сервиса были следующими.
Полный запрос данных для конкретного dataId
В связи с этим был установлен dataId в качестве первичного ключа, чтобы можно было сгруппировать данные одного и того же dataId в первую очередь, а time был установлен в качестве вторичного ключа.
Тем самым мы стремились согласовать фактический паттерн запросов с политикой Archive.
Кроме того, в среде Online Archive запросы с учетом критериев Partition могут снижать объем сканируемых данных, поэтому это было признано важным элементом проектирования с точки зрения оптимизации затрат.
3. Стратегия индексации для эксплуатации Archive
Во время внедрения Archive мы не просто определили политику Archive, но и учли процесс выполнения Archive и фактические паттерны запросов для построения индексов.
3-1. Индекс для идентификации объектов Archive
{ time: 1, dataId: 1 }
В соответствии с политикой Archive необходимо было постоянно идентифицировать данные, прошедшие 365 дней после создания,
Для эффективной идентификации данных Archive был создан отдельный индекс.
3-2. Индекс для запроса после архива
Основной паттерн запроса сервиса был основан на полной выборке по dataId,
Партitions Online Archive также были настроены следующим образом.
{ dataId: 1, time: 1 }
В соответствии с этим, для случаев, когда данные архива запрашиваются вместе через объединенную точку доступа, был создан индекс в том же порядке, что и структура разделов.
Тем самым мы стремились поддерживать согласованность между фактическим паттерном запроса и структурой архива.
В общем, это выглядит следующим образом.
|
Цель |
Индекс |
|---|---|
|
Идентификация целевого архива |
{ time: 1, dataId: 1 } |
|
Объединенный запрос после архива |
{ dataId: 1, time: 1 } |
4. Существующий API для выборки большого объема данных
В нашем сервисе существует API, который возвращает все данные по конкретному идентификатору.
GET /data/{dataId}
Этот API не был простым API для запросов.
Не просто возвращая полученные данные, нам также пришлось выполнить обработку данных в соответствии с форматом ответа.
Запрос к MongoDB → обработка данных для ответа → возврат клиенту
Кроме того, распределение данных также было неравномерным.
|
Объем данных по dataId |
Количество |
|---|---|
|
В общем случае |
Десятки - тысячи записей |
|
Кейсы с большими объемами данных |
Максимум сотни тысяч записей |
То есть, даже для одного и того же API, для определенных dataId была необходима обработка больших объемов данных.
5. Существующий способ запроса
Ранее использовался метод повторного запроса, основанный на OFFSET.
Например, структура выглядела так.
LIMIT 1000 OFFSET 0
LIMIT 1000 OFFSET 1000
LIMIT 1000 OFFSET 2000 ...
В обычной среде MongoDB это не вызывало больших проблем.
Однако после внедрения Online Archive возникла необходимость снова проверить, подходит ли существующий метод запросов в среде Archive.
6. Причины пересмотра запросов на основе OFFSET
В среде Online Archive объем данных, обрабатываемых при сканировании, может влиять на расходы.
То есть,
Увеличение Data Scanned → Возможное увеличение стоимости запросов
необходимо учитывать эту зависимость.
Существующий запрос на основе OFFSET требует многократного поиска предыдущих данных, чтобы достичь желаемой позиции.
Например,
LIMIT 1000 OFFSET 90000
такой запрос требует пропуска предыдущих 90,000 записей, чтобы вернуть результаты.
В структуре, где большие объемы данных запрашиваются многократно, такие затраты на поиск возникают неоднократно.
В среде Archive было решено, что такие повторные поиски могут привести к увеличению Data Scanned.
OFFSET → Повторный запрос → Возникновение повторного поиска → Увеличение Data Scanned → Возможное увеличение стоимости запросов
В конечном итоге было решено пересмотреть существующую стратегию запросов на основе OFFSET.
7. Переход на запросы на основе курсора
В качестве нового метода запроса был выбран метод на основе курсора.
Мы настроили использование функции Stream в Spring Data MongoDB для последовательного потребления данных.
@Meta(cursorBatchSize = 3000)
Stream<DataDoc> streamByDataId(String dataId);
Также было применено значение cursorBatchSize.
Причиной использования batchSize в этом примере является необходимость потреблять большие объемы данных не загружая их в память одновременно, а по частям определенного размера.
Курсор → извлечение по пакетам → последовательное потребление → контроль использования памяти
По сравнению с предыдущей структурой это выглядит следующим образом.
OFFSET → повторные извлечения → повторная навигация Курсор → последовательные извлечения → поддержание потока одиночного извлечения
В среде Archive мы пришли к выводу, что эта структура также более подходящая с точки зрения оптимизации затрат.
8. Ретроспектива
Из этого опыта стало очевидно, что внедрение Online Archive — не просто процесс снижения стоимости хранения.
Если меняется стратегия хранения, стратегия извлечения также должна быть пересмотрена.
Особенно в средах, где структура затрат изменяется, не всегда можно считать, что существующий метод является оптимальным.
В этом случае необходимо учитывать политику Archive, структуру индексов, шаблон извлечений и стратегию извлечения.
Оптимизация стоимости хранения
→ Внедрение Online Archive
→ Проектирование разделов
→ Индексирование
→ Учет затрат на запросы
→ Пересмотр OFFSET
→ Переход на курсорное извлечение
В конце концов, этот случай не был просто рассказом о применении курсора.
Работа, начатая для оптимизации затрат на хранение, привела к размышлениям о затратах на запросы, и в процессе этого я пересмотрел существующую стратегию запросов.
Изменение инфраструктуры вызвало изменение стратегии запросов приложения, и через это я еще раз осознал, что стратегии хранения и запросов тесно связаны.
Ссылка
https://www.mongodb.com/docs/atlas/online-archive/
https://www.mongodb.com/docs/atlas/data-federation/billing/
https://www.mongodb.com/docs/manual/reference/method/cursor.skip/
yeop