تمكن موقع فيديو يشهد حركة مرور عالية من خفض استعلامات قاعدة البيانات لصفحة "المحتوى الرائج" (trending-page) من 4,000 استعلام في الدقيقة إلى أقل من 50، كما خفّض زمن الاستجابة عند المئين الخامس والتسعين (95th-percentile) من 380 مللي ثانية إلى 40 مللي ثانية، وذلك عبر الانتقال من تخزين الصفحة بالكامل في الذاكرة المخبئية (whole-page caching) إلى تخزين الأجزاء (fragment caching) باستخدام Varnish و Edge Side Includes (ESI).
لماذا احتاج الموقع إلى استراتيجية تخزين مؤقت مختلفة
تبدو الصفحة الرئيسية التي تعرض أكثر المقاطع مشاهدة لهذا اليوم متشابهة لكل زائر في منطقة معينة تقريبًا: حوالي 95% من كود HTML متطابق لمليون مستخدم، بينما الـ 5% المتبقية تحمل بيانات شخصية مثل اسم المستخدم المسجل دخوله أو مربع البحث. واجه الفريق الهندسي خيارين غير مرغوب فيهما:
- تخزين الصفحة بالكامل في الذاكرة المخبئية والمخاطرة بتقديم بيانات شخصية قديمة للمستخدمين المسجلين دخولهم.
- تجاوز الذاكرة المخبئية تمامًا وترك كل طلب يرهق قاعدة البيانات.
كلا النهجين أفسدا تجربة المستخدم. لذا لجأ الفريق إلى ESI، وهي تقنية تسمح لبروكسي عكسي (reverse-proxy) بتجميع الصفحة من أجزاء مخزنة مؤقتًا بشكل مستقل عند حافة الشبكة (edge of the network).
كيف تم إعداد تخزين الأجزاء مؤقتًا
تعامل Varnish، وهو مسرع HTTP مفتوح المصدر، مع الصفحة كأنها هيكل يتكون من ثلاث قطع قابلة للاستبدال:
- شبكة الفيديو (Video grid) – القائمة المكلفة للفيديوهات الرائجة على مستوى المنطقة. يتم تخزينها مؤقتًا لمدة 60 ثانية لأنها تتغير بشكل متكرر ولكنها تظل كما هي لكل زائر مجهول.
- مبدل اللغة (Language switcher) – عنصر واجهة مستخدم ثابت نادرًا ما يتغير. يتم تخزينه مؤقتًا لمدة 24 ساعة.
- الترويسة (Header) – الجزء الشخصي الوحيد حقًا (اسم المستخدم، الصورة الرمزية، التنبيهات). لا يتم تخزينه مؤقتًا أبدًا؛ حيث يقوم Varnish بتوجيه الطلب إلى خادم التطبيق في كل مرة.
عند وصول طلب ما، يقدم Varnish الهيكل المخزن مؤقتًا، ويسحب الجزأين المخزنين من مخزنه المحلي، ثم يدرج الترويسة المباشرة من النظام الخلفي (backend).
الأرقام التي تهم
بعد هذا التحول:
- انخفض حمل قاعدة البيانات لصفحة المحتوى الرائج من 4,000 استعلام في الدقيقة إلى أقل من 50.
- انخفض زمن التأخير عند المئين الخامس والتسعين من 380 مللي ثانية إلى 40 مللي ثانية.
ثلاثة دروس عملية من عملية الإطلاق
1. فترات السماح (Grace periods) تقلل من حدة حالات عدم وجود بيانات في الذاكرة المخبئية عندما تنتهي صلاحية (TTL) أحد الأجزاء، يتوقف Varnish عادةً لجلب محتوى جديد، مما يتسبب في ارتفاع مفاجئ في زمن التأخير قد يؤدي إلى "تدافع القطيع" (thundering herd) من طلبات النظام الخلفي المتزامنة. من خلال تكوين فترة سماح، يستمر Varnish في تقديم الجزء القديم بينما يقوم بتحديث الذاكرة المخبئية بصمت في الخلفية. لا يشعر المستخدمون بأي توقف، ويرى النظام الخلفي معدل طلبات ثابتًا ويمكن إدارته.
2. تجريد ملفات تعريف الارتباط (Cookies) للأجزاء المجهولة ملفات تعريف الارتباط المرفقة بكل طلب تجعل Varnish يعامل كل طلب كطلب فريد، مما يبطل فعالية الذاكرة المخبئية. قام الفريق بتجريد ملفات تعريف الارتباط من شبكة الفيديو ومبدل اللغة، مما سمح بتخزين تلك الأجزاء مؤقتًا بشكل مكثف. فقط جزء الترويسة يحمل ملفات تعريف الارتباط، مما يحافظ على التخصيص دون التضحية بكفاءة الذاكرة المخبئية.
3. المفاتيح البديلة (Surrogate keys) تتيح المسح الفوري أحيانًا يجب إزالة فيديو ما على الفور — على سبيل المثال، لأسباب تتعلق بحقوق الطبع والنشر. والانتظار حتى تنتهي صلاحية الـ TTL البالغة 60 ثانية أمر غير مقبول. من خلال وسم كل جزء مخزن مؤقتًا بمفتاح بديل يعكس معرفات الفيديو الأساسية، يصدر الفريق أمر مسح (purge) واحد يبطل فورًا جميع نسخ فيديو معين عبر كل عقدة حافة (edge node). وهذا يتجنب عملية مسح كاملة للذاكرة المخبئية ويحافظ على امتثال الموقع.
الخلاصة: يحول تخزين الأجزاء مؤقتًا باستخدام Varnish و ESI الصفحة الضخمة المرتبطة بقاعدة البيانات إلى مجموعة من القطع الخفيفة والقابلة لإعادة الاستخدام، مما يقلل بشكل كبير من حمل النظام الخلفي وزمن التأخير مع الحفاظ على التخصيص لكل مستخدم.
