إنشاء شهادة discobot بطيء جدًا على خادمنا

لقد قمنا بتشجيع الأعضاء الجدد لدينا على إكمال دليل discobot، وقد واجه عدد منهم مشكلة سبق أن عشناها في مثيل Discourse (اختباري) سابق: شهادة آخر منشور تستغرق وقتًا طويلاً للتوليد والظهور فعليًا، دون أي مؤشر على أنها قيد التحميل أو التوليد. وبوقت طويل أعني فترة تتراوح بين 10 إلى 20 ثانية — وهي مدة كافية لشخص ما أن يستسلم. جربت الأمر على موقع meta ويبدو أن الأمر فوري هناك.

لاحظت أنه يمكن توليد الشهادة عند الطلب باستخدام عنوان URL التالي: /discobot/certificate.svg?date=Oct+28+2020&user_id=123، لذا قمت ببعض الاختبارات. في البداية، كان الأمر فوريًا. لكن بمجرد استخدام معرفات مستخدمين لم يكملوا الدليل مؤخرًا، اضطررت للانتظار لمدة 10-20 ثانية (إنه سريع بعد التوليد الأول، لذا أفترض وجود ذاكرة تخزين مؤقت في مكان ما). كما حصلت على بعض أخطاء 500 أثناء فترة الانتظار، وأعتقد أنها كانت نوعًا من انتهاء المهلة لأنها نجحت في التحديث التالي.

في سجلات /logs، أرى تحذيرًا لا أعرف ما إذا كان مرتبطًا:

فشل في معالجة الاستجابة المختطفة بشكل صحيح: Net::ReadTimeout

traceback
/usr/local/lib/ruby/2.6.0/net/protocol.rb:217:in `rbuf_fill'

/usr/local/lib/ruby/2.6.0/net/protocol.rb:191:in `readuntil'

/usr/local/lib/ruby/2.6.0/net/protocol.rb:201:in `readline'

/usr/local/lib/ruby/2.6.0/net/http/response.rb:40:in `read_status_line'

/usr/local/lib/ruby/2.6.0/net/http/response.rb:29:in `read_new'

/usr/local/lib/ruby/2.6.0/net/http.rb:1509:in `block in transport_request'

/usr/local/lib/ruby/2.6.0/net/http.rb:1506:in `catch'

/usr/local/lib/ruby/2.6.0/net/http.rb:1506:in `transport_request'

/usr/local/lib/ruby/2.6.0/net/http.rb:1479:in `request'

rack-mini-profiler-2.0.2/lib/patches/net_patches.rb:9:in `block in request_with_mini_profiler'

rack-mini-profiler-2.0.2/lib/mini_profiler/profiling_methods.rb:39:in `step'

rack-mini-profiler-2.0.2/lib/patches/net_patches.rb:8:in `request_with_mini_profiler'

/var/www/discourse/lib/final_destination.rb:370:in `block in safe_get'

/var/www/discourse/lib/final_destination.rb:414:in `block in safe_session'

/usr/local/lib/ruby/2.6.0/net/http.rb:920:in `start'

/usr/local/lib/ruby/2.6.0/net/http.rb:605:in `start'

/var/www/discourse/lib/final_destination.rb:411:in `safe_session'

/var/www/discourse/lib/final_destination.rb:362:in `safe_get'

/var/www/discourse/lib/final_destination.rb:131:in `get'

/var/www/discourse/lib/final_destination.rb:152:in `get'

/var/www/discourse/lib/file_helper.rb:55:in `download'

/var/www/discourse/plugins/discourse-narrative-bot/plugin.rb:113:in `fetch_avatar'

/var/www/discourse/plugins/discourse-narrative-bot/plugin.rb:98:in `block in generate'

/var/www/discourse/lib/hijack.rb:56:in `instance_eval'

/var/www/discourse/lib/hijack.rb:56:in `block in hijack'

/var/www/discourse/lib/scheduler/defer.rb:94:in `block in do_work'

rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:68:in `with_connection'

/var/www/discourse/lib/scheduler/defer.rb:89:in `do_work'

/var/www/discourse/lib/scheduler/defer.rb:79:in `block (2 levels) in start_thread'

أفترض أن الشهادة يتم توليدها محليًا، دون أي طلبات شبكة خارجية؟

الآلة هي من نوع t3a.medium (4 جيجابايت من الذاكرة)، والمنتدى ليس نشطًا بشكل خاص (حمل حوالي 0.4، مع وجود ذاكرة حرة كافية). أثناء انتظار توليد الشهادة، لم يبدو أن وحدة المعالجة المركزية قد تغيرت على الإطلاق، لذا لا يبدو أنها عنق الزجاجة.

نحن لسنا الوحيدين الذين يعانون من هذه المشكلة (غير متأكد ما إذا كان هذا مرتبطًا)، لكنني لا أرى أي شيء هناك يمكن أن يساعد.

غير متأكد ما إذا كنت على الطريق الصحيح، ولكن إذا قمت بتحديث عنوان URL الخاص بالشهادة عدة مرات، فستظهر لي في النهاية رسالة خطأ تخبرني بأن أبطئ. هل هناك آلية تحديد معدل للعناوين قد تتداخل هنا إذا كان العديد من الأشخاص يولدون الشهادات في نفس مسار URL؟ ربما لا، لكنني في حيرة من أمري حول سبب حدوث هذا. أي تلميحات موضع ترحيب.

هذه المسار بطيء بالفعل، لأنه جديد.

بصرف النظر عن محاولة تسريعه، ربما يمكننا إضافة تغيير في النص ليعلم المستخدم أن Discobot يقوم بإعداد شيء ما وأن الأمر سيستغرق دقيقة؟

لم أكن أدرك أنه معروف بأنه بطيء — إن لم يكن هناك شيء آخر، أعتقد أن تحديثًا للمنشور لتوضيح ذلك قد يساعد، لكنني ما زلت أتوقع أن يستسلم بعض الأشخاص إذا طالت فترة الانتظار.

يجب أن أقول إن 10 إلى 20 ثانية لتوليد ملف يبدو وقتًا غير معتادًا لطباعة صورة SVG موجودة مسبقًا (أفترض ذلك؟) مملوءة ببعض النص؟ насколько我能看到的,这似乎不是CPU瓶颈。这里的瓶颈是什么?

كنت أفكر في تعديل النص هنا لإضافة جملة مثل “انتظر من فضلك، فأنا أقوم بتوليد شيء رائع لك!” في الخطوة السابقة.. لكن في try.discourse.org، عملية توليد الشهادة سريعة للغاية:

الطابع الزمني للخطوة الأخيرة من discobot: 2 نوفمبر، 6:46 م 1604371566089
الطابع الزمني لخطوة توليد الشهادة من discobot: 2 نوفمبر، 6:46 م 1604371567470

لا أعرف بالضبط ما هي وحدات الطوابع الزمنية الأساسية، لكن الفرق هو 1381.

لقد رددت بأسرع ما يمكن في نفس الموضوع، وحصلت على هذه الطوابع الزمنية، وهي أقل من بضع ثوانٍ بوضوح:

1604373488630
1604373492182

وهذا يعني فرقًا قدره 3552 .. وقد نشرت حرفيًا بأسرع ما يمكن، عبر النسخ واللصق واستخدام اختصارات لوحة المفاتيح!

إذن.. هل خادمك ببساطة.. ضعيف.. أم ماذا؟

أعتقد أنه يتحدث عن توليد صورة الشهادة، وليس المنشور.

أنا أتحدث بالفعل عن توليد الشهادة — وليس عن رد المنشور الذي يدمجها (وهو سريع). هذا هو ما يسببه هذا الأمر لبعض أعضائنا:

لا، فإن t3a.medium هو مثيل من النطاق المتوسط، والحمل ليس مرتفعًا.

كما قلت، لا يبدو أن المشكلة مرتبطة بمعالج (CPU) لأنني أثناء انتظار انتهاء طلب مثل /discobot/certificate.svg?date=Oct+28+2020&user_id=123، لا يكون المعالج أكثر انشغالًا من أي وقت آخر (وهو ليس مشغولًا جدًا).

يبدو أن المشكلة تتعلق بانتهاء مهلة طلب شبكي:

يبدو أن الصورة الرمزية (avatar) في الشهادة عبارة عن كتلة data:image/png;base4. من ما أستطيع رؤيته، هناك محاولة لتحميل صورة رمزية تؤدي إلى انتهاء المهلة؟ ربما هذا ما يبطئ الأمور هنا؟

للتوضيح، هذا يحدث في منتدى يستخدم SSO، وتُخزن الصور الرمزية كروابط HTTPS على S3. لقد حاولت جلب بعض هذه الصور الرمزية من داخل حاوية Docker، وقد نجح الأمر وكان سريعًا جدًا — لا توجد مشاكل في الجدار الناري، إلخ. كل شيء آخر في المنتدى يعمل بسرعة، باستثناء توليد الشهادة الذي يستغرق وقتًا طويلاً.

أنا مستعد لمحاولة تصحيح هذا الأمر بشكل أكبر إذا تم تزويدي بتوجيهات حول ما يجب التحقق منه.

ظهرت الصورة تقريبًا على الفور بالنسبة لي على try.discourse.org .. لم ألاحظ أي تأخير ملحوظ يزيد عن نصف ثانية على الأكثر، إن كان هناك تأخير أصلاً! جرّبها بنفسك إذا لم تصدقني!

لذا عدت إلى ما قلته في الأصل: لماذا هذا بطيء جدًا على خادمك، بينما سريع جدًا على try.discourse.org؟

لماذا بالفعل… هذا ما أحاول الحصول على دعم بشأنه.

أدرك أن هذا سيناريو من نوع “يعمل على جهاز الكمبيوتر الخاص بي” الذي لا ينبغي أن يوجد حتى مع Docker، ولكن للأسف، ها نحن هنا ولا يبدو أنني الوحيد.

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

قمت بقضاء بعض الوقت في البحث في هذه المشكلة، ويبدو أن السبب هو أن discourse-narrative-bot يتوقف عند جلب صورة المستخدم لإدراجها في الشهادة. هنا:

يستخدم هذا المنتدى نظام الدخول الموحد (SSO)، وصور المستخدمين هي روابط Amazon S3 — وهي سريعة ولا تخضع لحدود المعدل من قبل Amazon. ومع ذلك، فإن هذه الدالة تجلب رابط صورة مستخدم على الشكل التالي:

https://forum.tld/user_avatar/forum.tld/username/240/18705_2.png

هل يمكن أن تكون أخطاء المهلة الزمنية التي تبطئ إنشاء الشهادة ناتجة عن الوصول إلى حدود المعدل في Discourse بطريقة ما؟ إما عن طريق طلب الصور بسرعة كبيرة من مثيل Discourse نفسه، أو عن طريق محاولة الوصول إلى Amazon S3 بسرعة كبيرة عندما يقوم عدة مستخدمين بإجراء دروس البوت؟

مثير للاهتمام. لقد قمنا بتضمين صورة بتنسيق Base64 هناك. أتساءل لماذا لم نرابط ببساطة إلى المورد الخارجي في وسم image SVG :thinking:

لقد غصت في تاريخ الإضافة حتى النقطة التي أضفناها فيها لأول مرة:

ويبدو أننا كنا نستخدم دائمًا صورًا مضمنة بتنسيق Base64.

تحرير: بعد بعض البحث، نقوم بالتضمين باستخدام Base64 لأن الشهادة تُحمّل عبر وسم HTML img. للحصول على صور رمزية أرخص، سيتعين علينا الانتقال إلى وسم object، وهو محظور افتراضيًا في سياسة محتوى الأمان (CSP) الخاصة بنا. أو تضمين ملف SVG بالكامل في محتوى المنشور. أعتقد أن iframe هو أفضل خيار لدينا.

لدي FIX: Make discobot certificate gen faster/non blocking by xfalcox · Pull Request #11344 · discourse/discourse · GitHub للحصول على تعليقات @tgxworld.

افترضت أن تضمين SVG للصورة الرمزية المشفرة بصيغة Base64 كان لنفس السبب الذي جعله يفعل ذلك مع الشعار: حتى تكون الشهادة لقطة في وقت محدد — ربما يحفظها الحائز عليها دون أي اعتمادات خارجية، بحيث تظل تُعرض لاحقًا بنفس الطريقة تمامًا.

نهج iframe يمنع مشاركتها بسهولة والفخر بها في منشور. لا أعرف مدى شيوع هذا في المنتديات الأخرى، لكنني رأيت بعض مستخدمينا يفعلون ذلك ببساطة عن طريق نسخ عنوان URL للصورة.

إذا كنا سنرابط إلى شيء خارجي، ألا يمكن استخدام <image> هنا وتجنب الحاجة إلى تغيير allowed_iframes؟

هذا ما يفعله طلب الدمج (PR) أعلاه إذا قرأته :grimacing:

ولكن إذا قمت بتحميل ملف SVG باستخدام وسم HTML img كما نفعل اليوم، فلن يتم تحميل الصور الخارجية الموجودة داخل وسوم image في ملف SVG. يجب تحميلها إما باستخدام object أو iframe لكي تعمل.

من الواضح أنني لا أعرف ما يكفي عن SVG. إن نهج iframe يمنع اقتباس/نسخ الشهادة، ومع ذلك فإنني سعيد بأن هذا الأمر يتم معالجته بطريقة ما، حيث سيحل مشكلتنا وكذلك مشكلة الشعار المفقود في الشهادة. :+1:

@mentalstring لقد دمجتُ كود توليد الشهادات الجديد. يجب أن يكون الأمر أسرع بكثير الآن.

عظيم أن نرى هذا الدمج. :+1:

نحن نستخدم النسخة المستقرة stable وليس لدي طريقة جيدة لاختبار هذا الآن. لكن إذا لم يعد fetch_avatar مستخدمًا، فأتوقع أن تختفي أخطاء Net::ReadTimeout لدينا مع هذا التحديث. سأضع علامة “تم الحل” على هذه المشكلة، وسأعيد فتحها إذا صادفت نفس المشكلة مرة أخرى عند التحديث. شكرًا!