أنظمة بحجم المنتجات

صمّم خلاصة أخبار

مستخدم ينشر صورة. بعد ثانية، نصف مليار شخص قد يرونها على صفحتهم الرئيسية — وكل واحد منهم يتوقعها في أقل من 200 ميلي ثانية. السؤال الذي يقرر البنية كلها صغير بشكل مخادع: متى تحسب خلاصة كل شخص؟

نصفان، نصرّح بهما من البداية
  1. النشر: منشور يُنشأ ويجب أن يصل إلى خلاصات كل من يتابع صاحبه — هذه هي مشكلة fanout.
  2. القراءة: مستخدم يفتح الصفحة الرئيسية ويتوقع خلاصته مجمّعة ومرتّبة ومعروضة بسرعة — مهما كانت طريقة عمل نصف النشر.
  3. الحجم: ‏~500 مليون منشور يومياً (≈ 6,000/ثانية)، والقراءات تفوق الكتابات ‏~100:1، والمستخدم العادي يتابع ‏~300 حساب، وقلة من المشاهير يحمل كل منهم عشرات ملايين المتابعين.
‏Fanout عند الكتابة (push)

في اللحظة التي يُنشأ فيها المنشور، يكتب عامل fanout مُعرِّف المنشور في الـfeed cache المحسوب مسبقاً لكل متابِع. تصبح قراءة الصفحة الرئيسية عملية بحث واحدة رخيصة: اجلب قائمة مُعرِّفات المنشورات المخزّنة، احمّلها، وانتهى. لصاحب حساب عادي لديه 300 متابِع، المنشور يكلّف 300 كتابة — تافه. لكن مشهوراً لديه 50 مليون متابِع يحوّل منشوراً واحداً إلى 50 مليون كتابة في الـcache. حتى بمعدل 100,000 كتابة في الثانية، هذه ثماني دقائق من عاصفة كتابات لأجل سيلفي واحدة — ومعظم هؤلاء المتابعين لن يفتحوا التطبيق قبل أيام.

‏Fanout عند القراءة (pull)

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

الجواب الاحترافي: هجين

‏Push للمستخدمين العاديين، وpull للمشاهير. عامل fanout يفحص عدد متابِعي صاحب المنشور: دون عتبة معينة (مثلاً 10 آلاف إلى مليون متابِع، تُضبط بالقياس)، ادفع المنشور إلى خلاصات المتابعين كالمعتاد. فوقها، خزّن المنشور في خط زمني خاص بالمشهور فقط. وعند القراءة، جمّع الخلاصة من الـcache المحسوب مسبقاً بالإضافة إلى دمج منشورات المشاهير القلائل الذين يتابعهم هذا المستخدم. منشورات العاديين تصل فوراً إلى الـcache؛ ومنشورات المشاهير تُسحب من خط زمني واحد ساخن ومكرَّر جيداً فقط عندما يقرأ أحدهم فعلاً.

الترتيب، بصدق

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

طبقات الـcache
  1. ‏Feed cache: قائمة محسوبة مسبقاً لكل مستخدم بمُعرِّفات المنشورات (أحدث بضع مئات)، يملؤها عامل fanout؛ هذا ما يجعل القراءة بحثاً واحداً.
  2. ‏Content cache: كائنات المنشورات نفسها — النص وروابط الوسائط والعدّادات — مفهرسة بمُعرِّف المنشور، حتى لا يضرب تحميل الخلاصة قاعدةَ البيانات لكل منشور.
  3. مخزن الرسم الاجتماعي (social graph): من يتابع من — مخزن مقسَّم (sharded) يجيب «من متابِعو هذا الكاتب؟» عند الكتابة، و«أي المشاهير يتابع هذا المستخدم؟» عند القراءة.
جرّب بنفسك
المبدأ

‏Fanout سؤال عن متى تدفع. ‏Push يدفع الآن، وقت الكتابة، فتصبح كل قراءة شبه مجانية. ‏Pull يدفع عند كل قراءة، فتصبح الكتابات شبه مجانية. لا أحدهما خطأ — الهجين ببساطة يدفع بكل طريقة حيث تكون تلك الطريقة رخيصة: push للحسابات الصغيرة الكثيرة حيث الكتابة رخيصة، وpull للحسابات العملاقة القليلة حيث القراءة نادرة والكتابة كارثية.

تحقّق سريع

لماذا يكسر المشهور الـpush fanout، وماذا يفعل الهجين بمنشوراتها؟ (متابِعوها الخمسون مليوناً يحوّلون منشوراً واحداً إلى 50 مليون كتابة في الـcache — دقائق من عاصفة كتابات، معظمها لأجل متابعين لن يقرأوا أصلاً. الهجين يتخطى الـpush لصالحها: منشوراتها تبقى في خطها الزمني الخاص وتُدمج في خلاصة القارئ عند القراءة فقط، من مصدر واحد ساخن ومكرَّر — فكتابة واحدة تخدم كل من يقرأ فعلاً.)

الخلاصة

قسّم التصميم إلى نشر وقراءة، والباقي يتبع: ‏push fanout يجعل القراءة بحثاً واحداً لكنه ينصهر عند المشاهير، وpull fanout يجعل الكتابة تافهة لكنه ينصهر عند كل صفحة رئيسية، والهجين — push للعاديين وpull مع دمج للمشاهير — هو سبب عمل الخلاصات الحقيقية. ثم يحمل الحملَ الـfeed cache والـcontent cache ومخزن الرسم الاجتماعي، ويقرر الترتيبُ ما يشعر به المستخدمون.

📌 افعل هذا الاثنين

اختر أي نظام تملكه حيث كتابة واحدة تتفرع إلى قرّاء كثيرين. عُدّ التفرع: متوسط المستلمين لكل كتابة، والحد الأقصى. إن كان الأقصى مئة ضعف المتوسط، فلديك مشكلة مشاهير — صمّم العتبة التي يتحول عندها push إلى pull قبل أن يكتشفها لك أول عميل مشهور.

أنظمة بحجم المنتجات