মূল কনটেন্টে যান
🧱
ডক•13

Caching

এই পথে যেখানে আসে

  • দিন ০০৪ · cache কোথায়
    cache কোথায় বসাতেন — browser, CDN, নাকি API-র সামনে; Cache-Aside এক লাইনে; ডেটা বাসি হয় কখন, আর srdtube-এ quota বাঁচাতে কোনটা আগে (ডক ১৩)
  • দিন ০১৮ · যা বাদ দিলাম
    সেকশন ৪ — যা ইচ্ছাকৃতভাবে বাদ: backend, database, login, cache — প্রতিটায় কেন বাদ আর কখন ফিরবেন (যেমন "quota বারবার শেষ হলে cache") (ডক ১২ · ডক ১৩)
  • দিন ০২৩ · দশ গুণ ব্যবহারকারী
    "ব্যবহারকারী ১০ গুণ হলে?" — doc বন্ধ, মুখে, রেকর্ড: সহজ উত্তর আগে (quota শেষ হবে, সাইট নিজে ভাঙবে না), তারপর দ্বিতীয় ধাপ (ছোট backend + cache); শেষে "আরও বিস্তারিত বলব?" (ডক ১১ · ডক ১৩)
  • দিন ০২৪ · ট্রাফিক আর cache
    দুটো লোকাল প্রশ্ন — "ট্রাফিক বাড়লে?" · "cache কোথায় বসাতেন?" — doc বন্ধ, প্রতিটা ২ মিনিট, বাংলা-ইংরেজি মিশিয়ে যেমন interview-এ হয়; রেকর্ড (ডক ১১ · ডক ১৩)

Caching হলো ব্যয়বহুলভাবে পাওয়া ডেটার একটা কপি দ্রুত-প্রবেশযোগ্য জায়গায় রেখে দেওয়া, যাতে পরের বার সেই খরচটা আর করতে না হয়। একক কৌশল হিসেবে এটাই সবচেয়ে বেশি performance দেয় — latency নাটকীয়ভাবে কমে, database-এর উপর চাপ কমে, এবং একই hardware দিয়ে অনেক বেশি throughput পাওয়া যায়।

Caching কাজ করে দুটো বাস্তবতার কারণে: temporal locality (এইমাত্র যা চাওয়া হয়েছে তা আবার চাওয়ার সম্ভাবনা বেশি) এবং অসম জনপ্রিয়তা (সাধারণত ২০% ডেটাই ৮০% request পায়)।

কিন্তু cache একটা মূল্য দাবি করে — এটা আরেকটা জায়গা যেখানে সত্যের একটা কপি থাকে, তাই staleness ও invalidation-এর সমস্যা এসে যায়। বিখ্যাত উক্তিটা অকারণে জনপ্রিয় হয়নি: "Computer science-এ কঠিন জিনিস দুটোই — cache invalidation আর নামকরণ।"


Types of Caching (কোথায় cache করবেন)

Request-এর পথে যত আগে cache hit হয়, তত সাশ্রয় — কারণ পরের সব ধাপই এড়ানো যায়।

Client Caching

Browser বা mobile app-এর নিজের কাছেই ডেটা রাখা — HTTP cache, localStorage, বা app-এর নিজস্ব store। এটা সবচেয়ে দ্রুত (কোনো network call-ই নেই) এবং সম্পূর্ণ বিনামূল্যে server-এর দিক থেকে।

নিয়ন্ত্রণ হয় HTTP header দিয়ে (Cache-Control, ETag, Last-Modified)। সীমাবদ্ধতা: একবার পাঠিয়ে দিলে আপনি আর সেটা মুছতে পারবেন না — তাই TTL সাবধানে দিন এবং versioned URL ব্যবহার করুন।

CDN Caching

Edge server-এ content রাখা, user-এর ভৌগোলিক কাছাকাছি। Static asset-এর জন্য আদর্শ, এবং আধুনিক CDN dynamic content-ও cache করতে পারে। বিস্তারিত: Content Delivery Networks।

Web Server Caching

Reverse proxy (Nginx, Varnish) স্তরে পুরো HTTP response cache করা। Application-এর কোনো কোড না চালিয়েই response দেওয়া যায় — তাই সাশ্রয় বিশাল। সবচেয়ে ভালো কাজ করে সেই page গুলোতে যেগুলো সব user-এর জন্য একই (হোমপেজ, article, product page)।

ব্যক্তিগতকৃত (personalized) page-এ সরাসরি কাজ করে না; তখন Edge Side Includes (ESI) বা "page cache করো, শুধু ব্যক্তিগত অংশটা আলাদা করে আনো" ধরনের কৌশল লাগে।

Database Caching

বেশিরভাগ database নিজেই ভেতরে cache রাখে — buffer pool (ঘন ঘন পড়া page গুলো memory-তে), query plan cache, ইত্যাদি। এটা প্রায় বিনামূল্যে পাওয়া সুবিধা, কিন্তু আপনার কাজ হলো database-কে যথেষ্ট RAM দেওয়া যাতে working set memory-তে ধরে। Database-এর memory কম দিয়ে বাইরে বিশাল cache বসানোর চেয়ে অনেক সময় database-এর RAM বাড়ানোই ভালো সমাধান।

Application Caching

Redis বা Memcached-এর মতো একটা in-memory store, যেখানে application ইচ্ছেমতো object রাখে — query-র ফলাফল, রেন্ডার করা fragment, session, computed value। এখানেই আপনার সবচেয়ে বেশি নিয়ন্ত্রণ, এবং system design আলোচনায় "cache" বললে সাধারণত এটাই বোঝানো হয়।

কী cache করবেন তার তিনটা স্তর আছে: query-level (SQL query-র ফলাফল — সহজ কিন্তু invalidate করা কঠিন), object-level (পুরো domain object — সবচেয়ে ব্যবহারিক, এটাই পছন্দনীয়), এবং fragment-level (রেন্ডার করা HTML টুকরো)।

Local in-process cache (একই server-এর memory-তে) সবচেয়ে দ্রুত, কিন্তু প্রতিটা server-এ আলাদা কপি হয় — তাই অসামঞ্জস্য ও কম hit rate। Distributed cache (Redis) সব server একই ডেটা দেখে, কিন্তু একটা network hop লাগে।


Cache Strategies (কীভাবে লিখবেন ও পড়বেন)

Cache Aside (Lazy Loading)

সবচেয়ে প্রচলিত প্যাটার্ন। Application নিজেই cache ও database দুটোর সাথে কথা বলে:

পড়া:   cache-এ আছে? → থাকলে দাও (hit)
         না থাকলে (miss) → DB থেকে পড়ো → cache-এ রাখো → দাও
লেখা:   DB-তে লেখো → cache-এর key টা মুছে দাও (invalidate)
  • সুবিধা: শুধু যা চাওয়া হয় তাই cache হয় (memory-র দক্ষ ব্যবহার), cache মরে গেলেও সিস্টেম চলে (শুধু ধীর হয়), বাস্তবায়ন সরল।
  • অসুবিধা: প্রতিটা miss-এ তিনটা ধাপ, তাই প্রথম request ধীর। Cache আর DB সাময়িকভাবে অমিল হতে পারে।
  • লেখার সময় cache update না করে delete করা বেশি নিরাপদ — একসাথে চলা দুটো write-এর কারণে ভুল মান cache-এ আটকে যাওয়া (race condition) এড়ানো যায়।

Write-Through

Application সবসময় cache-এ লেখে, আর cache নিজেই synchronously database-এ লিখে দেয়। লেখা তখনই সম্পন্ন যখন দুই জায়গাতেই লেখা হয়ে গেছে।

  • সুবিধা: cache কখনো stale হয় না — সবসময় সঙ্গতিপূর্ণ। পড়া সবসময় দ্রুত।
  • অসুবিধা: প্রতিটা write ধীর (দুই জায়গায় লিখতে হয়)। আর যে ডেটা কখনো পড়াই হবে না সেটাও cache-এ জায়গা নেয় — write-heavy কিন্তু কম-পড়া ডেটার জন্য অপচয়।
  • প্রায়ই cache-aside-এর সাথে মিলিয়ে ব্যবহার করা হয়।

Write-Behind (Write-Back)

Application শুধু cache-এ লেখে এবং সাথে সাথে সফল response পায়; cache পরে asynchronously (সাধারণত ব্যাচ করে) database-এ লেখে।

  • সুবিধা: write latency অত্যন্ত কম এবং write throughput বিশাল। একই record বারবার বদলালে database-এ একবারই লেখা হয় — চমৎকার সাশ্রয়।
  • অসুবিধা: ডেটা হারানোর ঝুঁকি — database-এ লেখার আগে cache মরে গেলে ওই write গুলো চিরতরে হারায়। বাস্তবায়নও সবচেয়ে জটিল।
  • ব্যবহার: view counter, like count, analytics event — যেখানে বিপুল write আছে কিন্তু কয়েকটা ঘটনা হারানো সহনীয়।

Refresh Ahead

Cache ভবিষ্যদ্বাণী করে যে কোন entry গুলো শিগগিরই আবার লাগবে, এবং TTL শেষ হওয়ার আগেই সেগুলো নিজে থেকে refresh করে নেয়।

  • সুবিধা: user কখনো cache miss-এর latency দেখে না; জনপ্রিয় key-র জন্য চমৎকার।
  • অসুবিধা: ভবিষ্যদ্বাণী ভুল হলে অপ্রয়োজনীয়ভাবে database-এ চাপ পড়ে। কোন key গুলো refresh হবে সেটা ঠিক করা কঠিন।
  • ব্যবহারিক রূপ: stale-while-revalidate — মেয়াদোত্তীর্ণ মানটা দিয়ে দাও, আর পেছনে নতুনটা এনে রাখো।

যে সমস্যাগুলো জানা থাকা দরকার

Cache Stampede (Thundering Herd) — একটা জনপ্রিয় key expire হওয়ামাত্র হাজারটা request একসাথে cache miss পেয়ে database-এ ঝাঁপিয়ে পড়ে। প্রতিরোধ: একটা lock দিয়ে শুধু একটা request-কে ডেটা আনতে দিন (বাকিরা অপেক্ষা করুক), TTL-এ এলোমেলো jitter যোগ করুন, বা refresh-ahead ব্যবহার করুন।

Cache Penetration — এমন key বারবার চাওয়া যা database-এও নেই, ফলে প্রতিবার database-এ যাওয়া। প্রতিরোধ: "নেই" ফলাফলটাও অল্প সময়ের জন্য cache করুন (negative caching), বা Bloom filter ব্যবহার করুন।

Eviction Policy — cache ভরে গেলে কাকে বাদ দেবেন? LRU (সবচেয়ে আগে ব্যবহৃত, সবচেয়ে প্রচলিত ও নিরাপদ ডিফল্ট), LFU (সবচেয়ে কম ব্যবহৃত), TTL/FIFO। ভুল policy-তে hit rate ধসে যায়।

Hit Rate নিরীক্ষা করুন — cache-এর একমাত্র উদ্দেশ্য hit দেওয়া। Hit rate ৯০%-এর নিচে হলে প্রশ্ন করুন: TTL কি খুব কম? Key কি খুব বেশি specific? Cache-এর আকার কি অপর্যাপ্ত? Hit rate না মাপলে আপনি জানেনই না cache টা আদৌ কাজ করছে কি না।


পূর্ববর্তী: Databases · পরবর্তী: Asynchronism