সেশন ০৪

Caching - একই কাজ বারবার না করার কৌশল

এই সেশনের লক্ষ্যঃ Cache কেন দরকার, কোথায় থাকে, কীভাবে data correctness নিশ্চিত করা যায় (এটাই সবচেয়ে কঠিন), আর production এ যেসব failure mode আছে সব বোঝা।
Caching - একই কাজ বারবার না করার কৌশল
Caching - একই কাজ বারবার না করার কৌশল

০০ যে প্রশ্নগুলোর উত্তর খুঁজবো

সবগুলো প্রশ্নের উত্তর জানার পর আপনি 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।

Caching কী?

Expensive কাজের answer কোনো fast জায়গায় store করে রাখা, যাতে সেই expensive কাজ বারবার করতে না হয়।

০২ Cache আসলে কতটা faster?

Cache থাকে RAM এ। এবার নিচের সংখ্যাগুলো দেখুনঃ

OperationTime
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 আনার মধ্যে ১০,০০০ গুণ পার্থক্য

Caching এর মূল উদ্দেশ্য

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 থেকে চারটা কঠিন প্রশ্ন আসেঃ

  1. কী cache করব (space সীমিত বলে)।
  2. Cache full হলে কী সরাব (eviction)।
  3. Data বদলালে cache কীভাবে fresh রাখব (invalidation)।
  4. Cache down হলে কী হবে (DB এখনো source of truth)।

০৩ App এ cache use করব কীভাবে?

Modern application এ একাধিক layer এ cache থাকে। এই session এর focus Distributed Cache (Redis), যা সবচেয়ে গুরুত্বপূর্ণ layer।

Cache-Aside Pattern (সবচেয়ে common)

Cache-aside কী?

App প্রথমে cache দেখে। Data থাকলে ব্যবহার করে (hit)। না থাকলে (miss) DB তে যায়, data পায়, cache এ রেখে দেয়, যাতে পরের বার কাজে লাগে।

CACHE MISS (প্রথম read) CACHE HIT (পরের read) App getUser(42) ১. ask cache Cache "missed!" ২. fallback to DB Database ৩. store App getUser(42) ১. ask cache Cache "got it!" ২. return fast Database DB অ্যাকসেস করতে হলো না
বাম দিক = প্রথম request (miss) - DB তে যেতে হয়। ডান দিক = পরের requests (hit) - cache থেকেই answer, DB থেকে ডাটা ফেস করতে হলো না।
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 এর 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

Strategy 1: Write-Through

DB আর cache দুটোতেই একসাথে write করা হয়।

  • সুবিধা: Cache সবসময় fresh থাকে।
  • Downside: Write slow হয়। DB write success হলো, কিন্তু cache write fail হলে silent inconsistency তৈরি হয়।
Strategy 2: Delete-on-Write (Invalidation)

Update হলে DB তে write করা হয়, আর cache entry delete করা হয়। পরের read টা miss হবে, ফলে fresh DB data cache এ write হবে।

  • সুবিধা: Simple। Cache হয় correct থাকবে, নয়তো missing থাকবে, কখনো wrong থাকবে না।
  • Downside: Delete এর পর একসাথে অনেক read এলে অনেক cache miss হয়, DB তে চাপ পড়ে।
Strategy 3: TTL (Time-to-Live)

প্রতিটা cache entry নির্দিষ্ট সময় (যেমন ৬০ সেকেন্ড) পর নিজে থেকে expire হবে।

  • সুবিধা: খুবই simple। Self-healing।
  • Downside: TTL period এর মধ্যে data stale থাকতে পারে।

Real systems এ তিনটার combination

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 প্রায়ই গুলিয়ে ফেলে।

Invalidation

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 না থাকে।

Eviction

Trigger: cache নিজে।

Cache নিজেই সরিয়ে দেয়। আপনাকে জিজ্ঞেস করবে না।

Memory full হলো, LRU policy তে সবচেয়ে পুরনো entry সরে গেল। কিংবা TTL শেষ হলো, entry expire হলো।

InvalidationEviction
কে সরায়আপনি (application code)Cache নিজে
কেন সরায়Source of truth বদলে গেছেMemory full, TTL শেষ, বা restart
GoalFreshness নিশ্চিত করাMemory manage করা
পরের read এ কী হয়Delete করলে miss হয়, DB থেকে fresh data আসে। Replace করলে সরাসরি cache থেকে latest data পাওয়া যায়।Miss হয়, DB থেকে data আসে (থাকলে)

০৭ সব কিছু cache করব?

প্রতিটা data এর জন্য তিনটা প্রশ্ন করুন:

  1. এটা কি read often?
  2. এটা কি change often?
  3. Stale data কি acceptable?
শুরু করুন এই ডাটা কি cache করবো? প্রশ্ন ১: এটা কি প্রায়ই read হয়? Read, write এর চেয়ে অনেক বেশি? না হ্যাঁ Cache করবেন না rarely read-এর ক্ষেত্রে memory অপচয় প্রশ্ন ২: এটা কি ঘন ঘন বদলায়? এই key-তে ঘন ঘন write হয়? না হ্যাঁ দীর্ঘমেয়াদী cache করুন Long TTL rarely write-এ cache invalidate করুন প্রশ্ন ৩: পুরনো ডাটা কি অ্যাক্সেপ্টেবল? ইউজার সামান্য পুরনো ডাটা একসেপ্ট করতে পারবেন? হ্যাঁ না সংক্ষিপ্ত cache করুন Short TTL, lag মেনে নিন যেমন: like count পুনর্বিবেচনা করুন Strict invalidate + ক্ষুদ্র TTL অথবা cache করার দরকার নাই ৪র্থ প্রশ্ন (হিডেন) ডাটা compute বা fetch করা কি ব্যয়বহুল? হ্যাঁ হলে, read কম হলেও cache করাই ভালো, কারণ cache করায় ডাটা দ্রুত পাওয়া যাবে।
এই ডাটা কি cache করবো? - ফ্রেমওয়ার্ক

ভালো cache candidate এর উদাহরণঃ

Dataকেন
User profileপ্রায়ই read, কম change, সামান্য staleness acceptable
Product catalogসবসময় read, কম change
Homepage feedঅনেক user এর জন্য একই, compute করা expensive
Top 10 trending postsCompute expensive, staleness acceptable
Search resultsPopular query repeat হয়, short TTL দিয়ে cache

খারাপ cache candidate এর উদাহরণঃ

Dataকেন
Bank account balanceStale হলে মারাত্মক ভুল হয়
Live chat messagesসারাক্ষণ change হয়
Real-time stock priceStale হলে ভুল হয়
One-time tokenএকবার ব্যবহারের জন্য, cache এ কোনো benefit নেই

”সবকিছু cache করুন” concept টা কেন বিপজ্জনক

  1. Cache free না: memory cost আছে।
  2. Stale এর cost context ভেদে আলাদা: stale tweet count acceptable, stale bank balance acceptable না।
  3. কিছু data এত দ্রুত change হয় যে cache রাখার আগেই বদলে যায়।
  4. কিছু 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।

সমাধানঃ

সমস্যা ২: Cache Penetration

DB তে যেগুলো নেই, সেগুলোর জন্য request আসে। Cache কোনো সাহায্য করতে পারে না।

Request: "Get user_999999999" (নেই)
Cache: miss
DB: nothing
Cache: store করার মতো কিছু নেই
Request আবার এলো → DB আবার query → অনন্তকাল চলবে...

সমাধানঃ

সমস্যা ৩: Cache Avalanche

অনেক cache entry একসাথে expire হলো, বা cache server নিজেই down হলো। DB overwhelmed হয়।

সমাধান:

সমস্যা ৪: Cold Cache

Cache restart হলে সেই মুহূর্তে cache পুরোপুরি empty থাকে। প্রতিটা request cache miss করে, ফলে DB overloaded হয়।

সমাধান: Cache warming (traffic আসার আগে cache pre-populate করা)।

০৯ System এখন দেখতে কেমন?

সেশন ০৩ এর সাথে এখন Cache layer যোগ হলো। অনেক read এখন database পর্যন্ত যায়ই না।

CLIENT LOAD BALANCER APPLICATION CACHE DATA BACKUP ইউজার ইউজার ইউজার LB-1 Active LB-2 Passive heartbeat Stateless Web 1 App Server Web 2 App Server Web 3 App Server Redis Cache cache-aside + TTL + delete-on-write miss → DB Primary DB Replica 1 Replica 2 nightly backup Backup Storage Cold (S3 / Glacier)
Cache layer যোগ হলো Web Server আর Database এর মাঝে। হাইলাইটেড অ্যারো = cache এ যাওয়া (primary read path)। সলিড অ্যারো = cache miss হলে DB তে যাওয়া।

এখন পর্যন্ত কি কি ঠিক করা হলো?

  • 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 hit rate এত important কেন? ৯৫% থেকে ৫০% এ drop হলে কী হবে?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“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 করছে।

প্রশ্ন ২: টীমের এক জুনিয়র ডেভ বলল "সবকিছু cache করো!" কোথায় ঠিক, কোথায় ভুল?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“User profile cache করব। বাকি সব না।”

এই answer খুব short, কোনো যুক্তি নেই। প্রতিটা case আলাদাভাবে বিচার করতে হবে। Framework টা হলো read-often, change-often, staleness-tolerant

প্রতিটা case চেক

Itemরায়কেন
User profileCACHEপ্রায়ই read, কম change, সামান্য stale acceptable
Search resultsCACHE (সাবধানে)Popular query repeat হয়, short TTL। Google, Amazon প্রচুর cache করে।
Bank balanceCACHE করবেন নাStale হলে legal disaster
Live chat messagesCACHE করবেন নাসারাক্ষণ change হয়; websocket/push ব্যবহার করুন

”সবকিছু cache” কেন dangerous

  1. Cache free না, memory cost আছে।
  2. Stale এর cost context ভেদে আলাদা।
  3. কিছু data এত দ্রুত change হয় যে cache কোনো সাহায্য করে না।
  4. কিছু data per-request unique, এতে cache এর কোনো benefit নেই।
শিক্ষা

“কোথায় ঠিক, কোথায় ভুল” জিজ্ঞেস করলে প্রতিটা case ধরে ধরে বিশ্লেষণ করুন। প্রতিটা decision যুক্তি দিয়ে defend করুন।

প্রশ্ন ৩: Product team DB তে price update করল, কিন্তু cache invalidate করতে ভুলে গেল। কোনটা safest mechanism: write-through, delete-on-write, না TTL?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“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)

StrategyFailure mode
Write-throughDB update হয়েছে, cache update হয়নি। Cache expire না হওয়া পর্যন্ত silent
inconsistency তৈরি হয়
Delete-on-writeDB 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 বেশি গুরুত্বপূর্ণ।

১১ যে টার্মগুলো শিখলাম

টার্মমানে
CacheExpensive কাজের result fast storage এ রাখা।
Cache hitData cache এ ছিল, fast access।
Cache missData cache এ ছিল না, মূল DB তে যেতে হবে।
Hit rateCache থেকে serve হওয়া request এর %, একটা critical safety metric।
Cache-asideApp আগে cache দেখে, miss হলে DB তে যায়, cache populate করে। সবচেয়ে common pattern।
Write-throughDB আর cache একই operation এ update হয়।
Delete-on-writeDB update এর পর cache entry delete করা।
TTL (Time To Live)Cache entry নির্দিষ্ট সময় পর নিজে থেকে expire হয়।
Cache invalidationCache কে source of truth এর সাথে sync রাখা।
EvictionCache full হলে entry সরানো।
LRU / LFU / FIFOEviction policy।
Cache stampedePopular entry expire হলে একসাথে অনেক miss।
Cache penetrationDB তে নেই, এমন data এর repeated query।
Cache avalancheMass expiration বা cache server failure।
TTL jitterTTL এ ছোট random variation।
Stale-while-revalidateএক request fresh data আনার সময় বাকিদের old value serve করা।
Cold cacheEmpty cache। DB full load পায়।
Cache warmingTraffic আসার আগে cache pre-populate করা।
Bloom filterProbabilistic structure, “এই key definitely নেই” বলার জন্য।
Redis / MemcachedPopular distributed cache system।

১২ সংক্ষিপ্ত সারসংক্ষেপ

  1. Caching মানে expensive result কে fast memory এ store করে রাখা, যাতে কাজ আবার না করতে হয়। এটা slow operation কে near-instant memory lookup এ পরিণত করে।
  2. কঠিন কাজ caching না। কঠিন কাজ হলো invalidation (fresh রাখা) আর eviction (কী সরাব)। Cache-aside, delete-on-write আর TTL এর combination সবচেয়ে common।
  3. Cache failure এর নাম আছে: stampede, penetration, avalanche। প্রতিটার পরিচিত defense আছে।

১৩ মনে রাখুন