تستغرق الصور الرمزية وقتاً طويلاً في التحميل بعد الانتقال إلى 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 منذ فترة طويلة.

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

لقد أنهيت اختبارات إضافية ويمكنني تأكيد أن المشكلة لا تتعلق بـ R2. نفس السلوك (بطء تحميل الصور الرمزية في المنشورات وعند النقر على اسم المستخدم) يستمر حتى مع وجود AWS S3 مُعد بشكل صحيح. كما أنها ليست مشكلة جدار حماية، حيث يؤكد أمر “ufw status” أن جدار الحماية معطل حاليًا. أخطط لإجراء المزيد من الاختبارات هذا الأسبوع في بيئة تجريبية، حيث يمكنني إبقاء المنتدى قيد التشغيل لفترات أطول وإخفاءه إذا لزم الأمر دون أي مشاكل.

هل قمت بإعداد كلا من CDN للموقع و CDN لـ S3؟

نعم، أنا أستخدم كلاهما. الدلو متصل بـ CloudFront لعنوان URL الخاص بـ S3 CDN، ونفس الشيء ينطبق على عنوان URL الخاص بـ Discourse CDN.

أما بالنسبة لاختبارات R2، لم أكن أستخدم عنوان URL الخاص بـ Discourse CDN.

ما عدا على ذلك الذي لا يعمل؟

ومشكلتك مع 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 بدون Discourse CDN

  2. R2 مع Discourse CDN

  3. AWS S3 مع Discourse CDN

  4. AWS S3 بدون Discourse CDN

في جميع الحالات، استخدمت عنوان URL الخاص بـ S3 CDN: files.mydomain.com.

بالنسبة للحالات التي تتضمن Discourse CDN، استخدمت: cdn.mydomain.com.

المشكلة هي أنه في كل سيناريو، يكون تحميل الصور الرمزية (Avatars) بطيئاً جداً دائماً.

عندما أفتح موضوعاً، أرى الصور الرمزية تُحمّل واحدة تلو الأخرى. ومع ذلك، لا يحدث هذا إلا مرة واحدة. على سبيل المثال، إذا انتقلت إلى admin/users، أرى فقط أسماء المستخدمين، ثم تبدأ الصور الرمزية في التحميل واحدة تلو الأخرى.

إذا نقرت على اسم مستخدم، تفتح بطاقة المستخدم وتظهر الصورة الرمزية بعد 3-4 ثوانٍ. يحدث هذا أيضاً مرة واحدة فقط؛ فإذا نقرت عليها مرة أخرى، تظهر الصورة الرمزية على الفور، ربما بسبب التخزين المؤقت (Caching).

ملاحظة: عند إجراء كل اختبار، أقوم باستعادة النسخة الاحتياطية من الوقت الذي لم أكن أستخدم فيه S3/R2، وأحذف الدلو (Bucket)، وأبدأ من جديد.

أنا فقط سأخمن أنه لا علاقة له بتكوين تخزين الكائنات. أعتقد أن رموز المستخدم (Avatars) لديك بطيئة عبر جميع إعداداتك الأربعة لأن الزجاجة (المعوق) ليست مزود التخزين؛ بل هو زمن التأخير في الشبكة بين قطرة موقعك (Droplet) وسطل التخزين (Bucket)، أو أن وحدة المعالجة المركزية (CPU) لخادمك تكافح لتغيير حجم الصور على الطاير. لا أعرف شيئاً عن تكوين الخادم/شبكة توصيل المحتوى (CDN) لديك وما هي المسافات المتضمنة هنا. لكنني أعتقد أنه بمجرد بناء ذاكرة التخزين المؤقت على الحافة (Edge Cache)، لن يهم نوع التخزين الذي تستخدمه طالما التزمت بواحد وتركته يبني ذاكرة التخزين المؤقت بنفسه. ومع ذلك، أنا فقط أتحدث عن نظريات في هذه المرحلة لأن لديّ أفكاراً أخرى. :woman_shrugging:t2: :grinning_cat_with_smiling_eyes:

لم أعد أعرف ما أفكر فيه أيضاً. بالنسبة لـ R2، كنت أستخدم منطقة أوروبا الغربية (WEUR)، وبالنسبة لـ S3، كنت أستخدم eu-north-1. هذه مواصفات خادم VPS الخاص بي:

معالج AMD Turin (4 نوى افتراضية) ذاكرة 8GB DDR5 ECC تخزين NVMe SSD سعة 256GB عرض نطاق 5TB (10 جيجابت) موقع في لوس أنجلوس، كاليفورنيا

ربما يجب أن أجرب الاختبار مع منطقة في الولايات المتحدة في المرة القادمة؟ لا أعتقد أنني أستطيع فعل ذلك مع R2.

هذا ما كنت أتوقعه. إن إنشاء جميع الرموز التعريفية يستغرق وقتًا طويلاً. ستؤدي مهام rake (رَك) العملية، لكنها تستغرق وقتًا طويلاً، خاصة إذا كان هناك عدد كبير من المستخدمين. في المرة الأولى التي تصل فيها إلى مستخدم، يتم إنشاء الرمز التعريفي، ويستغرق تشغيل برنامج خارجي لمعالجة بيانات الصورة إلى أحجام مختلفة بضع ثوانٍ. بعد ذلك، كل شيء على ما يرام. أعتقد أنك بحاجة فقط إلى تشغيل مهمة rake والانتظار حتى يتم إنشاء جميع الرموز التعريفية بأحجامها المختلفة؟

نعم، أعتقد أن هذا ما كنت أقصد هنا، لكن ربما لم أشرح الأمر بشكل صحيح:

لكن أعتقد أنك قلت إنها كانت تُحمّل ببطء في كل مرة. :thinking:

أعتقد أنك تبدأ العملية من الصفر في كل مرة تقوم فيها بتغيير إعدادات S3 أو مسح ذاكرة التخزين المؤقت. إذا كان لديك عدد كبير من رموز تعريف المستخدمين، فستستغرق هذه العملية وقتاً طويلاً.