الآخر

Cheat Sheet: الكاش قدام الداتابيز

cache-aside · TTL · invalidation · stampede · lock · jitter · SWR · XFetch · pool · breaker · penetration · metrics
🎯 الهدف: تفتكر كل قاعدة وكل حل في المذكرة بسرعة.
أكاش إمتى؟قراءة أكتر من الكتابة، query غالية، نفس البيانات بتتطلب، وتستحمل تبقى قديمة شوية
مكاشش إمتى؟كتابة كتير، consistency قوية (فلوس/مخزون وقت الدفع)، hit rate واطي، بيانات فريدة لكل يوزر
حمل الداتابيزQPS × miss rate، ومن 95٪ لـ 99٪ hit يقلل الحمل 5 مرات
الداتابيز تصغر؟لأ، لازم تستحمل كاش فاضي (restart، deploy، hot key)
النمط الافتراضيcache-aside: GET، لو miss هات من DB وSET key val EX ttl
null من ioredisيعني مش موجود، فاكتب cached !== null مش if (cached)
write-throughاكتب في DB والكاش مع بعض، الكاش حديث بس الـ write أبطأ
write-behindاكتب في الكاش والـ DB بعدين، سريع بس ممكن تضيع بيانات
write-aroundاكتب في DB بس، والكاش يتملي وقت القراءة
الـ TTLعلى قد ما القيمة تستحمل تبقى قديمة، ودايمًا موجود كشبكة أمان
اسم الـ keyنوع:version:id، وأي حاجة بتغيّر النتيجة جوه الـ key
غيّرت شكل الـ objectزوّد الـ version: product:v1 ← product:v2
وقت الكتابةUPDATE الأول وبعدين DEL، والمسح أأمن من التحديث
قيمة قديمة بعد المسحrace بين قراءة بطيئة والمسح، فاعمل delayed double delete
مسح مجموعة keysversioned namespace: INCR category:5:version
حد بيكتب من بره التطبيقCDC (Debezium / WAL) يمسح الكاش
الـ stampedehot key خلص، آلاف miss مع بعض، الداتابيز بطّأت، الـ pool اتملى
عدد الـ missesQPS × وقت الـ query، وبيكبر لما الداتابيز تبطّأ
pg بيستنى للأبدdefault connectionTimeoutMillis هو 0، فحط قيمة
retry stormrefresh + retries تلقائية بتضاعف الحمل وقت الضعف
جوه الـ processsingle-flight: Map للـ Promise اللي شغالة + finally يمسح
بين الـ instancesSET lock:key token NX PX 5000 في أمر واحد
فك الـ lockLua: امسح بس لو القيمة هي الـ token بتاعك
بعد ما تاخد الـ lockdouble-check: اقرا الكاش تاني قبل الـ query
المستنيينpoll بـ backoff + jitter لحد waitMs، أو stale، أو fallback
الـ lock TTLأطول من أطول query، ومعاه statement_timeout
Redlockمش محتاجه للكاش، أسوأ حاجة 2 queries بدل 1
الـ jitterttl ± 10–20%، أو ينقص بس لو فيه حد أقصى للقدم
الـ avalanchekeys كتير خلصت مع بعض أو الكاش وقع: jitter + warming
الـ jitter والـ hot keyمش كفاية، محتاج lock أو refresh قبل الـ expiry
stale-while-revalidatesoft TTL جوه القيمة + hard TTL في Redis، ورجّع القديم وجدد في الخلفية
XFetchجدد لو now - delta × beta × ln(rand) >= expiry، ومعاه single-flight
refresh-aheadjob بـ lock بيجدد الـ hot keys المعروفة قبل ما تخلص
never expireللإعدادات والـ flags، مع job بيصلّح أو TTL طويل
بعد deploycache warming للـ hot keys بـ batches وjitter
Redis نفسه سخنL1 بـ lru-cache وTTL ثانية أو اتنين
node واحدة في Cluster سخنةانسخ الـ key على كذا slot أو اقرا من الـ replicas
الـ poolmax صغير، connectionTimeoutMillis قصير، statement_timeout
حساب الـ maxinstances × max أقل من max_connections، أو PgBouncer
الـ timeoutsاللي جوه أقصر من اللي بره
load sheddingpool.waitingCount عالي ← 503 + Retry-After على طول
circuit breakerclosed ← open بعد أخطاء ← half-open يجرّب ← closed
bulkheadspool منفصل للحاجات المهمة زي checkout
retries2–3 مرات، backoff أُسّي، full jitter، في طبقة واحدة
penetrationkeys مش موجودة: __null__ بـ TTL قصير + bloom filter + validation
bloom filterلأ = أكيد مش موجود، آه = غالبًا موجود
breakdownاسم تاني للـ hot key اللي خلص = المشكلة الأساسية
Redis وقعcommandTimeout قصير، enableOfflineQueue: false، وsingle-flight وbreaker قدام DB
big keys--bigkeys، قسّمها، وامسح بـ UNLINK
أهم metrichit ratio لكل نوع key، وmisses في الثانية
أبكر إنذارpool.waitingCount أكبر من صفر
hot keysredis-cli --hotkeys مع LFU، أو اعدّ في الكود
labels الـ metricsنوع الـ key مش الـ id

خلّصت المذكرة لما

🧠 اختبر نفسك
١) hot key بـ 10,000 read في الثانية، والـ TTL بيخلص كل 5 دقايق والداتابيز بتضرب. أقل حاجة تعملها؟
single-flight + lock موزّع بـ SET NX PX، وأحسن منها stale-while-revalidate عشان محدش يستنى.
٢) كل ساعة بالظبط الداتابيز بتضرب دقيقة. والـ hot keys محمية. المشكلة غالبًا؟
avalanche: keys كتير بنفس الـ TTL اتملت مع بعض. الحل jitter.
٣) Redis وقع، إيه اللي يمنع الداتابيز تقع وراه؟
timeouts قصيرة على Redis، وsingle-flight جوه الـ process، وcircuit breaker، وload shedding، وL1 cache.