০০ যে প্রশ্নগুলোর উত্তর খুঁজবো
সবগুলো প্রশ্নের উত্তর জানার পর আপনি cache এর basic idea থেকে production failure mode পর্যন্ত সবকিছু বুঝতে পারবেন।
- ১ আমার cache কেন দরকার?
- ২ Cache আসলে কতটা fast? এত ঝামেলা কি worth?
- ৩ App এ cache কীভাবে ব্যবহার করব?
- ৪ DB এর data পরিবর্তন হলে cache কীভাবে adjust হবে?
- ৫ Cache এর memory সীমিত। Cache full হলে কী হবে?
- ৬ Invalidation আর Eviction এর মধ্যে পার্থক্য কী?
- ৭ আমি কি সব কিছু cache করব?
- ৮ Production caching এ কী কী জটিলতা আসতে পারে?
- ৯ আমাদের পুরো system এখন দেখতে কেমন?
০১ Cache কেন দরকার?
ভাবুন আপনি একটা সরকারি অফিসে কাজ করেন। সারাদিন মানুষ আপনার কাছে একই form নিতে আসে। প্রতিবার আপনাকে basement এ যেতে হয়, file খোলেন, form photocopy করেন, form দেন। প্রতিবার ৫ মিনিট লাগে।
৫০ বার এটা করার পর একজন বুদ্ধিমান মানুষ কী করবেন? সবচেয়ে বেশি লাগে এমন form গুলোর কপি নিজের desk এ রেখে দেবেন। কেউ চাইলে ২ সেকেন্ডে হাতে দিয়ে দেবেন। Basement এ যাবেন শুধু stock শেষ হলে।
এটাই Caching।
Expensive কাজের answer কোনো fast জায়গায় store করে রাখা, যাতে সেই expensive কাজ বারবার করতে না হয়।
০২ Cache আসলে কতটা faster?
Cache থাকে RAM এ। এবার নিচের সংখ্যাগুলো দেখুনঃ
| Operation | Time |
|---|---|
| CPU cache (L1) | ~১ nanosecond |
| RAM | ~১০০ nanoseconds |
| SSD | ~১,০০,০০০ nanoseconds (১০০ µs) |
| HDD | ~১,০০,০০,০০০ nanoseconds (১০ ms) |
| Database (network এর মধ্য দিয়ে) | ~১-১০ milliseconds |
| Across continents | ~১৫০ milliseconds |
RAM থেকে read, HDD থেকে read এর চেয়ে ১,০০,০০০ গুণ দ্রুত। Cache (RAM) থেকে data নেওয়া আর network এর মধ্য দিয়ে database এ গিয়ে data আনার মধ্যে ১০,০০০ গুণ পার্থক্য।
Slow operation (DB query, network call, computation) কে fast memory lookup এ পরিণত করা।
লাইব্রেরির গল্প
একটা লাইব্রেরির basement এ হাজার হাজার বই আছে। Basement এ গিয়ে একটা বই আনতে ১০ মিনিট লাগে। Librarian দেখলেন প্রতিদিন ২০ জন student “Introduction to Machine Learning” বইটা চায়। তিনি ওই বইয়ের কয়েকটা কপি সামনের desk এ রেখে দিলেন। এখন সেই student রা ১০ সেকেন্ডে বই পেয়ে যাচ্ছে।
সামনের desk এর shelf হলো cache, আর basement হলো database।
এই analogy থেকে চারটা কঠিন প্রশ্ন আসেঃ
- কী cache করব (space সীমিত বলে)।
- Cache full হলে কী সরাব (eviction)।
- Data বদলালে cache কীভাবে fresh রাখব (invalidation)।
- Cache down হলে কী হবে (DB এখনো source of truth)।
০৩ App এ cache use করব কীভাবে?
Modern application এ একাধিক layer এ cache থাকে। এই session এর focus Distributed Cache (Redis), যা সবচেয়ে গুরুত্বপূর্ণ layer।
Cache-Aside Pattern (সবচেয়ে common)
App প্রথমে cache দেখে। Data থাকলে ব্যবহার করে (hit)। না থাকলে (miss) DB তে যায়, data পায়, cache এ রেখে দেয়, যাতে পরের বার কাজে লাগে।
function getUser(id):
user = cache.get(id)
if user exists:
return user # cache hit
user = database.get(id) # cache miss
cache.set(id, user)
return user
দুটো গুরুত্বপূর্ণ term জেনে রাখুনঃ
- Cache hit (ক্যাশ হিট): data cache এ ছিল।
- Cache miss (ক্যাশ মিস): data cache এ ছিল না, DB তে যেতে হয়েছে।
ভালো cache এর target হলো ৯০% এর বেশি hit rate।
০৪ DB এর data পরিবর্তন হলে cache কীভাবে adjust হবে?
“There are only two hard things in computer science: cache invalidation and naming things.” - Phil Karlton
সমস্যাঃ
Step 1: User 31 এর name "Roy"। Step 2: DB তে name update হলো "Mr. Roy"। Cache এ এখনো "Roy"। Step 3: পরের read আসবে cache থেকে। "Roy" return হবে। যেটা ভুল ডেটা!
তিনটা strategy
DB আর cache দুটোতেই একসাথে write করা হয়।
- সুবিধা: Cache সবসময় fresh থাকে।
- Downside: Write slow হয়। DB write success হলো, কিন্তু cache write fail হলে silent inconsistency তৈরি হয়।
Update হলে DB তে write করা হয়, আর cache entry delete করা হয়। পরের read টা miss হবে, ফলে fresh DB data cache এ write হবে।
- সুবিধা: Simple। Cache হয় correct থাকবে, নয়তো missing থাকবে, কখনো wrong থাকবে না।
- Downside: Delete এর পর একসাথে অনেক read এলে অনেক cache miss হয়, DB তে চাপ পড়ে।
প্রতিটা cache entry নির্দিষ্ট সময় (যেমন ৬০ সেকেন্ড) পর নিজে থেকে expire হবে।
- সুবিধা: খুবই simple। Self-healing।
- Downside: TTL period এর মধ্যে data stale থাকতে পারে।
Real systems এ তিনটার combination
- Read এর জন্য Cache-aside।
- Invalidation এর জন্য Delete-on-write।
- Safety net হিসেবে TTL (যদি invalidation fail হয়)।
Layered defense। একটা fail হলে আরেকটা কাজ করে।
০৫ Cache full হলে কী হবে?
Cache এর memory সীমিত। Full হলে memory free করার ব্যবস্থা করতে হবে। এটাকে বলা হয় Eviction (ইভিকশন)।
| Policy | আচরণ | কখন ব্যবহার করবেন |
|---|---|---|
| LRU (Least Recently Used) | সবচেয়ে আগে access হওয়া entry সরায় | সবচেয়ে common, real-world scenario তে ভালো কাজ করে |
| LFU (Least Frequently Used) | সবচেয়ে কমবার access হওয়া entry সরায় | recency এর চেয়ে popularity বেশি গুরুত্বপূর্ণ হলে |
| FIFO (First In First Out) | সবচেয়ে আগে আসা entry সরায় | simple, কিন্তু বেশিরভাগ ক্ষেত্রে এটা ভুল strategy (শুধু কখন entry এসেছে সেটা দেখে, কতবার ব্যবহার হয়েছে সেটা দেখে না) |
| TTL | নির্দিষ্ট সময় পর entry delete করে | সাধারণত অন্য policy (LRU/LFU) এর সাথে combine করে ব্যবহার হয় |
Real systems এ বেশিরভাগ সময় LRU ব্যবহার হয়।
০৬ Invalidation বনাম Eviction এর পার্থক্য কী?
অনেকেই Invalidation আর Eviction এই দুটো term প্রায়ই গুলিয়ে ফেলে।
Trigger: আপনি (application code)।
DB বদলায়, আপনি গিয়ে cache কে বলেন “এই entry আর valid না।”
দুটো উপায়ঃ
- Delete করুন: entry সরিয়ে দিন। পরের read এ cache miss হয়, DB থেকে fresh data আসে, cache আবার fill হয়। সহজ এবং safe।
- Replace করুন: entry delete না করে নতুন data দিয়ে replace করুন। পরের read এ সরাসরি cache থেকেই data পাবে, DB hit লাগবে না।
Method আলাদা, goal একটাইঃ cache যেন stale না থাকে।
Trigger: cache নিজে।
Cache নিজেই সরিয়ে দেয়। আপনাকে জিজ্ঞেস করবে না।
Memory full হলো, LRU policy তে সবচেয়ে পুরনো entry সরে গেল। কিংবা TTL শেষ হলো, entry expire হলো।
| Invalidation | Eviction | |
|---|---|---|
| কে সরায় | আপনি (application code) | Cache নিজে |
| কেন সরায় | Source of truth বদলে গেছে | Memory full, TTL শেষ, বা restart |
| Goal | Freshness নিশ্চিত করা | Memory manage করা |
| পরের read এ কী হয় | Delete করলে miss হয়, DB থেকে fresh data আসে। Replace করলে সরাসরি cache থেকে latest data পাওয়া যায়। | Miss হয়, DB থেকে data আসে (থাকলে) |
০৭ সব কিছু cache করব?
প্রতিটা data এর জন্য তিনটা প্রশ্ন করুন:
- এটা কি read often?
- এটা কি change often?
- Stale data কি acceptable?
ভালো cache candidate এর উদাহরণঃ
| Data | কেন |
|---|---|
| User profile | প্রায়ই read, কম change, সামান্য staleness acceptable |
| Product catalog | সবসময় read, কম change |
| Homepage feed | অনেক user এর জন্য একই, compute করা expensive |
| Top 10 trending posts | Compute expensive, staleness acceptable |
| Search results | Popular query repeat হয়, short TTL দিয়ে cache |
খারাপ cache candidate এর উদাহরণঃ
| Data | কেন |
|---|---|
| Bank account balance | Stale হলে মারাত্মক ভুল হয় |
| Live chat messages | সারাক্ষণ change হয় |
| Real-time stock price | Stale হলে ভুল হয় |
| One-time token | একবার ব্যবহারের জন্য, cache এ কোনো benefit নেই |
”সবকিছু cache করুন” concept টা কেন বিপজ্জনক
- Cache free না: memory cost আছে।
- Stale এর cost context ভেদে আলাদা: stale tweet count acceptable, stale bank balance acceptable না।
- কিছু data এত দ্রুত change হয় যে cache রাখার আগেই বদলে যায়।
- কিছু data per-request unique: এতে cache এর কোনো benefit নেই।
Read-heavy, compute এ slow, আর staleness tolerant, এসব ক্ষেত্রে cache করুন। Critical real-time বা one-time data cache করবেন না।
০৮ Production caching-এ কী কী জটিলতা আসতে পারে?
সমস্যা ১: Cache Stampede (Thundering Herd)
Popular cached item expire হলো। হাজার হাজার request একই মুহূর্তে cache miss করে। সবাই একসাথে DB তে request করে। DB overloaded হয়ে crash করে।
At t=60s: cache entry expire হলো। At t=60.001s: ১০,০০০ request এলো। সব ১০,০০০ cache miss করল। সব ১০,০০০ DB তে query করল। DB crushed।
সমাধানঃ
- Lock + recompute: একটা request DB তে যায়, বাকিরা wait করে।
- Stale-while-revalidate: এক request fresh data আনতে গেলে বাকিরা stale value পায়।
- TTL jitter: expiry randomize করা হয় (TTL=৬০±৫s) যাতে একসাথে সব expire না হয়।
সমস্যা ২: Cache Penetration
DB তে যেগুলো নেই, সেগুলোর জন্য request আসে। Cache কোনো সাহায্য করতে পারে না।
Request: "Get user_999999999" (নেই) Cache: miss DB: nothing Cache: store করার মতো কিছু নেই Request আবার এলো → DB আবার query → অনন্তকাল চলবে...
সমাধানঃ
- Negative result cache করুন: “NOT_FOUND” কিছু সময়ের জন্য store করে রাখুন।
- Bloom filter ব্যবহার করুন: এটা একটা probabilistic data structure (সম্ভাবনার ভিত্তিতে উত্তর দেয়)। এর কাজ হলো খুব fast ভাবে বলে দেওয়া, “এই key টা DB তে definitely নেই” অথবা “হয়তো আছে”। Bloom filter যদি বলে “নেই”, তাহলে DB তে query করার দরকারই নেই। সরাসরি reject করুন। এতে cache penetration attack থেকে DB রক্ষা পায়।
সমস্যা ৩: Cache Avalanche
অনেক cache entry একসাথে expire হলো, বা cache server নিজেই down হলো। DB overwhelmed হয়।
সমাধান:
- TTL jitter।
- Cache redundancy (multiple cache server)।
- Graceful degradation: cache হঠাৎ down হলে সব request একসাথে DB তে চলে আসে। DB সেই load নিতে পারে না, crash করে। তাই request গুলো throttle করুন, rate limit সেট করুন। কিছু request কে wait করান বা reject করুন। App slow হবে, কিন্তু পুরো system fail করবে না।
সমস্যা ৪: Cold Cache
Cache restart হলে সেই মুহূর্তে cache পুরোপুরি empty থাকে। প্রতিটা request cache miss করে, ফলে DB overloaded হয়।
সমাধান: Cache warming (traffic আসার আগে cache pre-populate করা)।
০৯ System এখন দেখতে কেমন?
সেশন ০৩ এর সাথে এখন Cache layer যোগ হলো। অনেক read এখন database পর্যন্ত যায়ই না।
এখন পর্যন্ত কি কি ঠিক করা হলো?
- DB Load কমেছে dramatically - বেশিরভাগ read cache থেকেই আসে।
- Response time অনেক faster - DB query (১০ms) থেকে cache lookup (১ms)।
- একই DB আরো অধিক traffic handle - cache hit ৯৫%, DB load ২০ গুণ কম (db hit ৫%)।
নতুন যেসব সমস্যা তৈরি হলো
- Cache Invalidation - DB তে data change হলে cache এর সেই entry টাকে কখন এবং কীভাবে update/delete করবো, এটা ম্যানেজ করা কঠিন।
- Cache Stampede / Penetration / Avalanche - cache fail করলে DB melt।
- Cold cache - cache restart হলে DB তে সব load যায়, dangerous।
- Memory cost - cache এর জন্য আলাদা মেশিন।
যা এখনো বাকি
- দূরের ইউজার - cache same data center এ থাকলে শুধু সেই region এর user রা benefit পায়। অন্য মহাদেশের user দের জন্য network latency রয়েই গেছে। Geographic distance এর কারণে cache খুব একটা বেনিফিট দিতে পারবে না।
- Static content (image, CSS, JS) - একটা web page এ database call হয়তো ২-৩ টা, কিন্তু image/CSS/JS file থাকতে পারে ৫০-১০০ টা। এই static file গুলো প্রতিবার origin server থেকে download হচ্ছে - প্রতিটার জন্য full network round trip।
- Write traffic এখনো এক Primary তে - cache শুধু read এ help করছে।
১০ মগজে প্রেশার দিন
আগে নিজে ভাবুন। তারপর দেখুন, সবাই যেভাবে ভাবে, কেন ভুল, আর সঠিক চিন্তা কী।
উত্তর দেখুন আগে নিজে ভাবুন
সবাই যেভাবে ভাবে
“Cache হলো conditional gate। Hit rate কমলে DB তে বেশি request যায়, DB slow হয়।”
এই চিন্তা ঠিক direction এ, কিন্তু আসল disaster টা এখানে মিসিং।
আসল math দেখুন
ধরুন system ১০,০০০ request/sec handle করে।
- ৯৫% hit rate এ: ৯,৫০০ hits, ৫০০ DB query।
- ৫০% hit rate এ: ৫,০০০ hits, ৫,০০০ DB query। DB load ১০ গুণ।
DB ৫০০/sec এর জন্য sized ছিল। এখন ৫,০০০/sec পাচ্ছে। কী হবে?
- DB slow হয়, query timeout করে, connection pile up করে।
- DB CPU ১০০% এ ওঠে, DB down হয়ে যায়।
The Death Spiral
DB overloaded হলে query slow হয়। Cache populate হতে দেরি হয়। Cache miss বাড়ে। Cache hit rate drop করে। আরো request DB তে যায়। ইতিমধ্যেই struggling DB তে আরো load পড়ে। শেষে DB পুরোপুরি down হয়ে যায়।
Cache hit rate শুধু efficiency metric না। এটা একটা safety boundary। DB সাধারণত এই assumption এ sized হয় যে cache বেশিরভাগ traffic handle করছে।
উত্তর দেখুন আগে নিজে ভাবুন
সবাই যেভাবে ভাবে
“User profile cache করব। বাকি সব না।”
এই answer খুব short, কোনো যুক্তি নেই। প্রতিটা case আলাদাভাবে বিচার করতে হবে। Framework টা হলো read-often, change-often, staleness-tolerant।
প্রতিটা case চেক
| Item | রায় | কেন |
|---|---|---|
| User profile | CACHE | প্রায়ই read, কম change, সামান্য stale acceptable |
| Search results | CACHE (সাবধানে) | Popular query repeat হয়, short TTL। Google, Amazon প্রচুর cache করে। |
| Bank balance | CACHE করবেন না | Stale হলে legal disaster |
| Live chat messages | CACHE করবেন না | সারাক্ষণ change হয়; websocket/push ব্যবহার করুন |
”সবকিছু cache” কেন dangerous
- Cache free না, memory cost আছে।
- Stale এর cost context ভেদে আলাদা।
- কিছু data এত দ্রুত change হয় যে cache কোনো সাহায্য করে না।
- কিছু data per-request unique, এতে cache এর কোনো benefit নেই।
“কোথায় ঠিক, কোথায় ভুল” জিজ্ঞেস করলে প্রতিটা case ধরে ধরে বিশ্লেষণ করুন। প্রতিটা decision যুক্তি দিয়ে defend করুন।
উত্তর দেখুন আগে নিজে ভাবুন
সবাই যেভাবে ভাবে
“Safest হলো write-through। Trade-off: write-through slow, delete-on-write এ cache miss, TTL এ stale।”
এই চিন্তা framing আর deeper trade-off, দুটোই miss করেছে।
আসল সমস্যা চিনুন
আসল সমস্যা হলো human error, কেউ invalidate করতে ভুলে গেছে। তাহলে সঠিক প্রশ্ন হলো, কোন strategy human memory এর উপর নির্ভর করে না?
তিনটাই automatic, কিন্তু আলাদা ভাবে
- Write-through: code যখন DB তে write করে, একই সাথে cache এও write করে। “ভুলে যাওয়ার” সুযোগ নেই।
- Delete-on-write: code নিজে থেকেই cache delete করে।
- TTL: cache নিজেই expire হয়, invalidation এর দরকার নেই।
কোন strategy কখন fail করে (trade-off)
| Strategy | Failure mode |
|---|---|
| Write-through | DB update হয়েছে, cache update হয়নি। Cache expire না হওয়া পর্যন্ত silent |
| inconsistency তৈরি হয় | |
| Delete-on-write | DB update হয়েছে, কিন্তু delete fail করল (rare, কিন্তু সম্ভব) |
| TTL only | কোনো failure নেই, কিন্তু একটা guaranteed staleness window থাকে |
আসল উত্তর: Combination
Mature approach হলো combine করা:
- Delete-on-write primary mechanism।
- Short TTL safety net (যদি delete fail হয়)।
বেশিরভাগ real systems এ এই approach ই ব্যবহার করা হয়।
সবসময় ভাবুন, fail হলে কী হবে? Real systems এ speed এর চেয়ে failure handling বেশি গুরুত্বপূর্ণ।
১১ যে টার্মগুলো শিখলাম
| টার্ম | মানে |
|---|---|
| Cache | Expensive কাজের result fast storage এ রাখা। |
| Cache hit | Data cache এ ছিল, fast access। |
| Cache miss | Data cache এ ছিল না, মূল DB তে যেতে হবে। |
| Hit rate | Cache থেকে serve হওয়া request এর %, একটা critical safety metric। |
| Cache-aside | App আগে cache দেখে, miss হলে DB তে যায়, cache populate করে। সবচেয়ে common pattern। |
| Write-through | DB আর cache একই operation এ update হয়। |
| Delete-on-write | DB update এর পর cache entry delete করা। |
| TTL (Time To Live) | Cache entry নির্দিষ্ট সময় পর নিজে থেকে expire হয়। |
| Cache invalidation | Cache কে source of truth এর সাথে sync রাখা। |
| Eviction | Cache full হলে entry সরানো। |
| LRU / LFU / FIFO | Eviction policy। |
| Cache stampede | Popular entry expire হলে একসাথে অনেক miss। |
| Cache penetration | DB তে নেই, এমন data এর repeated query। |
| Cache avalanche | Mass expiration বা cache server failure। |
| TTL jitter | TTL এ ছোট random variation। |
| Stale-while-revalidate | এক request fresh data আনার সময় বাকিদের old value serve করা। |
| Cold cache | Empty cache। DB full load পায়। |
| Cache warming | Traffic আসার আগে cache pre-populate করা। |
| Bloom filter | Probabilistic structure, “এই key definitely নেই” বলার জন্য। |
| Redis / Memcached | Popular distributed cache system। |
১২ সংক্ষিপ্ত সারসংক্ষেপ
- Caching মানে expensive result কে fast memory এ store করে রাখা, যাতে কাজ আবার না করতে হয়। এটা slow operation কে near-instant memory lookup এ পরিণত করে।
- কঠিন কাজ caching না। কঠিন কাজ হলো invalidation (fresh রাখা) আর eviction (কী সরাব)। Cache-aside, delete-on-write আর TTL এর combination সবচেয়ে common।
- Cache failure এর নাম আছে: stampede, penetration, avalanche। প্রতিটার পরিচিত defense আছে।
১৩ মনে রাখুন
- Cache hit rate একটা safety metric, শুধু performance না। Drop করলে DB down হয়ে যেতে পারে।
- “এটা কি cache করব?” এই প্রশ্নের উত্তরের জন্য একটা framework রাখুন। Read-often, change-often, staleness-tolerant।
- কোনো invalidation strategy ই bulletproof না। Delete-on-write আর short TTL combine করুন।
- সবসময় ভাবুন, fail হলে কী হবে? Speed এর চেয়ে failure mode বেশি গুরুত্বপূর্ণ।
- Cache failure এর নাম জানুনঃ stampede, penetration, avalanche। সেইসাথে সবগুলোর defense mechanism।
- DB ই source of truth। Cache হলো speed layer। উল্টোটা কখনো না।
- Cold cache dangerous। Cache restart এর পর traffic আসার আগে warm করুন।