البداية · فصل ١

ليه تحط كاش قدام الداتابيز أصلًا؟

latency · DB load · cost · hit rate · read-heavy · staleness
🎯 الهدف: تعرف الكاش بيكسّبك إيه، وإمتى يفيد وإمتى يضر، وتحسب الـ hit rate بإيدك.

الفكرة في سطر

الكاش مخزن سريع وقريب بتحط فيه نسخة من حاجة غالية تجيبها، عشان المرة الجاية تاخدها من غير ما تدفع التمن تاني.

  • الحاجة الغالية: query تقيلة على الداتابيز، أو حساب، أو call لـ API تاني.
  • المخزن السريع: غالبًا Redis أو Memcached (في الـ memory، على الشبكة)، أو memory الـ process نفسه.
  • النسخة دي مؤقتة: ليها عمر (TTL)، وممكن تبقى قديمة عن الداتابيز شوية.
الكاش مش مكان الحقيقة. الداتابيز هي الحقيقة، والكاش نسخة سريعة منها.

بيكسّبك إيه؟

سرعة (latency)

قراءة من Redis في نفس الـ data center بتاخد أقل من ملّي ثانية تقريبًا. query عليها joins وaggregations ممكن تاخد عشرات أو مئات الملّي ثانية.

حمل أقل على الداتابيز

كل request بيتخدم من الكاش هو request مراحش للداتابيز. فالداتابيز بتفضل فاضية للـ writes والـ queries اللي ملهاش كاش.

فلوس أقل

تكبير الداتابيز (CPU أكتر، replicas) غالي وصعب. شوية Redis قدامها غالبًا أرخص بكتير من إنك تكبّرها.

امتصاص الزحمة

لما الـ traffic يعلى فجأة على نفس البيانات، الكاش بيشيل الضربة بدل الداتابيز. بس لو اتعمل صح، وده موضوع المذكرة كلها.

إمتى الكاش يفيد؟

  • القراءة أكتر بكتير من الكتابة: صفحة منتج بتتقري ألف مرة وبتتعدل مرة في اليوم.
  • الـ query غالية: joins كتير، أو COUNT/SUM على جداول كبيرة، أو ترتيب وفلترة.
  • نفس البيانات بتتطلب كتير: الـ homepage، الـ categories، الإعدادات، المنتجات المشهورة.
  • البيانات تستحمل تبقى قديمة شوية: عدد المشاهدات لو اتأخر ٣٠ ثانية مفيش مشكلة.

إمتى الكاش يضر أو ملوش لازمة؟

  • الكتابة كتير: لو القيمة بتتغير كل ثانية، هتقضي وقتك بتمسح الكاش وتملاه، والـ hit rate هيبقى واطي.
  • محتاج consistency قوية: رصيد الحساب البنكي، المخزون وقت الدفع، الصلاحيات بعد ما اتسحبت. هنا القيمة القديمة غلطة مش تأخير.
  • الـ hit rate واطي: لو كل request بيطلب key مختلف، الكاش مجرد خطوة زيادة قبل الداتابيز.
  • بيانات خاصة بكل يوزر ومش بتتكرر: نتيجة بحث فريدة ليوزر واحد مش هتتطلب تاني غالبًا.
  • الداتابيز أصلًا سريعة: query على primary key بـ index بتاخد ملّي ثانية. اتأكد إن فيه مشكلة قبل ما تزود طبقة.

نكاش إيه؟

النوعمثالملاحظة
نتيجة querySELECT * FROM products WHERE id = $1الأشهر، والـ key فيه الـ id
حساب مجمّععدد الطلبات النهارده، الـ top 10غالي جدًا يتحسب كل مرة
object جاهزالمنتج بالـ reviews والصور مع بعضبتجمّع كذا query في قيمة واحدة
sessionبيانات اليوزر اللي عامل loginغالبًا Redis هو المكان الأساسي ليها مش كاش
response كاملJSON بتاع endpoint عاملو نفس الـ response لكل الناس

حسبة الـ hit rate

الـ hit rate هو نسبة الـ requests اللي لقت القيمة في الكاش.

الحسبة
hit rate      = hits / (hits + misses)متوسط الوقت  = (hit rate × وقت الكاش) + (miss rate × (وقت الكاش + وقت الداتابيز))حمل الداتابيز = عدد الـ requests في الثانية × miss rate

مثال: 10,000 request في الثانية، والكاش بياخد 1ms، والداتابيز 20ms.

الـ hit rateمتوسط الوقتالـ requests اللي بتوصل الداتابيز
0% (من غير كاش)20ms10,000 / ثانية
90%1 + 0.10 × 20 = 3ms1,000 / ثانية
95%1 + 0.05 × 20 = 2ms500 / ثانية
99%1 + 0.01 × 20 = 1.2ms100 / ثانية
  • لاحظ القفزة: من 95% لـ 99% شكلها ٤% بس، بس حمل الداتابيز قلّ ٥ مرات.
  • يعني إيه؟ الداتابيز متصممة على إن الـ miss rate صغير. لو الكاش فجأة بطّل يشتغل (أو key سخن خلص)، الحمل بيرجع ١٠,٠٠٠ مرة واحدة. ودي بالظبط بداية المشكلة اللي في المذكرة.

خلّصت الفصل لما

🧠 اختبر نفسك
١) رصيد المحفظة وقت الدفع، تكاشه؟
لأ. محتاج consistency قوية، والقيمة القديمة هنا ممكن تخلي اليوزر يدفع بفلوس مش معاه.
٢) 20,000 request في الثانية والـ hit rate بتاعك 98%. كام request بيوصل الداتابيز؟
20,000 × 0.02 = 400 request في الثانية.
٣) كل يوزر بيعمل بحث بكلمات مختلفة تمامًا. الكاش هيفيد؟
غالبًا لأ، لأن نفس الـ key مش هيتطلب تاني، فالـ hit rate هيبقى واطي والكاش خطوة زيادة.