أسس التوسّع
الكاش وشبكة CDN
قاعدة بياناتك تجيب عن سؤال في 50 مللي ثانية. والذاكرة تجيب عن السؤال نفسه في 50 ميكرو ثانية — أسرع ألف مرة. كل نظام بطيء استخدمته يوماً كان في الغالب نظاماً يظل يسأل قاعدة البيانات أسئلة سبق أن أجاب عنها.
القراءات تهيمن على كل نظام تقريباً، ومعظمها مكرر: نفس الملف الشخصي، نفس صفحة المنتج، نفس قائمة المتصدرين. إرسال كل تكرار إلى قاعدة البيانات يهدر أغلى مواردها — وعلى نطاق واسع، يتحول الهدر إلى انقطاع كامل.
- عند القراءة: افحص الـcache أولاً. إن كانت البيانات موجودة (hit)، أرجعها فوراً — وقاعدة البيانات لا تستيقظ أصلاً.
- عند غيابها (miss): اقرأ من قاعدة البيانات، أرجع النتيجة، وضع نسخة في الـcache. القارئ التالي يأخذ الطريق السريع.
- عند الكتابة: حدّث قاعدة البيانات أولاً، ثم أبطل النسخة المخزنة في الـcache. القراءة التالية تفشل مرة واحدة، تعيد تحميل القيمة الجديدة، وتعيد ملء الـcache.
في نمط cache-aside يملك تطبيقك عملية ملء الـcache: فالـcache مخزن جامد، والتطبيق يقرر ما يدخل إليه ومتى يموت. أما read-through فيقلب المعادلة — الـcache نفسه يقرأ من قاعدة البيانات عند الـmiss، فيكتفي كودك بسؤال الـcache؛ استدعاءات أبسط، لكن الـcache أصبح مطالباً بفهم مصدر بياناتك. وwrite-through يمرّر كل كتابة عبر الـcache إلى قاعدة البيانات بشكل متزامن: الـcache محدّث دائماً، لكن كل كتابة تدفع كامل زمن قاعدة البيانات. وwrite-behind يذهب أبعد — يؤكد الـcache الكتابة فوراً ويدفعها إلى قاعدة البيانات على دفعات لاحقاً: كتابات خاطفة السرعة، وإن ماتت عقدة الـcache قبل الدفع، ضاعت تلك البيانات. السرعة والحداثة والمتانة — لن تحصل على الثلاثة مجاناً أبداً.
كل قيمة في الـcache لها TTL — مدة صلاحية تنتهي بعدها. TTL قصير يعني بيانات أحدث وحملاً أثقل على قاعدة البيانات؛ وTTL طويل يعني العكس. وعندما يمتلئ الـcache، تطرد سياسة إخلاء مثل LRU أقل العناصر استخداماً مؤخراً. واحذر المفتاح الساخن: إن انتهت صلاحية ملف شخصية مشهورة وقت ذروة الزيارات، سينقضّ سيل من الطلبات (thundering herd) على قاعدة البيانات دفعة واحدة — وزّع أوقات انتهاء الصلاحية أو استخدم قفلاً يجعل طلباً واحداً يعيد التحميل بينما تنتظر البقية.
تقسيم الـcache (sharding) يوزع الحمل على العقد — حتى ينفجر مفتاح واحد انفجاراً هائلاً. منشور شخصية مشهورة أو سلعة تخفيضات خاطف قد يجذب ملايين الطلبات في الثانية، وكلها تسقط على عقدة الـcache نفسها؛ ولا ينفع مفتاحاً واحداً أي قدر من التقسيم. الحل هو key-local caching: احتفظ بـL1 صغير داخل كل خادم تطبيق لحفنة المفاتيح فائقة السخونة، فلا تغادر القراءات العملية أصلاً. والثمن قِدَم مضاعف — مئات الخوادم يحمل كل منها نسخته الخاصة، ولا يصلها أي إبطال، فتنحرف النسخ جميعها حتى ينتهي TTL القصير جداً لكل منها. لا تستخدمه إلا لمفاتيح يُحتمَل فيها اختلاف بضع ثوانٍ، مثل عدادات المشاهدة — لا لرصيد مالي أبداً.
الملفات الثابتة — الصور والفيديوهات وحزم JavaScript — لا ينبغي أن تسافر من مركز بياناتك الوحيد إلى كل مستخدم على الأرض. شبكة CDN تنسخها إلى خوادم edge قريبة من المستخدمين وتقدمها من هناك، ملتزمة بترويسات TTL التي تحددها. وعندما تحتاج استبدال ملف قبل انتهاء مدته، تبطله صراحةً لدى الـCDN. الفيزياء هي نفس فيزياء الـcache؛ الجديد هنا هو الجغرافيا.
منطقة push تعمل كمستودع تملؤه بنفسك: ترفع الملفات إلى تخزين الـCDN، وكل خادم edge يقدم نسختك حتى تستبدلها. أنت تتحكم تماماً بما يراه المستخدمون، وخادمك الأصلي لا يحمل أي زيارات — مثالية للملفات الضخمة نادرة التغير كالفيديوهات وحزم التثبيت، وثمنها أن عملية النشر تقع عليك. أما منطقة pull فتعمل كمتجر يطلب البضاعة عند الحاجة: الـCDN يجلب من خادمك الأصلي عند أول miss في كل edge، يخزن النسخة، ويقدمها للتكرارات. الإعداد شبه معدوم — وجّه الـCDN إلى خادمك وامضِ في طريقك — لكن أول مستخدم في كل منطقة يدفع ثمن رحلة بطيئة كاملة، ويجب أن يبقى خادمك الأصلي حياً وسريعاً بما يكفي لملء الكاشات. اختر push للتحكم، وpull للراحة.
الـcache ليس قاعدة بيانات صغيرة — هو رهان على أن بعض البيانات تُقرأ أكثر بكثير مما تتغير. لا تضع هذا الرهان إلا حيث الاحتمالات في صالحك، واعرف دائماً ما الذي تخسره إذا قدُمت البيانات.
لا تتعامل مع الـcache كمصدر للحقيقة أبداً. الكاشات تفقد البيانات، وتنتهي صلاحية عناصرها، وقد تمُحى بإعادة تشغيل — قاعدة البيانات هي الحقيقة، والـcache مجرد طريق مختصر. أي مسار كتابة يحدّث الـcache دون قاعدة البيانات هو خطأ فقدان بيانات ينتظر لحظته.
في نمط cache-aside، لماذا تبطل الكتابةُ الـcache بدل تحديثه — وما الذي يفسد لو حدّثت الـcache ونسيت قاعدة البيانات؟ (الإبطال يتجنب تسابق الكتابات المتزامنة ويُبقي مصدراً واحداً للحقيقة؛ ونسيان قاعدة البيانات يعني أن مسح الـcache سيمحو بيانات المستخدمين بصمت.)
الذاكرة تتفوق على القرص بألف مرة، لذا أجب عن التكرارات من الذاكرة: افحص الـcache ← غياب ← قاعدة البيانات ← املأ؛ وعند الكتابة حدّث قاعدة البيانات وأبطل النسخة. اختر درجة قِدم البيانات بوعي عبر TTL، واحمِ المفاتيح الساخنة من الانقضاض الجماعي، ودع CDN يقوم بالحيلة نفسها للملفات الثابتة قرب مستخدميك.
حدد أكثر ثلاث قراءات تكراراً في نظام تملكه. لكل واحدة اكتب: كم مرة تتغير، وما كلفة إجابة قديمة، وما قيمة TTL التي يمكنك التعايش معها. هذه قائمة مرشحيك للتخزين المؤقت.
أسس التوسّع