🗺️ الخريطة

البداية٣ فصول
فصل ١ليه تحط كاش قدام الداتابيز أصلًا؟#سرعة #حمل الداتابيز #hit rate #إمتى لأ
فصل ٢أنماط الكاش — Cache-Aside وأخواته#cache-aside #write-through #write-behind #TTL #أسماء الـ keys
فصل ٣الـ Invalidation والـ Consistency#مسح ولا تحديث #race #double delete #CDC
المشكلةفصل واحد
فصل ٤المشكلة — الـ Cache Stampede على Hot Key#hot key #TTL خلص #pool اتملى #retries #محاكاة
الحلول٣ فصول
فصل ٥الحل الأول — طلب واحد بس يروح للداتابيز#single-flight #SET NX PX #Lua #الانتظار #lock TTL
فصل ٦الحل التاني — TTL Jitter ضد الـ Cache Avalanche#jitter #avalanche #deploy #bulk load #±10٪
فصل ٧حلول تانية — متخليش الـ Key يخلص أصلًا#soft/hard TTL #XFetch #refresh-ahead #warming #lru-cache #نسخ الـ hot key
الحماية٣ فصول
فصل ٨احمي الداتابيز حتى لو الكاش فشل#pool #timeouts #circuit breaker #load shedding #bulkhead #retries
فصل ٩مشاكل الكاش التانية — Penetration والـ Avalanche والـ Big Keys#penetration #negative cache #bloom #big keys #Redis وقع
فصل ١٠تشوف المشكلة قبل ما تحصل — Metrics والـ Alerts#hit ratio #DB QPS #pool waiting #lock #hotkeys #alerts
بعدهافصل واحد
الآخرCheat Sheet: الكاش قدام الداتابيز#المشكلة والحل في سطر

المذكرة دي بتجاوب على سؤالين. الأول: إمتى وليه وإزاي تحط كاش قدام الداتابيز؟ والتاني: إزاي الكاش اللي المفروض يحمي الداتابيز يبقى هو نفسه السبب إنها تقع؟

المشكلة بالظبط كده:

  • عندك key سخن: بيتقري أكتر من 10,000 مرة في الثانية.
  • الـ TTL بتاعه خلص: فجأة كل الـ requests مش لاقية القيمة في الكاش.
  • كلهم راحوا للداتابيز: في نفس اللحظة، بنفس الـ query.
  • الداتابيز بطّأت: فالـ requests فضلت مستنية، والـ connection pool اتملى للآخر.
  • الـ requests الجديدة بتفشل: قبل ما تبدأ أصلًا، لأنها مش لاقية connection.

الحل الأساسي: request واحد بس يروح للداتابيز ويجيب القيمة ويحطها في الكاش، والباقي يستنوه. ومعاه: إن الـ TTLs كلها متخلصش في نفس اللحظة (jitter).

terminal
docker run -d --rm --name redis -p 6379:6379 redis:7-alpinedocker run -d --rm --name pg -e POSTGRES_PASSWORD=pass -p 5432:5432 postgres:16-alpinemkdir cache-lab && cd cache-lab && pnpm init && pnpm add ioredis pg lru-cacheexport REDIS_URL=redis://127.0.0.1:6379export DATABASE_URL=postgres://postgres:pass@127.0.0.1:5432/postgres