Обновление сервиса изображений аватаров: удаление прокси-метода

С философией Discourses 1RTT я думаю, что, возможно, пришло время переписать код отдачи изображений аватаров.

Изображения аватаров должны обрабатываться как любые другие загружаемые изображения: изменяться в размерах при загрузке, сохраняться и отдаваться напрямую из файловой системы/S3/CDN.

Текущий метод Discourse использует прокси-подход для отдачи изображений аватаров. Такой подход создаёт лишние HTTP-круговые запросы и проблемы с IP-адресами.

Вот обзор запросов к аватарам:

  • Отрисовывается начальный HTML-код Discourse.
  • Браузер обнаруживает изображение аватара и запрашивает его у сервера Discourse.
  • Сервер Discourse выступает в роли прокси и запрашивает изображение из локального хранилища файлов/S3/CDN.
  • Сервер Discourse получает изображение.
  • Сервер Discourse отправляет изображение в браузер.

Для каждого пользовательского аватара требуется один дополнительный HTTP-круговой запрос и соответствующее время обработки на сервере. Типичная тема или список тем могут содержать более 30 пользовательских изображений аватаров. На моём сайте это приводит к 10 000–20 000 дополнительных RTT и связанной с этим нагрузке на сервер в день, которых можно избежать.

Кроме того, изображения аватаров запрашиваются напрямую с сервера. Для реализации защиты на уровне CDN необходимо добавлять IP-адреса в белый список. Это требует добавления в белый список шлюзов, а не IP-адресов серверов. Хостинг-компании регулярно вносят изменения для балансировки сетевого трафика. Мой IP-адрес шлюза будет меняться/эволюционировать. Программное обеспечение не должно зависеть от обновления IP-адреса для корректной работы базовых изображений аватаров. Это основано на следующем инциденте в поддержке: Avatar Proxy and CDN Hot-Link Protection.

С точки зрения производительности и простоты, можем ли мы обеспечить отдачу изображений аватаров напрямую из назначенного файлового хранилища Discourse?

5 лайков

Действительно, это очень запутанная часть приложения, @LotusJeff.

Чтобы устранить некоторые из её недостатков, мы недавно разработали способ сократить эти циклы запросов в нашем хостинге, но, кажется, мы так и не задокументировали это здесь. Есть ли какая-либо публичная документация об этом, @david?

4 лайка

Да, у нас есть глобальная настройка GlobalSetting, которую можно включить, установив переменную окружения DISCOURSE_REDIRECT_AVATAR_REQUESTS=true

В этом случае запросы аватаров будут обслуживаться не через прокси, а с помощью редиректа 302 на файловое хранилище.

Само по себе… это не очень хорошая идея. Это означает, что браузеры будут выполнять два полных HTTP-круговорота для каждого аватара. Поэтому, хотя это может решить вашу проблему с «защитой от хотлинкинга»… я бы не рекомендовал включать эту настройку. Это ухудшит опыт ваших пользователей.

Мы используем эту настройку на нашем хостинге discourse.org. Однако мы дополняем её функцией Lambda, работающей на нашем CDN Cloudfront. Она обнаруживает редирект 302 и сама выполняет проксирование. По сути: мы переносим проксирование с наших серверов приложений на CDN.

Что касается более общего вопроса «можно ли изменить аватары так, чтобы они ссылались напрямую на ресурс». Это сложно, потому что URL-адреса аватаров уже встроены во все исторические сообщения (например, в цитаты). Динамические URL-адреса /user-avatar/ позволяют нам сохранять работоспособность этих ссылок, когда пользователь меняет свой аватар. Боюсь, у нас нет планов менять эту систему.

Если существует простой и малорисковый способ заставить существующее проксирование работать для вашего случая использования (например, добавить глобальную настройку, которая добавляет определённый HTTP-заголовок в любые запросы на проксирование аватаров), то мы могли бы рассмотреть возможность принятия PR с таким изменением.

3 лайка

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

Единственная помощь, которую я могу оказать сейчас, — это использовать свои старые навыки бизнес-аналитика и менеджера по разработке. Поэтому, в духе желания быть полезным, вот мои мысли.

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

Одно из таких предположений — сохранение обновленного изображения аватара под новым именем файла. У человека есть только один аватар. Мы не храним записи имен аватаров. Я предлагаю, чтобы при обновлении изображения аватара оно сохранялось с тем же именем файла, что и существующий аватар. По сути, именно это и делает ссылка /user-avatar/. Вместо использования обходного пути, реализуйте эту логику при создании/обновлении аватара. Это решит проблемы с историческими постами для будущих «запеченных» постов.

Является ли это масштабным изменением «большого взрыва»? Нет, это изменение можно внедрять в течение нескольких месяцев, постепенно улучшая производительность сайта. Мои команды разработчиков всегда имели список возможностей для оптимизации кода для каждого блока кода. Мы хотели внести эти улучшения, но они не были критичными для выполнения по отдельности. Когда код открывался для разработки по какой-либо другой причине, разработчик также вносил эти оптимизационные изменения. Это минимизировало наше тестирование и количество ошибок за счет сокращения количества раз, когда код открывался и обновлялся.

Я бы разбил этот проект на следующие этапы:

  1. Обновить логику сохранения изображения аватара, чтобы заменять любые обновления изображений, используя текущее имя файла.
  2. Заменить все использования изображений аватаров на стандартную функцию, использующую предпочтительную систему хранения/доставки файлов Discourse. Это можно внедрять в течение нескольких месяцев, постепенно переходя к новой логике отображения изображений аватаров.
  3. После завершения первых двух этапов предоставить сообществу инструкции и фрагменты кода для замены и повторной «запекания» исторических изображений аватаров в «запеченном» HTML в их предпочтительную файловую систему. Реализовать это будет на усмотрение владельцев отдельных сайтов Discourse. (Эти инструкции и фрагменты кода будут полезны для внесения изменений в сырой HTML).

Я уверен, что вы уже рассмотрели всё это. Я также знаю, что исправление старого кода никогда не попадает в список приоритетов.

Если я могу чем-то помочь в этом усилии, пожалуйста, дайте мне знать.

P.S. Я очень ценю предложение внести PR для настройки глобального заголовка. Позвольте мне провести дополнительное исследование и вернуться с более четко определенными требованиями. Спасибо за вашу помощь.

К сожалению, если файл изменяем, это означает, что мы больше не сможем включать бесконечное кэширование ресурса в CDN и в браузерах конечных пользователей.

Существуют стратегии, позволяющие реализовать что-то подобное без существенного ущерба для производительности — например, директива stale-while-revalidate. Однако это влечёт за собой свои издержки и последствия для пользовательского опыта.

1 лайк