Аватары долго загружаются после переезда на совместимый с S3 R2

Здравствуйте,

Я только что перешел на R2, и все прошло отлично. Все изображения имеют ссылку на S3 CDN. Однако я заметил проблему: аватары загружаются очень долго. В среднем это занимает от 3 до 4 секунд, независимо от того, кликаю ли я на аватар пользователя или просматриваю сообщение. Это нормально?

Хм, я подозреваю, что проблема может быть одной из трёх, но наиболее вероятная — это изменение размера аватаров «на лету».

1. Изменение размера аватаров «на лету»

Когда вы перенесли загрузки в R2, оригинальные изображения были перемещены; однако Discourse использует аватары разных размеров (например, 45 пикселей для сообщений, 120 пикселей для карточки пользователя).

Если эти оптимизированные размеры не мигрировали идеально или ещё не были сгенерированы, Discourse вынужден генерировать их синхронно в момент, когда пользователь нажимает на аватар:

  1. Discourse скачивает оригинальный аватар из R2 на локальный сервер.
  2. Изменяет его размер с помощью ImageMagick.
  3. Загружает новый размер обратно в R2.
  4. Перенаправляет браузер на новый URL, и этот процесс занимает 3–4 секунды.

Для проверки: выполните жёсткую перезагрузку страницы. Если аватар загружается 3–4 секунды при первом открытии, но мгновенно при втором — это именно то, что происходит.

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

./launcher enter app
rake avatars:refresh

2. Тайм-аут IPv6 на 3 секунды

Если аватары загружаются 3–4 секунды каждый раз, даже после нескольких перезагрузок, скорее всего, происходит сетевой тайм-аут.

Конечные точки API Cloudflare R2 являются двойными (dual-stack), то есть они используют как IPv4, так и IPv6. Если на вашем сервере (Droplet) назначен адрес IPv6, но шлюз IPv6 хоста настроен неправильно, внутреннее подключение Ruby к хранилищу R2 сначала попытается использовать IPv6, зависнет на 3 секунды (это стандартный тайм-аут TCP в Linux), завершится ошибкой, а затем мгновенно успешно подключится через IPv4.

Для проверки: подключитесь к серверу по SSH и выполните:

curl -I -6 https://cloudflare.com

Если команда зависает на несколько секунд и завершается ошибкой, значит, IPv6 на сервере настроен неправильно, из-за чего каждая внутренняя проверка API S3 испытывает задержку в 3 секунды.

Для исправления: вам нужно либо исправить маршрутизацию IPv6 в панели управления хостом, либо полностью отключить IPv6 на Droplet.

3. Задержки Gravatar

Если ваш сайт настроен на проверку обновлений Gravatar, он может опрашивать внешние серверы Gravatar перед отображением аватара. Если у сервера медленное исходящее подключение (что часто также связано с DNS или IPv6), это может блокировать отображение аватара.

Для проверки: выполните на сервере команду:
curl -I -6 https://gravatar.com
Если она зависает на 3 секунды, значит, IPv6 настроен неправильно (см. выше).

Исправление, связанное с Gravatar: в настройках Discourse перейдите в раздел автоматически загружать граватары, временно отключите эту опцию и посмотрите, поможет ли это. Я не думаю, что это основная проблема, но если это так, вы можете оставить настройку отключённой, исправить маршрутизацию IPv6, как описано в пункте 2 выше, или изменить DNS-резолвер.

Спасибо за быстрый ответ. Кажется, я уже пробовал команду ‘rake avatars:refresh’ ранее, но не уверен в этом на все сто.

Раньше у меня получалось мгновенно открывать аватар, если кликнуть по нему дважды: первый раз — для загрузки, второй — для мгновенного открытия. Но, вероятно, это связано с кэшированием. Я также только что протестировал ваш второй совет, и он возвращает «HTTP/2 301» с несколькими другими строками. То же самое касается третьего совета. Я снова запущу avatars:refresh через пару дней, так как мне нужно было восстановить снимок состояния (snapshot). Ещё раз спасибо!

Gravatar

server: nginx
date: Mon, 22 Jun 2026 19:29:00 GMT
content-type: text/html; charset=utf-8
content-length: 0
content-language: en
expires: Wed, 11 Jan 1984 05:00:00 GMT
cache-control: no-cache, must-revalidate, max-age=0
x-redirect-by: Gravatar
location: https://en.gravatar.com/
alt-svc: h3=":443"; ma=86400
strict-transport-security: max-age=31536000; includeSubdomains; preload

CF

HTTP/2 301
date: Mon, 22 Jun 2026 19:27:00 GMT
content-type: text/html
content-length: 167
location: https://www.cloudflare.com/
cache-control: max-age=3600
expires: Mon, 22 Jun 2026 20:26:59 GMT
set-cookie: __cf_bm=eBP2aJ7Eg30nHPuvMMNxxKrgNtcNwKs0WDgnYyONeus-1782156420-1.0.1.1-sXpW27iuhGDF615cOfwNFybH4IMxgvZy3uA_3X_o..402T_3KSgT7CSymipL5RjdpGe3raWEqsVxQFFLPKRoDjfoT7B.0rqyDt.osbkOF98; path=/; expires=Mon, 22-Jun-26 19:57:00 GMT; domain=.cloudflare.com; HttpOnly; Secure; SameSite=None
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=QfYqSekEDPJHC2k%2BMjHN0cGjz172tmUWe2GSR8EgwNLh3TGjFYkQ0vwPxlzY1NcBcKFOMaAi4FlgjqjhETOOtHf%2BH9KdQSvqN3OME2Uh1i4nHIw%2Fy1qkvSpf4jxDchM7CaDW80tJkjBV4OqF"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
strict-transport-security: max-age=15780000; includeSubDomains
server: cloudflare
cf-ray: a0fda5d8ecd6b26d-LAX
alt-svc: h3=":443"; ma=86400

Да, учитывая ваш ответ, я почти уверен, что проблема в пункте №1, поскольку результаты команды curl для Cloudflare и Gravatar выглядят ожидаемо. Попробуйте выполнить rake avatars:refresh, когда вам будет удобно, и дайте знать, сработало ли это.

Привет, Лилли, у меня всё ещё та же проблема. Даже после выполнения rake avatars:refresh. Проблема также проявляется в разделе /latest. Я пробовал очищать кэш в браузере и на Cloudflare, но безрезультатно. Возможно, нужно подождать? Я тестирую это на форуме с 4500 пользователями.

Больше не очищайте кэш браузера или Cloudflare — когда вы запускаете rake avatars:refresh для такого количества пользователей, это происходит не мгновенно. Вместо этого создаются тысячи задач в Sidekiq, которые обрабатываются в фоновом режиме и могут занять несколько часов в зависимости от процессора вашего сервера. Извините, я должен был упомянуть Sidekiq и то, что процесс может занять время в зависимости от количества пользователей.

Перейдите на your-forum.com/sidekiq/queues и наблюдайте за очередью. Подождите, пока она полностью опустеет. Как только Sidekiq завершит работу, все размеры должны сохраниться в вашем бакете R2, и, я думаю, загрузка аватаров должна вернуться к нормальной скорости.

Хм, кажется, происходит что-то другое. В моих очередях ничего нет. Но если я нажимаю на аватар любого пользователя, в логах tail -f log/production.log появляется сообщение: Sent file /var/www/discourse/tmp/avatar_proxy/3689d91eb5e1013beef831c585b5e62edeeecbd6.jpeg (0.2ms)

Ого, хорошо. Это, скорее всего, ключевое доказательство, указывающее на другую проблему.

avatar_proxy в логах обычно означает, что Discourse отказывается отдавать аватар напрямую через CDN Cloudflare R2. Вместо этого Discourse агрессивно перехватывает запрос, скачивает изображение из R2 в локальную папку /tmp сервера, а затем с помощью Ruby отдаёт его браузеру. То есть, похоже, CDN полностью обходится, что и объясняет задержку в 3 секунды — я подозреваю, что сервер вручную загружает и отдаёт файл при каждом запросе :grimacing:

Discourse использует avatar_proxy в нескольких очень специфических сценариях, и обычно это настройка приватности или безопасности, которая заставляет сервер маскировать внешние URL.

Проверьте следующие настройки в админ-панели: Настройки сайта:

Найдите external system avatars url — если в этом поле что-то есть (например, /letter_avatar_proxy/v4/...), удалите всё, чтобы поле было пустым. Это должно остановить проксирование Discourse для аватаров по умолчанию. Также стоит проверить uploaded avatars allowed groups и убедиться, что там указано TL_0.

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

Перенастройка пользовательских аватаров:
Похоже, что в вашей базе данных всё ещё содержатся прямые URL-адреса бакета R2 вместо вашего нового CDN-URL. Поскольку они не совпадают, ваш форум, вероятно, проксирует их в целях безопасности.

Проверьте в консоли Rails, с чем именно борется Discourse:

./launcher enter app
rails c

Выберите имя пользователя с медленно загружающимся аватаром

u = User.find_by_username("the_selected_username")
u.user_avatar.custom_upload.url

Если вывод возвращает прямой URL бакета, значит предыдущая перенастройка не охватила всё (возможно, была упущена поддомен или схема).

Чтобы исправить это, подключитесь по SSH к серверу, снова зайдите в контейнер (не в rails) (./launcher enter app) и запустите инструмент перенастройки (снова, лол), чтобы заменить прямой URL на ваш CDN-URL:

discourse remap "https://<ваш-прямой-cloudflare-url>.r2.cloudflarestorage.com" "https://cdn.your-domain.com"

Затем запустите его второй раз, используя // вместо https://, на всякий случай.

Кстати, просто из любопытства: какой хостинг-провайдер вы используете? У меня такая же общая настройка, как у вас, и я ещё не сталкивался с этой проблемой. Поэтому мне также интересно узнать о вашей конфигурации, и я хочу попробовать воспроизвести это.

полученный URL указывает на CDN S3, и я могу открыть изображение в браузере.

Пока оставлю S3, так как сейчас он мне не особо нужен.

Кроме того, я уже давно использую Advinservers.

Спасибо за помощь, очень благодарен.

Я завершил дополнительное тестирование и могу подтвердить, что проблема не связана с R2. То же самое поведение (медленная загрузка аватаров в сообщениях и при клике на имя пользователя) сохраняется даже при правильно настроенном AWS S3. Это также не проблема файрвола, так как «ufw status» подтверждает, что файрвол в данный момент отключен. Я планирую провести больше тестов на этой неделе в тестовой среде, где я смогу держать форум в рабочем состоянии более длительное время и при необходимости отключать его без каких-либо проблем.

У вас настроены оба CDN — site и s3?

Да, я использую оба. Бакет подключён к CloudFront для URL CDN S3, и то же самое для URL CDN Discourse.

Для тестов R2 я не использовал URL CDN Discourse.

Разве не на том, который не работает?

И именно с R2 без CDN Discourse у вас возникают проблемы?

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

Аватары здесь загружаются с того, что выглядит как CDN Discourse: https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lilly/48/555832_2.png

Профили пользователей загружаются быстрее после первой загрузки?

Снова повторю, не обещаю, что понимаю и не смотрел код, но предполагаю, что они обслуживаются CDN Discourse, и Discourse полагается на то, что последующие запросы будут получать данные из CDN. Думаю, это объясняет, почему это не работает (или работает медленно) на версии R2 без CDN Discourse.

возможно, я не до конца понимаю, что вы имеете в виду, но у меня есть два сайта, работающих с объектным хранилищем R2, которые не сталкиваются с этой проблемой. :woman_shrugging:t2:

У них нет CDN для Discourse? Если нет, то я ошибаюсь. Если же есть, то, возможно, отсутствие CDN для Discourse (при наличии S3-бакета?) вызывает эту проблему.

Но странно, что аватары ведут себя по-разному с S3 и без него.

На самом деле, я протестировал это с 4 различными конфигурациями:

  1. R2 без CDN Discourse

  2. R2 с CDN Discourse

  3. AWS S3 с CDN Discourse

  4. AWS S3 без CDN Discourse

Во всех случаях я использовал URL CDN S3: files.mydomain.com.

Для случаев с CDN Discourse я использовал: cdn.mydomain.com.

Проблема в том, что в каждом сценарии загрузка аватаров всегда очень медленная.

Если я открываю тему, я вижу, как аватары загружаются по одному. Однако это происходит только один раз. Например, если я перейду в admin/users, я вижу только никнеймы, а затем аватары начинают загружаться по одному.

Если я нажму на никнейм, откроется карточка пользователя, и аватар появится через 3-4 секунды. Это также происходит только один раз; если я нажму снова, аватар появится мгновенно, вероятно, из-за кэширования.

P.S.: При проведении каждого теста я восстанавливаю снимок с момента, когда я не использовал S3/R2, удаляю бакет и начинаю заново.

Я просто предположу, что это никак не связано с конфигурацией объектного хранилища. Я думаю, что ваши аватары загружаются медленно во всех четырех конфигурациях, потому что узким местом является не сам провайдер хранилища, а сетевая задержка между вашим дроплетом и бакетом, либо процессор вашего сервера с трудом справляется с изменением размера изображений на лету. Я не знаю ничего о конфигурации вашего сервера/CDN и о расстояниях, которые здесь задействованы. Но я думаю, что после формирования кэша на краевых узлах не будет иметь значения, какое хранилище вы используете, главное — придерживаться одного варианта и позволить кэшу сформироваться. Однако в данный момент я просто выдвигаю теории, так как у меня нет других идей. :woman_shrugging:t2: :grinning_cat_with_smiling_eyes:

Я тоже уже не знаю, что и думать. Для R2 я использовал регион «Западная Европа» (WEUR), а для S3 — eu-north-1. Вот характеристики моего VPS:

Процессор AMD Turin (4 виртуальных ядра), 8 ГБ памяти DDR5 ECC, SSD NVMe на 256 ГБ, 5 ТБ трафика (10 Гбит/с), расположен в Лос-Анджелесе, Калифорния.

Возможно, в следующий раз стоит протестировать с регионом в США? Не думаю, что это возможно с R2.

Это вполне ожидаемо. Генерация всех аватаров занимает много времени. Задачи Rake запустят этот процесс, но он будет долгим, особенно если у вас много пользователей. При первом обращении к пользователю генерируется его аватар, и на запуск внешней программы, которая обрабатывает данные изображения в разных размерах, уходит несколько секунд. После этого всё работает нормально. Думаю, вам просто нужно запустить задачу Rake и подождать, пока она сгенерирует все аватары в различных размерах?

ну да, думаю, именно это я и хотел сказать, но, возможно, не объяснил это правильно:

но мне кажется, вы говорили, что он загружается медленно каждый раз. :thinking:

кажется, каждый раз, когда вы меняете конфигурацию S3 или очищаете кэш, вы начинаете процесс заново. если у вас много аватаров пользователей, это займёт очень много времени.