كيف جعلت الإباحية 20x أكثر كفاءة مع دفق فيديو Python

نشرت: 2022-03-11

مقدمة

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

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

ما هي المشكلة؟

قبل بضع سنوات ، كنت أعمل في الموقع السادس والعشرين (في ذلك الوقت) الأكثر زيارة في العالم - وليس فقط صناعة الإباحية: العالم.

في ذلك الوقت ، قدم الموقع طلبات دفق الفيديو الإباحية باستخدام بروتوكول المراسلة في الوقت الحقيقي (RTMP). وبشكل أكثر تحديدًا ، استخدمت حل Flash Media Server (FMS) ، الذي أنشأته Adobe ، لتزويد المستخدمين بالبث المباشر. كانت العملية الأساسية على النحو التالي:

  1. يطلب المستخدم الوصول إلى بعض البث المباشر
  2. يرد الخادم بجلسة RTMP يقوم بتشغيل اللقطات المرغوبة

لسببين ، لم تكن FMS خيارًا جيدًا بالنسبة لنا ، بدءًا من تكاليفها ، والتي تضمنت شراء كليهما:

  1. تراخيص Windows لكل جهاز قمنا بتشغيل FMS عليه.
  2. ~ 4K دولار من التراخيص الخاصة بـ FMS ، والتي كان علينا شراء عدة مئات منها (وأكثر كل يوم) بسبب حجمنا.

بدأت كل هذه الرسوم تتراكم. وبغض النظر عن التكاليف ، كان FMS منتجًا يفتقر إليه ، خاصة في وظائفه (المزيد حول هذا قليلاً). لذلك قررت إلغاء FMS وكتابة محلل Python RTMP الخاص بي من البداية.

في النهاية ، تمكنت من جعل خدمتنا أكثر كفاءة بنحو 20 مرة.

ابدء

كانت هناك مشكلتان أساسيتان: أولاً ، لم تكن RTMP وبروتوكولات وتنسيقات Adobe الأخرى مفتوحة (أي متاحة للجمهور) ، مما جعل من الصعب التعامل معها. كيف يمكنك عكس أو تحليل الملفات بتنسيق لا تعرف شيئًا عنه؟ لحسن الحظ ، كانت هناك بعض جهود التراجع المتاحة في المجال العام (لم يتم إنتاجها بواسطة Adobe ، ولكن بواسطة مجموعة تسمى OS Flash ، لم تعد موجودة الآن) والتي اعتمدنا عليها في عملنا.

ملاحظة: أصدرت Adobe لاحقًا "المواصفات" التي لا تحتوي على معلومات أكثر مما تم الكشف عنه بالفعل في الويكي العكسي والمستندات غير المنتجة من Adobe. كانت مواصفاتهم (Adobe) ذات جودة منخفضة بشكل سخيف وجعلت من شبه المستحيل استخدام مكتباتهم فعليًا. علاوة على ذلك ، بدا البروتوكول نفسه مضللًا عن عمد في بعض الأحيان. علي سبيل المثال:

  1. استخدموا الأعداد الصحيحة 29 بت.
  2. لقد تضمنت رؤوس بروتوكول ذات تنسيق endian كبير في كل مكان - باستثناء حقل معين (ولكن غير مميز) ، والذي كان Endian صغيرًا.
  3. لقد قاموا بضغط البيانات في مساحة أقل على حساب القدرة الحسابية عند نقل إطارات فيديو 9 كيلو بايت ، الأمر الذي لم يكن له معنى ، لأنهم كانوا يكسبون بتات أو بايت في وقت واحد - مكاسب ضئيلة لمثل هذا الحجم من الملفات.

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

ثلاثة مستخدمين يوضحون الفرق بين حل دفق الفيديو متعدد البث ومشكلة دفق FMS.

حل دفق الفيديو متعدد البث الخاص بي

مع وضع ذلك في الاعتبار ، قررت إعادة حزم / تحليل تدفق الاستجابة النموذجي إلى "علامات" FLV (حيث تكون "العلامة" مجرد بعض بيانات الفيديو أو الصوت أو البيانات الوصفية). يمكن أن تنتقل علامات FLV هذه داخل RTMP مع القليل من المشكلات.

فوائد مثل هذا النهج:

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

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

تحسين أداء دفق الفيديو: مزج Python و RTMP و C.

بعد تحديد الكود ، اخترت نقل وظائف الأداء الحرجة إلى وحدة Python النمطية المكتوبة بالكامل في C. كانت هذه عناصر منخفضة المستوى إلى حد ما: على وجه التحديد ، استفادت من آلية epoll الخاصة بالنواة لتوفير ترتيب لوغاريتمي للنمو .

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

Epoll مدهش لأن كل ما عليك فعله هو تسجيل مقبس وسيتذكر النظام هذا المقبس المميز ، ويتعامل مع جميع التفاصيل الدقيقة داخليًا. لذلك لا يوجد جدال مع كل مكالمة. كما أنه يتطور بشكل أفضل بكثير ويعيد فقط المقابس التي تهتم بها ، وهو أفضل بكثير من تشغيل قائمة من 100 كيلو من واصفات المقبس لمعرفة ما إذا كان لديهم أحداث مع bitmasks - وهو ما عليك القيام به إذا كنت تستخدم الحلول الأخرى.

لكن لزيادة الأداء ، دفعنا ثمنًا: اتبع هذا النهج نمط تصميم مختلف تمامًا عن ذي قبل. كان النهج السابق للموقع (إذا كنت أتذكر بشكل صحيح) عملية واحدة متجانسة تمنع الاستلام والإرسال ؛ كنت أقوم بتطوير حل يحركه الحدث ، لذلك كان علي إعادة تشكيل بقية الكود أيضًا لتلائم هذا النموذج الجديد.

على وجه التحديد ، في نهجنا الجديد ، كان لدينا حلقة رئيسية ، والتي تعاملت مع الاستلام والإرسال على النحو التالي:

استخدم حل دفق الفيديو Python مجموعة من "علامات" RTMP و FLV وتدفق الفيديو متعدد البث.

  1. تم تمرير البيانات المستلمة (كرسائل) إلى طبقة RTMP.
  2. تم تشريح RTMP واستخراج علامات FLV.
  3. تم إرسال بيانات FLV إلى طبقة التخزين المؤقت والبث المتعدد ، والتي نظمت التدفقات وملأت المخازن المؤقتة منخفضة المستوى للمرسل.
  4. احتفظ المرسل بهيكل لكل عميل ، مع آخر فهرس تم إرساله ، وحاول إرسال أكبر قدر ممكن من البيانات إلى العميل.

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

مشكلات مستوى الأنظمة والمعمارية والأجهزة

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

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

نجح هذا ، ولكن مع عيب واحد: على الرغم من التعامل مع الحالة العامة بشكل جيد ، فقد رأينا أداءً سيئًا عندما شاهد كل شخص على الموقع (أو عدد غير متناسب من المستخدمين) مذيعًا واحدًا. الخبر السار: هذا لا يحدث أبدًا خارج حملة تسويقية. لقد قمنا بتنفيذ مجموعة منفصلة للتعامل مع هذا السيناريو ، ولكن في الحقيقة رأينا أن تعريض تجربة المستخدم الذي يدفع مقابل جهد تسويقي للخطر أمر لا معنى له - في الواقع ، لم يكن هذا سيناريو حقيقيًا حقًا (على الرغم من أنه كان من الجيد التعامل مع كل ما يمكن تخيله قضية).

خاتمة

بعض الإحصائيات من النتيجة النهائية: كانت حركة المرور اليومية على الكتلة حوالي 100 ألف مستخدم في الذروة (60٪ تحميل) ، حوالي 50 ألف في المتوسط. لقد قمت بإدارة مجموعتين (HUN و US) ؛ تعامل كل منهم مع حوالي 40 آلة لتقاسم الحمولة. كان النطاق الترددي المجمع للمجموعات حوالي 50 جيجابت في الثانية ، والتي استخدموا منها حوالي 10 جيجابت في الثانية أثناء تحميل الذروة. في النهاية ، تمكنت من دفع 10 جيجابت في الثانية / الجهاز بسهولة ؛ نظريًا 1 ، يمكن أن يصل هذا الرقم إلى 30 جيجابت في الثانية / الجهاز ، وهو ما يترجم إلى حوالي 300 ألف مستخدم يشاهدون التدفقات بشكل متزامن من خادم واحد.

تحتوي مجموعة FMS الحالية على أكثر من 200 آلة ، والتي كان من الممكن استبدالها بـ 15 جهازًا - منها 10 فقط يمكنها القيام بأي عمل حقيقي. أعطانا هذا تقريبًا تحسنًا بمقدار 200/10 = 20x.

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

هذا ، وأن طرح الحل الخاص بك يمكن أن يكون له مردود كبير.

1 في وقت لاحق ، عندما وضعنا الكود قيد الإنتاج ، واجهنا مشكلات في الأجهزة ، حيث استخدمنا خوادم sr2500 أقدم من Intel والتي لم تستطع التعامل مع بطاقات 10 Gbit Ethernet بسبب انخفاض عرض النطاق الترددي لـ PCI. بدلاً من ذلك ، استخدمناها في سندات 1-4x1 Gbit Ethernet (تجميع أداء العديد من بطاقات واجهة الشبكة في بطاقة افتراضية). في النهاية ، حصلنا على بعض من أحدث sr2600 i7 Intels ، والذي يخدم 10 جيجابت في الثانية عبر البصريات دون أي مكامن الخلل في الأداء. تشير جميع الحسابات المسقطة إلى هذا الجهاز.