Как подсчитать размер объектов OSS по каталогу

облачные вычисления

С непрерывным развитием облачных сервисов все больше и больше ресурсов хранится в облаке. Объектное хранилище является одним из широко используемых методов хранения, таких как OSS от Alibaba Cloud, BOS от Baidu Cloud и S3 от Amazon. Хотя для пользователей он более удобен в использовании, для разработчиков он часто ограничен SDK и сталкивается со многими проблемами. Например, такая, казалось бы, простая функция, как подсчет размера объектов OSS, выглядит так.

Деловая сцена

Некоторые файлы проекта компании хранятся в OSS Alibaba Cloud, и размер хранимых объектов необходимо подсчитывать в соответствии с каталогом, чтобы рассчитать стоимость хранения и оценить стоимость нисходящего трафика. Эти объекты имеют следующие 3 характеристики: 1 большой. Их число превышает один миллион и будет продолжать расти бесконечно. 2 Модификаций немного. После загрузки есть большая вероятность, что модификация не будет произведена. 3 цикла мало. Объекты хранятся только 3 месяца и автоматически удаляются через 3 месяца.

Проблемы с SDK

Alibaba Cloud SDK напрямую не предоставляет API-функции для статистики по папкам, но должен передаватьListObjectsфункция для перечисления размера каждого объекта, а затем выполнять ручную статистику.

оListObjectsФункция и ее параметры запроса показаны на следующем рисунке.

Информация в описании более подробная, но параметров не так много.Подводя итог, можно выделить следующие моменты:

  1. Количество возвращаемых записей может быть установлено для каждого запроса, и максимальное значение равно 1000.
  2. Если перечисление не может быть завершено за один раз, оно вернет значение NextMarker, которое можно использовать в качестве параметра Marker в запросе для получения данных следующей страницы.
  3. Вы можете перечислить объекты в каталоге и подкаталогах, установив параметр Prefix.
  4. Каталоги можно перечислить с помощью параметра Delimiter.

То есть,ListObjectsФункция аналогична итератору, при большом количестве объектов ее можно запрашивать только один за другим через метку пейджинга. Представьте, что если есть 100 000 объектов, требуется не менее 100 вызовов, каждые 2-3 секунды, и это занимает от 3 до 5 минут. Однако количество наших проектов в настоящее время невелико, около 1,2 миллиона, а общее время будет достигать 40-60 минут, что слишком долго! Специально для программ функциональных вычислений, развернутых в облаке, 10 минут уже истекли.

Как оптимизировать работу со статистикой запросов?

Что касается идеи оптимизации производительности интерфейса, то обычно существует три типа решений:

1 сжатие Например, протокол HTTP использует сжатие gzip для возврата данных. Поскольку функция API не предоставляет полей фильтра или параметров сжатия, размер возвращаемых данных неизменен, и сжатие не работает.

2 сплит Разделение можно разделить на две категории в зависимости от цели: одна — это задержка данных запроса, например, внешние компоненты маршрутизации с отложенной загрузкой, а другая — параллелизм, например, загрузка больших файлов по частям.

Ленивая загрузка не имеет значения для статистики файла и не уменьшает конечное время потребления.

Использование параллелизма теоретически может сократить время запроса интерфейса, но в работе возникнут некоторые проблемы, т.к.ListOjectsФункция использует метод итератора, и каждый запрос зависит от предыдущего результата.NextMarkerзначение, этот параметр заставляет запрос стать последовательной операцией.

3 Кэш Кэши, как правило, могут быть оптимизированы для многократного повторения операций, потому что результат сразу же доступен при попадании в кэш. Например, надежный внешний кеш и кеш согласования.

Кешировать результаты запроса напрямую не имеет смысла, потому чтоListObjectsФункция не предоставляет механизм оценки, аналогичный протоколу HTTP, для проверки достоверности кеша.ListObjectsфункция проверки достоверности кеша.

Но разве кэширование вообще не имеет смысла? Конечно нет~

Разделить и кэшировать

Если параметры каждого запроса кэшируются (в основномNextMarker), то параллельные запросы могут быть реализованы при повторном запросе. Конкретные идеи реализации заключаются в следующем:

  1. При первом запросе запрос выполняется постранично, когда количество объектов в каталоге превышает 1000, текущие параметры запроса кэшируются в соответствии с каталогом. Когда он меньше 1000, пейджинг не будет генерироваться, и параметр кэша не имеет большого значения.
  2. При повторном запросе сначала получите кэшированный объект. Запросить, есть ли у каждого каталога параметры кеша. Если он существует, выполнить параллельный запрос в соответствии с параметрами кеша. Если он не существует, запросить напрямую.
  3. При возврате результатов и параметров кэшированияNextMarkerКогда значения несовместимы, подтверждается, что файл изменился, текущий результат параллельного запроса отбрасывается, и запрос повторяется один за другим.
  4. Для каждого результата запроса, если количество объектов превышает 1000, параметры кэша обновляются.

Чтобы еще больше сократить возможности параллелизма вычислений функций Alibaba Cloud, были приняты две меры:

  1. Перешел с Python на Node.js. Учитывая, что проект может быть передан коллегам из бэкенда для обслуживания, был выбран Python, но производительность параллелизма потоков и сопрограмм Python не так хороша, как у Node.js, а рабочая нагрузка многопроцессорности относительно велика, поэтому был изменен на Node.js.
  2. Неограниченный параллелизм. Читать все параметры кеша, а потом вызывать их по отдельностиListObjectsфункцию и, наконец, вернуть результаты.

Но после параллельного выполнения выдавалась ошибка, аналогичная следующему разбору XML (потому что ошибок было слишком много, поэтому они были перехвачены).

Error: Unclosed root tag
Line: 1284
Column: 8
Char:
raw xml: <?xml version="1.0" encoding="UTF-8"?>
......

Учитывая, что принцип реализации функции API заключается в преобразовании XML-строки, полученной через HTTP-запрос, сначала в XML, затем в JSON-данные и возвращении, можно предположить, что возвращаемая XML-строка является неполной, в результате в случае сбоя при анализе объекта XML.

Таким образом, он был изменен, чтобы запрашивать только каталог, в котором сообщалось об ошибке статистики, но ошибки не возникало.

Мне пришлось ввести исходный код SDK для отладки точки останова, и, наконец, я обнаружил, что тайм-аут запроса вызвал ошибку.

Основная причина заключается в том, что слишком много параллелизма заставляют очереди ждать результатов ответа, поэтому время ожидания истекает, но это сообщение об ошибке слишком вводит в заблуждение. . .

Параллелизм и очереди

Для решения проблемы ожидания в очереди решение тоже очень простое, т.Контролируйте количество параллелизма.

Как это контролировать? Очередь задач создается на основе цикла событий движка JavaScript.

Если очередь задач не пуста, она постоянно опрашивается.

Когда количество выполненных задач не достигает верхнего предела, выполнение задачи прекращается, а счетчик увеличивается на 1.

Счетчик уменьшается на единицу после выполнения задачи. Основной код выглядит следующим образом:

function schedule() {
  /* running 计数器,记录当前执行的任务数
   * concurrency 并发数限制
   */
  while(queue.length > 0 && running < concurrency) {
    running++
    // queue 任务队列
    let task = queue.shift()
    // singleList 函数基于 API 函数的封装
    singleList.call(null, task.params, task.key)
    .then(task.resolve, task.reject)
    .finally(() => {
      running--;
      //
      if(queue.length > 0) timeout = setTimeout(schedule, 0)
      console.info('waiting:', queue.length, 'running:', running)
    })
  }
}

Окончательный результат выполнения в Alibaba Cloud Function Compute подсчитывает 1,2 миллиона объектов и записывает их в базу данных, что занимает 69 секунд и занимает 962 МБ памяти.

Duration: 69451.69 ms, Billed Duration: 69500 ms, Memory Size: 3072 MB, Max Memory Used: 962.17 MB

В настоящее время эта производительность уже может соответствовать бизнес-требованиям: даже если количество файлов увеличится на порядок, выполнение может быть завершено в течение 10 минут (максимальный тайм-аут Alibaba Cloud Function Compute — 600 секунд).

оптимизация

Теоретически время также можно сократить, увеличив количество параллелизма. Конкретные идеи: Настройте основной процесс и назначьте задачи различным процессам для выполнения, тем самым еще больше увеличив возможности параллелизма. Метод распределения может быть распределен по количеству объектов, например, процесс выделяется для каждых 100 задач.


Оригинальная ссылка:Специальность.Дай ему файл trumpet.com/OSS.Контракт…Информация об авторе:Чжу Делонг, а будущий старший фронтенд-инженер.