تستغرق الصور الرمزية وقتاً طويلاً في التحميل بعد الانتقال إلى R2 المتوافق مع S3

مرحبًا،

لقد انتقلت للتو إلى R2 وسارت كل الأمور بشكل مثالي. جميع الصور تحتوي الآن على روابط عنوان URL الخاص بشبكة توصيل المحتوى (CDN) الخاصة بـ S3. ومع ذلك، لاحظت وجود مشكلة: تستغرق الصور الرمزية (الأفاتار) وقتًا طويلاً في التحميل. في المتوسط، يستغرق ذلك حوالي 3 إلى 4 ثوانٍ، سواء عند النقر على صورة رمزية لمستخدم أو عند التصفح داخل مشاركة. هل هذا متوقع؟

حسناً، أعتقد أن المشكلة قد تكون واحدة من ثلاث مشكلات مختلفة، لكن الأرجح بالنسبة لي هو إعادة التحجيم الفوري.

1. إعادة تحجيم الصور الرمزية فورياً

عندما قمتَ بنقل ملفاتك المرفوعة إلى R2، تم نقل الصور الأصلية؛ ومع ذلك، يستخدم Discourse أحجاماً مختلفة للصور الرمزية (على سبيل المثال، 45 بكسل للمشاركات، و120 بكسل لبطاقة المستخدم).

إذا لم تكن هذه الأحجام المحسّنة المحددة قد نُقلت بشكل مثالي، أو لم يتم إنشاؤها بعد، فيضطر Discourse إلى إنشائها بشكل متزامن في اللحظة التي ينقر فيها المستخدم عليها:

  1. يقوم Discourse بتنزيل الصورة الرمزية الأصلية من R2 إلى الخادم المحلي.
  2. يعيد تحجيمها باستخدام ImageMagick.
  3. يرفع الحجم الجديد مرة أخرى إلى R2.
  4. يعيد توجيه المتصفح إلى العنوان الجديد، وتستغرق هذه العملية من 3 إلى 4 ثوانٍ.

للتحقق: قم بتحديث الصفحة قسرياً (hard-refresh) - إذا استغرقت الصورة الرمزية 3-4 ثوانٍ في المرة الأولى، ولكنها تُحمّل فوراً في المرة الثانية، فهذا هو بالضبط ما يحدث.

للعلاج: ستُصلح هذه المشكلة نفسها بشكل طبيعي مع تصفح المستخدمين وإنشاء الأحجام. ولكن يمكنك إصلاحها فوراً من خلال إجبار الخادم على إنشاء جميع الصور الرمزية مسبقاً في الخلفية، وذلك عن طريق الدخول إلى الخادم عبر SSH وتشغيل الأمر التالي:

./launcher enter app
rake avatars:refresh

2. مهلة IPv6 البالغة 3 ثوانٍ

إذا كانت الصور الرمزية تستغرق 3-4 ثوانٍ في كل مرة حتى بعد التحديثات المتعددة، فمن المرجح أنها تصادف مهلة اتصال بالشبكة.

نقاط نهاية واجهة برمجة تطبيقات Cloudflare R2 تدعم كل من IPv4 وIPv6 (ثنائية الطبقة). إذا كان لديك عنوان IPv6 مخصصاً لخادمك (Droplet)، ولكن بوابة IPv6 للمضيف غير موجهة بشكل صحيح، فسيحاول الاتصال الداخلي لـ Ruby مع دلو R2 استخدام IPv6 أولاً، ويتوقف لمدة 3 ثوانٍ (وهي مهلة TCP الافتراضية في Linux)، ثم يفشل وينجح فوراً باستخدام IPv4.

للتحقق: ادخل إلى الخادم عبر SSH وشغل الأمر:

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

إذا توقف الأمر لبضع ثوانٍ ثم فشل، فهذا يعني أن IPv6 في الخادم معطوب، مما يتسبب في تأخير مدته 3 ثوانٍ في كل فحص داخلي لواجهة برمجة تطبيقات S3.

للعلاج: ستحتاج إما إلى إصلاح توجيه IPv6 في لوحة تحكم المضيف الخاص بك، أو ربما حتى تعطيل IPv6 على الخادم (Droplet) تماماً.

3. تأخيرات Gravatar

إذا كان موقعك مضبوطاً للتحقق من تحديثات Gravatar، فقد يقوم بمسح خوادم Gravatar الخارجية قبل عرض الصورة الرمزية. إذا كان للخادم اتصال خارجي بطيء (غالباً ما يكون ذلك مرتبطاً أيضاً بـ DNS أو IPv6)، فقد يعطل ذلك عرض الصورة الرمزية.

للتحقق: شغل الأمر التالي على خادمك:
curl -I -6 https://gravatar.com
إذا توقف الأمر لمدة 3 ثوانٍ، فهذا يعني أن IPv6 معطوب (انظر أعلاه).

الحل المتعلق بـ Gravatar: في إعدادات Discourse الخاصة بك، انتقل إلى تنزيل Gravatars تلقائياً، وقم بإيقافه مؤقتاً، وانظر إذا كان ذلك يحل المشكلة - لا أعتقد أن هذه هي المشكلة، ولكن إذا كانت كذلك، يمكنك ترك الإعداد معطلاً، أو إصلاح توجيه IPv6 كما هو موضح في النقطة 2 أعلاه، أو ربما تغيير مُحلل DNS.

شكرًا لك على ردك السريع. أعتقد أنني قد جربت بالفعل أمر ‘rake avatars:refresh’ من قبل، لكنني لست متأكدًا تمامًا.

ما كان يعمل معي في السابق لعرض الصورة الرمزية فورًا هو النقر عليها مرة أولى؛ وفي المرة الثانية، كانت تفتح على الفور. لكن هذا ربما يعود إلى التخزين المؤقت. كما أنني جربت للتو نصيحتك الثانية، وقد أعادت استجابة “HTTP/2 301” مع عدة أسطر أخرى. الأمر نفسه ينطبق على النصيحة الثالثة. سأقوم بتشغيل أمر avatars:refresh مرة أخرى بعد بضعة أيام، حيث كنت بحاجة إلى استعادة لقطة نظام. شكرًا لك مجددًا!

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 لمعالجتها في الخلفية، وقد يستغرق ذلك عدة ساعات اعتمادًا على وحدة المعالجة المركزية (CPU) لخادمك. آسف على ذلك، كان ينبغي عليّ ذكر Sidekiq وأن الأمر قد يستغرق وقتًا طويلاً اعتمادًا على عدد المستخدمين.

انتقل إلى your-forum.com/sidekiq/queues وراقب قائمة الانتظار. انتظر حتى تتفرغ تمامًا. بمجرد انتهاء Sidekiq من معالجة المهام، ستصبح جميع الأحجام محفوظة بشكل دائم في دلو R2 الخاص بك، وأعتقد أن سرعة تحميل الصور الرمزية (الأفاتار) ستعود إلى طبيعتها.

حسناً، أعتقد أن هناك شيئاً آخر يحدث. لا توجد أي عناصر في طوابيري. ولكن إذا نقرت على صورة أي مستخدم، سيظهر هذا في السطر التالي من سجل الإنتاج: tail -f log/production.log: تم إرسال الملف /var/www/discourse/tmp/avatar_proxy/3689d91eb5e1013beef831c585b5e62edeeecbd6.jpeg (0.2ms)

واو، حسنًا. هذا على الأرجح الدليل القاطع ويشير إلى مشكلة مختلفة.

كلمة avatar_proxy في السجلات تعني عادةً أن Discourse يرفض تقديم الصورة الرمزية مباشرةً من شبكة توصيل المحتوى (CDN) الخاصة بـ Cloudflare R2. بدلاً من ذلك، يقوم Discourse باعتراض الطلب بشكل نشط وتحميل الصورة من R2 إلى مجلد /tmp على الخادم المحلي، ثم يستخدم Ruby لتقديم الصورة للمتصفح. لذا، أعتقد أن هذا يتجاوز شبكة توصيل المحتوى تمامًا ويشرح التأخير لمدة 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 بدلاً من عنوان 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)، ثم قم بتشغيل أداة إعادة التعيين (مرة أخرى LOL) لاستبدال عنوان URL الخام بعنوان URL الخاص بشبكة توصيل المحتوى:

discourse remap "https://<your-raw-cloudflare-url>.r2.cloudflarestorage.com" "https://cdn.your-domain.com"

ثم قم بتشغيله مرة ثانية باستخدام // بدلاً من https:// في حال حدوث ذلك.

بالمناسبة، مجرد فضول، ما هي خدمة الاستضافة التي تستخدمها؟ لدي نفس الإعداد العام مثلك ولم أواجه هذه المشكلة بعد. لذا أنا مهتم أيضًا بتكوينك وأريد محاولة إعادة إنتاجه بطريقة ما.

الرابط الذي أحصل عليه يظهر عنوان URL الخاص بـ S3 CDN، ويمكنني فتح الصورة في المتصفح.

سأتجاوز استخدام S3 في الوقت الحالي، لأنني لا أحتاج إليه حقًا في هذه المرحلة.

وأتخدم Advinservers منذ فترة طويلة.

شكرًا لمساعدتك، وأقدّر ذلك كثيرًا.