Spaced Repetition (Lesson 1.3): Back-of-the-envelope estimation এ ১ million user, প্রতি user এর ১ KB data — মোটামুটি কত memory লাগবে? (হিসাবটা মাথায় করে বলো)
Prerequisite: Lesson 4.2 (Caching Strategies), Lesson 1.3 (Estimation)
তুমি এই lesson শেষে পারবে:
- TTL, explicit invalidation আর eviction — এই তিনটা আলাদা জিনিস কেন আলাদা, আর কোনটা কোন সমস্যার উত্তর, সেটা বুঝবে
- একটা write হলে ঠিক কোন কোন cache key মুছতে হবে — সেটা key design দেখে বের করতে পারবে
- LRU আর LFU eviction policy এর পার্থক্য, আর TaskFlow এর জন্য Redis এ কোনটা বেছে নেবে — বলতে পারবে
Tier: 3 — Design Exercise (hands-on Redis implementation পরের lesson, 4.4 তে)
০. TaskFlow এখন কোথায়
গত lesson এ TaskFlow এর caching strategy ঠিক হয়েছে — read এ Cache-Aside, write এ DB তে লিখে cache key invalidate। কাগজে-কলমে সিদ্ধান্তটা পরিষ্কার।
কিন্তু গত lesson এর শেষে একটা বাড়তি প্রশ্ন রেখে এসেছিলাম: user যখন একটা task update করবে, ঠিক কোন কোন key মুছতে হবে? শুধু ওই task এর key টাই কি যথেষ্ট?
প্রশ্নটা নিরীহ দেখালেও, এর ভেতরেই লুকিয়ে আছে caching এর সবচেয়ে কুখ্যাত সমস্যা। Phil Karlton এর সেই বিখ্যাত উক্তিটা আছে না —
"There are only two hard things in Computer Science: cache invalidation and naming things."
আজকের lesson সেই "দুটো কঠিন জিনিস" এর প্রথমটা নিয়ে। আর শেষে দেখব, প্রথমটা আসলে দ্বিতীয়টার সাথে জড়িয়ে আছে — key এর নাম ঠিকভাবে না দিলে invalidation কখনোই সহজ হবে না।
১. Theory
১.১ আসলে তিনটা আলাদা প্রশ্ন
লোকে প্রায়ই "cache expire হওয়া" বলে সব গুলিয়ে ফেলে। কিন্তু এখানে তিনটা সম্পূর্ণ আলাদা প্রশ্ন আছে, আর তিনটার উত্তরও আলাদা:
১. TTL → "কতক্ষণ পর নিজে থেকে মুছে যাবে?" (সময় ঠিক করে)
২. Invalidation → "data বদলে গেছে, এখনই মুছে দাও" (তুমি ঠিক করো)
৩. Eviction → "memory ভরে গেছে, কাকে বের করব?" (Redis ঠিক করে)
পার্থক্যটা খেয়াল করো — কে সিদ্ধান্ত নিচ্ছে, সেটাই মূল কথা। TTL এ ঘড়ি সিদ্ধান্ত নেয়, invalidation এ তোমার code সিদ্ধান্ত নেয়, আর eviction এ Redis নিজে বাধ্য হয়ে সিদ্ধান্ত নেয় — কারণ তার আর জায়গা নেই।
১.২ TTL — সবচেয়ে সহজ, আর সবচেয়ে কম নির্ভরযোগ্য
TTL (Time To Live) মানে — "এই key টা N সেকেন্ড পর নিজে থেকেই মরে যাবে।"
await redis.set(cacheKey, JSON.stringify(tasks), 'EX', 300); // ৫ মিনিট
এর সৌন্দর্য হলো এটা স্বয়ংক্রিয়। তুমি invalidate করতে ভুলে গেলেও, সর্বোচ্চ ৫ মিনিট পর পুরনো data নিজে থেকে চলে যাবে। এটা একটা safety net — শেষ ভরসা।
কিন্তু TTL এর দাম হলো একটা জানালা:
t=0s user task টা update করল → DB তে নতুন value
Cache এ এখনো পুরনো value
t=0-300s এই পুরো সময় জুড়ে user পুরনো data দেখবে ← Staleness Window
t=300s TTL শেষ → পরের read এ DB থেকে নতুন value আসবে
এই মাঝের সময়টাকে বলে staleness window — যতক্ষণ cache আর DB একমত না।
এখান থেকেই TTL এর মূল trade-off:
| TTL | Cache hit ratio | Staleness | DB load |
|---|---|---|---|
| ছোট (১০s) | কম | কম | বেশি |
| বড় (১ঘ) | বেশি | বেশি | কম |
তাহলে ঠিক মানটা কত? এটা নির্ভর করে data টা বাসি হলে কতটা ক্ষতি, তার উপর:
- TaskFlow এর task list → ৫ মিনিট পুরনো দেখালে কেউ মরে যাবে না, কিন্তু বিরক্ত হবে → ৩০-৬০ সেকেন্ড
- User এর profile picture → ঘণ্টাখানেক পুরনো দেখালেও চলে → ১ ঘণ্টা
- Account balance বা payment status → এক সেকেন্ডও বাসি চলবে না → cache-ই করা উচিত না, বা খুব ছোট TTL সহ invalidation বাধ্যতামূলক
১.৩ Explicit Invalidation — delete করো, update কোরো না
TTL শুধু safety net। আসল কাজটা হলো — data বদলানোর সাথে সাথে cache কে জানানো। এখানে দুটো পথ আছে, আর একটা স্পষ্টভাবে ভালো:
পথ ১ (update): DB তে লেখো → cache এ নতুন value লিখে দাও
পথ ২ (delete): DB তে লেখো → cache key টা মুছে দাও ← এটাই সাধারণত ভালো
কেন delete ভালো? তিনটা কারণে:
- Update করতে গেলে তোমাকে নতুন value টা বানাতে হবে — মানে আবার DB query, আবার serialize। Delete এ সেই খরচ নেই, আর data টা আসলে কেউ পড়তে চাইলে তখন এমনিতেই load হয়ে যাবে।
- Race condition কম। দুইজন একসাথে update করলে, "update" পদ্ধতিতে কার value শেষে cache এ বসবে সেটা অনিশ্চিত — এমনকি পুরনো value নতুনটার উপরে বসে যেতে পারে। Delete এ এই নির্দিষ্ট ঝামেলাটা নেই; cache খালি থাকলে পরের read DB এর সত্যটাই আনবে। তবে delete করলেও race পুরোপুরি চলে যায় না — নিচের নোটটা দেখো।
- কেউ হয়তো ওই data আর পড়বেই না। তাহলে cache এ নতুন value বসিয়ে memory নষ্ট করার মানে কী?
তোমার stack এ:
async function updateTask(
redis: Redis,
userId: number,
taskId: number,
title: string
): Promise<void> {
// ধাপ ১ — সত্যের উৎস (DB) আগে
await Task.update({ title }, { where: { id: taskId, userId } });
// ধাপ ২ — তারপর cache মুছে দাও
await redis.del(`task:${taskId}`, `tasks:user:${userId}`);
}
ক্রমটা গুরুত্বপূর্ণ — আগে DB, পরে cache। উল্টো করলে একটা সূক্ষ্ম bug আছে: cache মুছে দিলে, কিন্তু DB write টা fail করল — এর মাঝখানে যদি কেউ read করে, সে DB থেকে পুরনো value এনে আবার cache এ ভরে দেবে। ফলে cache এ পুরনো data ফিরে আসবে, আর TTL শেষ না হওয়া পর্যন্ত থেকে যাবে।
একটা সৎ নোট — "আগে DB, পরে delete" এও একটা সরু race থেকে যায়:
t=0 Reader : cache miss → DB থেকে পুরনো value পড়ছে (একটা ধীর query)
t=1 Writer : DB তে নতুন value লিখল
t=2 Writer : cache key delete করল (এটা এমনিতেই খালি — মোছার কিছু নেই)
t=3 Reader : তার ধীর query শেষ হলো → পুরনো value টা cache এ লিখে দিল
এখন TTL শেষ না হওয়া পর্যন্ত cache এ পুরনো data থাকবে। এর জন্য দুর্ভাগ্যজনক timing লাগে (write এর আগে শুরু হওয়া একটা read, যেটা delete এর পরে শেষ হয়), তাই এটা বিরল — কিন্তু high load এ বিরল জিনিস রোজ ঘটে। TTL safety net যে বাদ দেওয়া যায় না, এটা তার আরেকটা কারণ। প্রচলিত প্রতিকার: একটু দেরি করে দ্বিতীয়বার delete করা (delayed double delete), অথবা একটা lease/version check, যাতে বাসি reader cache ভরতে না পারে (Facebook এর memcache paper এটাকে lease বলে)।
১.৪ কোন key গুলো মুছতে হবে — গত lesson এর প্রশ্নের উত্তর
উপরের code এ লক্ষ্য করেছ, আমি দুইটা key মুছেছি? এটাই ছিল গত lesson এর বাড়তি প্রশ্নের উত্তর।
একটা task update হলে যেসব cache entry বাসি হয়ে যায়:
task:42 ← ওই task এর নিজের copy
tasks:user:7 ← ওই user এর পুরো list (task টা এই list এ আছে)
tasks:user:7:completed ← "completed" filter করা list
tasks:user:7:page:1 ← paginated view
tasks:project:3 ← task টা যদি কোনো project এ থাকে
একটা write, পাঁচটা বাসি key। এটাই invalidation কে কঠিন বানায় — data একটা, কিন্তু সেটা কতগুলো আলাদা "view" এ ঢুকে আছে সেটা মনে রাখা কঠিন। নতুন একটা endpoint যোগ করার সময় invalidation এর জায়গায় সেটা যোগ করতে ভুলে গেলে — সেটাই সেই bug যেটা মাসখানেক পরে "মাঝে মাঝে পুরনো data দেখায়" হিসেবে ফিরে আসে।
এখানেই "naming things" আর "cache invalidation" এক হয়ে যায়। Key গুলো যদি একটা নিয়ম মেনে namespace করা থাকে, তাহলে একসাথে মোছা সহজ:
tasks:user:7:* ← এই prefix এর সব key একসাথে মুছে ফেলা
তবে সাবধান — Redis এ KEYS tasks:user:7:* চালানো production এ বিপজ্জনক, কারণ এটা পুরো keyspace scan করে আর ততক্ষণ Redis কে আটকে রাখে (Redis single-threaded)। বিকল্প: SCAN (ধীরে ধীরে, block না করে), অথবা আরও ভালো — প্রতিটা user এর key গুলোর একটা তালিকা আলাদা করে রাখা (Redis Set এ), যাতে ঠিক কোনগুলো মুছতে হবে তা জানা থাকে।
আরেকটা পরিষ্কার কৌশল — version/generation key:
tasks:user:7:v12 ← v হলো version number
User এর কিছু বদলালে version টা এক বাড়িয়ে দাও (INCR tasks:user:7:version)। পুরনো v12 key গুলো আর কেউ খুঁজবেই না — সবাই এখন v13 চাইবে। পুরনোগুলো TTL শেষে নিজে থেকেই মরে যাবে। মোছার দরকারই নেই।
১.৫ Eviction — memory ভরে গেলে কে যাবে
TTL আর invalidation, দুটোই "data টা আর ঠিক নেই" নিয়ে। Eviction সম্পূর্ণ আলাদা প্রশ্ন — data হয়তো একদম ঠিক আছে, কিন্তু জায়গা নেই।
Redis এ তুমি একটা memory সীমা ঠিক করে দাও, আর বলে দাও সীমা ছাড়ালে সে কী করবে:
maxmemory 2gb
maxmemory-policy allkeys-lru
Policy গুলো (গুরুত্বপূর্ণ কয়েকটা):
| Policy | কী করে |
|---|---|
noeviction |
কিছু মুছবে না; নতুন write error দেবে (default) |
allkeys-lru |
সব key এর মধ্যে, সবচেয়ে অনেকক্ষণ আগে ব্যবহৃত টা বাদ |
allkeys-lfu |
সব key এর মধ্যে, সবচেয়ে কম বার ব্যবহৃত টা বাদ |
volatile-lru |
শুধু যেগুলোর TTL সেট করা আছে, তাদের মধ্যে LRU |
allkeys-random |
যাকে-তাকে random বাদ |
noeviction default — আর এটা প্রায়ই অপ্রত্যাশিত। অনেকে Redis বসিয়ে maxmemory-policy সেট করতে ভুলে যায়, তারপর memory ভরে গেলে হঠাৎ OOM command not allowed error দেখে অবাক হয়। যদি Redis টা pure cache হিসেবে ব্যবহার করো (অর্থাৎ data হারালেও DB তে আসলটা আছে), তাহলে allkeys-lru প্রায় সবসময়ই সঠিক পছন্দ।
১.৬ LRU vs LFU — কোনটা কখন
দুটোর যুক্তি আলাদা:
- LRU (Least Recently Used) — "সবচেয়ে অনেকক্ষণ ধরে কেউ ছোঁয়নি" সেটা বাদ। প্রশ্ন: কখন শেষ ব্যবহার হয়েছে?
- LFU (Least Frequently Used) — "সবচেয়ে কম বার ব্যবহৃত হয়েছে" সেটা বাদ। প্রশ্ন: কত বার ব্যবহার হয়েছে?
একটা উদাহরণে পার্থক্যটা পরিষ্কার হয়। ধরো TaskFlow এ:
key A : গত ৩ মাসে ১০,০০০ বার পড়া হয়েছে, কিন্তু শেষ ২ ঘণ্টায় একবারও না
key B : গত ৩ মাসে মাত্র ৩ বার পড়া হয়েছে, কিন্তু ৫ মিনিট আগে পড়া হয়েছে
LRU বলবে: B সম্প্রতি ব্যবহৃত, তাই A কে বাদ দাও। LFU বলবে: A অনেক জনপ্রিয়, তাই B কে বাদ দাও।
কে ঠিক? নির্ভর করে তোমার traffic এর চরিত্রের উপর:
- LRU ভালো যখন ব্যবহারে একটা "সাম্প্রতিকতা" থাকে — কেউ আজ কাজ করছে মানে সে আরও কিছুক্ষণ করবে। TaskFlow এর সাধারণ ব্যবহারে এটাই স্বাভাবিক।
- LFU ভালো যখন কিছু জিনিস চিরস্থায়ীভাবে জনপ্রিয় — যেমন একটা news site এর homepage। LRU এখানে একটা বিপদে পড়ে: হঠাৎ কোনো scan বা bot এসে একগাদা অচেনা key পড়ে ফেললে, সেগুলো "recent" হয়ে যায় আর সত্যিকারের জনপ্রিয় data গুলোকে বের করে দেয় — একে বলে cache pollution।
Trade-off Table — তিনটা প্রক্রিয়া এক নজরে
| TTL | Invalidation | Eviction | |
|---|---|---|---|
| কে সিদ্ধান্ত নেয় | ঘড়ি | তোমার code | Redis (বাধ্য হয়ে) |
| কেন ঘটে | সময় শেষ | data বদলেছে | memory শেষ |
| কতটা নির্ভুল | আনুমানিক | নির্ভুল | data এর সাথে সম্পর্কহীন |
| ভুল হলে | staleness window | পুরনো data দেখা যায় | hit ratio পড়ে যায় |
| TaskFlow এ | ৩০-৬০s task list এ | write এ del |
allkeys-lru |
তিনটাই একসাথে লাগে। Invalidation হলো নির্ভুল অস্ত্র, TTL হলো ভুলে যাওয়ার বিরুদ্ধে safety net, আর eviction হলো memory শেষ হয়ে গেলে শেষ রক্ষা। একটা দিয়ে বাকি দুটোর কাজ চালানো যায় না।
২. Interview Angle
Cache invalidation প্রায় প্রতিটা system design interview এ আসে, কিন্তু সরাসরি না — ঘুরিয়ে। সবচেয়ে common রূপ: "তোমার design এ user একটা জিনিস update করল, কিন্তু অন্য একজন পুরনোটা দেখছে — কেন, আর কীভাবে ঠিক করবে?" এখানে TTL আর explicit invalidation দুটোরই কথা বলতে হবে, আর বলতে হবে কেন শুধু TTL যথেষ্ট না (staleness window) এবং কেন শুধু invalidation-ও যথেষ্ট না (কোনো একটা জায়গায় মুছতে ভুলে যাবেই)।
একটা ভালো follow-up যেটা অনেকে আটকে যায়: "invalidate করার সময় DB আগে না cache আগে?" — উত্তর: DB আগে, cache পরে, আর কারণটা বলতে পারতে হবে (মাঝখানে একটা read এসে পুরনো value আবার cache এ ভরে দিতে পারে)।
আর eviction নিয়ে প্রশ্নটা প্রায় সবসময় একই: "LRU না LFU?" — এখানে "LRU ভালো" বলে থেমে যেয়ো না। Traffic pattern এর কথা তোলো: recency-driven access এ LRU, চিরস্থায়ী জনপ্রিয়তা থাকলে LFU, আর LFU যে scan/bot এর কারণে হওয়া cache pollution থেকে বাঁচায় — সেটা বলতে পারলে তুমি স্পষ্টভাবে এগিয়ে।
৩. Key Takeaway
- তিনটা আলাদা প্রক্রিয়া, গুলিয়ে ফেলা যাবে না: TTL (ঘড়ি সিদ্ধান্ত নেয়), invalidation (তুমি নাও), eviction (Redis বাধ্য হয়ে নেয়)
- TTL হলো safety net, নির্ভুল সমাধান না — এর দাম হলো staleness window
- Write এ cache update না করে delete করা সাধারণত ভালো — কম খরচ, কম race condition
- ক্রম সবসময় আগে DB, পরে cache — উল্টো করলে পুরনো value cache এ ফিরে আসতে পারে
- একটা write সাধারণত একাধিক key বাসি করে (item, list, filtered list, paginated view) — সবগুলো ভাবতে হবে
- ভালো key naming (namespace, বা version key) ছাড়া invalidation কখনোই সহজ হবে না
- Production এ
KEYS pattern*চালিয়ো না — Redis single-threaded, এটা সবাইকে আটকে দেবে;SCANবা version key ব্যবহার করো - Redis এ
maxmemory-policydefaultnoeviction— pure cache হলেallkeys-lruসেট করা প্রায় সবসময় সঠিক
৪. নতুন Term (Glossary)
| Term | অর্থ |
|---|---|
| TTL (Time To Live) | একটা cache entry কতক্ষণ বাঁচবে, তার পর নিজে থেকেই মুছে যাবে |
| Staleness Window | data বদলানো আর cache সেটা জানার মাঝের সময় — যতক্ষণ পুরনো উত্তর দেখানো হয় |
| Cache Invalidation | data বদলেছে বলে সংশ্লিষ্ট cache entry গুলো ইচ্ছাকৃতভাবে মুছে দেওয়া |
| Eviction Policy | memory ভরে গেলে Redis কোন নিয়মে key বাছাই করে বের করে দেবে |
| LRU | Least Recently Used — সবচেয়ে অনেকক্ষণ আগে ব্যবহৃত key টা বাদ দেওয়া হয় |
| LFU | Least Frequently Used — সবচেয়ে কম বার ব্যবহৃত key টা বাদ দেওয়া হয় |
| Cache Pollution | অপ্রয়োজনীয় (যেমন scan/bot এর আনা) data cache ভরে সত্যিকারের জনপ্রিয় data সরিয়ে দেওয়া |
৫. Reflection Questions
আগে নিজে ভেবে উত্তর দাও, তারপর Answer Key খুলো।
-
TaskFlow এ একজন user একটা task কে "completed" চিহ্নিত করল। তোমার cache এ নিচের key গুলো আছে। কোনগুলো invalidate করতে হবে, আর কোনগুলো ছোঁয়ার দরকার নেই — কেন?
task:99·tasks:user:7·tasks:user:7:completed·tasks:user:12·user:7:profile -
একজন developer বলছে: "আমি সব key তে ১০ সেকেন্ড TTL দিয়ে দেব, তাহলে invalidation এর ঝামেলাই থাকবে না — সর্বোচ্চ ১০ সেকেন্ড পুরনো data দেখাবে, ব্যস।" যুক্তিটা শুনতে ঠিক লাগছে। এতে সমস্যা কী?
-
TaskFlow এর Redis এ
maxmemory-policyসেট করা হয়নি (defaultnoeviction)। একদিন memory ভরে গেল। Application এ ঠিক কী ঘটবে — read গুলো fail করবে, নাকি write গুলো, নাকি দুটোই? আর user এর চোখে ব্যাপারটা কেমন দেখাবে?
Answer Key
প্রশ্ন ১:
task:99— হ্যাঁ, এটাই সেই task, এরcompletedfield বদলেছেtasks:user:7— হ্যাঁ, এই list এ task 99 আছে, আর তার status বদলেছেtasks:user:7:completed— হ্যাঁ, আর এটা সবচেয়ে সহজে ভুলে যাওয়া জায়গা। Task টা এখন এই filtered list এ ঢুকবে, অথচ cached version এ সে নেইtasks:user:12— না, ভিন্ন user, তার list এ এই task নেইuser:7:profile— না, profile data (নাম, ছবি, timezone) task update এ বদলায় না
মূল শিক্ষা: filtered/derived view গুলোই সবচেয়ে বেশি miss হয়। মূল object আর তার list মনে থাকে, কিন্তু "completed only", "page 2", "project অনুযায়ী" — এগুলো ভুলে যাওয়া সহজ।
প্রশ্ন ২: যুক্তিটা correctness এর দিক থেকে খারাপ না, কিন্তু performance এর দিক থেকে এটা cache টাকে প্রায় অকেজো করে দেয়।
ভেবে দেখো — যদি একটা key তে গড়ে প্রতি ১০ সেকেন্ডে ৩টা request আসে, তাহলে প্রথমটা miss (DB তে যাবে), পরের দুটো hit। Hit ratio ~৬৭%। কিন্তু কম জনপ্রিয় key তে, যেখানে প্রতি ৩০ সেকেন্ডে একটা request — প্রতিটা request ই miss, কারণ আগেরটা ততক্ষণে মরে গেছে। Hit ratio প্রায় ০%।
মানে তুমি Redis এর খরচ, জটিলতা আর একটা বাড়তি network hop সবই নিচ্ছ, অথচ DB load প্রায় কমছেই না। তার উপর এখন প্রতি ১০ সেকেন্ডে সব জনপ্রিয় key একসাথে expire হবে — এতে DB তে হঠাৎ হঠাৎ load এর ঢেউ আসবে (Lesson 4.6 এর cache stampede)।
সঠিক পথ: যুক্তিসঙ্গত TTL (৩০-৬০s) + explicit invalidation। TTL টা safety net, invalidation টা আসল কাজ।
প্রশ্ন ৩: noeviction এ read গুলো ঠিকঠাক চলতে থাকবে, কিন্তু write গুলো fail করবে — Redis OOM command not allowed when used memory > 'maxmemory' error দেবে।
Application এর চোখে এটা একটা অদ্ভুত অবস্থা: cache এ যা আছে তা পড়া যাচ্ছে, কিন্তু নতুন কিছু cache এ ঢোকানো যাচ্ছে না। Cache-Aside এ ধাপ ৩ (cache এ লিখে রাখা) প্রতিবার fail করবে, মানে প্রতিটা cache miss চিরকাল miss-ই থেকে যাবে — সেই data আর কখনো cache এ ঢুকতে পারবে না।
User এর চোখে: site ধীরে ধীরে slow হতে থাকবে (যত নতুন data চাওয়া হয়, তত সব DB তে যায়), কিন্তু কিছু "ভাঙবে" না। এই নীরব অবনতিটাই এটাকে বিপজ্জনক বানায় — কোনো loud alarm বাজে না, শুধু latency বাড়তে থাকে।
আর যদি তোমার code এ Redis error টা properly handle করা না থাকে (try/catch ছাড়া redis.set), তাহলে ওই error টা request handler এ গিয়ে user কে 500 দেখাবে — অথচ DB একদম সুস্থ আছে। এজন্যই cache এর write গুলো সবসময় fail-safe রাখতে হয়: cache এ লিখতে না পারা কখনোই request fail করার কারণ হওয়া উচিত না।
৬. Practical Exercise
Tier 3 — Design Exercise
TaskFlow এ একটা নতুন feature আসছে — shared project। একটা project এ একাধিক user থাকতে পারে, আর একটা task একটা project এর অধীনে থাকে। এখন cache এ এই key গুলো আছে:
task:{taskId}
tasks:user:{userId}
tasks:user:{userId}:completed
tasks:project:{projectId}
project:{projectId}:members
যা করতে হবে:
-
User 7, project 3 এর একটা task (id 99) এর title বদলালো। কোন কোন key invalidate হবে? Project 3 এ যদি আরও ৪ জন member থাকে, তাদের cached list গুলোর কী হবে — আর এটা কী নতুন সমস্যা তৈরি করে?
-
উপরের সমস্যাটা এড়াতে version key পদ্ধতি কীভাবে সাহায্য করতে পারে?
tasks:project:3এর জন্য একটা version-ভিত্তিক key design লিখে দেখাও। -
TaskFlow এর জন্য Redis এ কোন
maxmemory-policyবেছে নেবে, আর কেন? তোমার উত্তরে এটাও বলো — যদি একই Redis instance এ cache এবং session data (যেগুলো হারালে user logout হয়ে যাবে) দুটোই রাখা হয়, তাহলে তোমার পছন্দ কি বদলাবে?
৭. Progress Ledger
=== PROGRESS LEDGER ===
Completed: Module 1, 2, 3 (সম্পূর্ণ), 4.1, 4.2
Current: 4.3 — Invalidation, TTL & Eviction
TaskFlow state: Nginx reverse proxy + LB সামনে, horizontal-scale-ready backend,
caching design সম্পূর্ণ কাগজে (Cache-Aside + invalidate-on-write, TTL ৩০-৬০s,
allkeys-lru) — এখনো একটাও line code লেখা হয়নি, পরের lesson এ Redis বসবে
Terms learned (Module 4 so far): Cache Hierarchy, CDN, PoP, Edge Cache TTL,
Buffer Pool, Cache-Aside, Read-Through, Write-Through, Write-Behind,
Write-Around, Cold Start, TTL, Staleness Window, Cache Invalidation,
Eviction Policy, LRU, LFU, Cache Pollution
Weak spots: [তুমি যেখানে আটকেছিলে — নিজে লিখো]
Next: 4.4 — Redis Hands-on: Express + Sequelize এ caching layer (Tier 1, প্রথম
runnable code এই module এ)
=======================
৮. পরের Lesson
Exercise টা করে পাঠাও — বিশেষ করে ৩ নম্বরের শেষ অংশটা (cache আর session একসাথে), ওখানে একটা ফাঁদ আছে।
রেডি হলে next লিখো — Lesson 4.4 এ অবশেষে code। গত তিনটা lesson এ যা যা ঠিক করেছি — Cache-Aside, invalidate-on-write, TTL, LRU — সবগুলো একসাথে বসিয়ে TaskFlow এ একটা সত্যিকারের Redis caching layer বানাব, Express + Sequelize + Redis দিয়ে। আর মেপে দেখব cache আসলে কতটা পার্থক্য করল।