সরাসরি পর্বে যান
পর্ব ৬৫ · ৬৬-এর মধ্যে · মডিউল ১০

System design ইন্টারভিউর ধারণাভিত্তিক প্রশ্ন — trade-off আর follow-up

System Design Interview Concept Questions — Trade-offs, Follow-up Chains and Red Flags at Three Levels

Taught in Bangla, this page collects 55 concept questions for system design interviews, ordered by module and tagged at three experience levels. Each gives a strong trade-off answer with a number or example, a weak-answer sample where useful, and follow-up chains, covering latency, APIs, scaling, caching, databases, messaging, CAP, quorum, consensus, CRDTs, reliability and security, plus interview behaviour and red flags.

এই পর্বে যা শিখবেন

  • যেকোনো ধারণার প্রশ্নকে একটি trade-off হিসেবে বলা — কী পাই, কী দিই, কোন অবস্থায় কোন দিক জেতে, আর একটি সংখ্যা দিয়ে
  • Latency, availability, API, scaling, caching আর ডেটাবেসের প্রশ্নে follow-up-এর শিকল ধরে গভীরে নামা
  • Messaging, CAP-PACELC, quorum, consensus, ঘড়ি, fencing token আর CRDT-র প্রশ্নে সংজ্ঞার ভুল এড়িয়ে সঠিক দাবি করা
  • Resilience, rate limiting, SLO, DR, deployment আর নিরাপত্তার প্রশ্নে বাস্তব পরিচালনার দৃষ্টিভঙ্গি দেখানো
  • ইন্টারভিউর আচরণ: প্রশ্ন পরিষ্কার করা, আপত্তি সামলানো, না জানলে সৎভাবে বলা — আর red flag বাক্যগুলো চিনে এড়ানো

১ · ধারণার প্রশ্নে ইন্টারভিউয়ার কী শোনেন — তিন স্তর আর উত্তরের ছক

System design ইন্টারভিউর একটি বড় অংশ পুরো নকশা নয়, ছোট ধারণার প্রশ্ন: “cache-aside আর write-through-এর পার্থক্য কী?”, “R + W > N হলেও পুরোনো মান আসে কেন?”, “retry-তে jitter কেন লাগে?”। এগুলো আসে নকশার মাঝখানে deep dive হিসেবে, বা আলাদা আলোচনায়। ইন্টারভিউয়ার সংজ্ঞা শুনতে চান না — শুনতে চান আপনি দামটা জানেন কি না। নিচের প্রশ্নগুলো এ ধরনের আলোচনায় প্রায়ই আসা ধাঁচের; কোনো নির্দিষ্ট প্রতিষ্ঠানের প্রশ্ন বা প্রক্রিয়া নয়, আর প্রতিষ্ঠানভেদে ধরন অনেক আলাদা।

স্তরসাধারণত যা শোনা হয়কঠিনতার চিহ্ন
শুরুসঠিক সংজ্ঞা, একটি সুবিধা আর একটি দাম, একটি সহজ উদাহরণ। “কোনটি কখন” বলতে পারা।(সহজ)
মাঝারিসংখ্যায় trade-off, ব্যর্থতার একটি ঘটনা, বাস্তব টুলের আচরণ — আর follow-up-এ এক-দুই স্তর নিচে নামা।(মাঝারি)
অভিজ্ঞকোণার ঘটনা, ভুল ধারণা ভাঙা, পরিচালনার দাম (alert, migration, rollback), আর “কীভাবে যাচাই করব” — অনুমান নয়, মাপ।(কঠিন)

স্তরগুলো শুধু প্রস্তুতির সুবিধার জন্য। নতুন প্রকৌশলীর কাছেও অভিজ্ঞ-স্তরের প্রশ্ন আসতে পারে, আর সিনিয়রকেও শুরুর প্রশ্নে পরিষ্কার উত্তর দিতে হয়।

শক্তিশালী উত্তরের ছক

এক বাক্যে সংজ্ঞা → কী পাই, কী দিই → কখন কোন দিক জেতে → একটি সংখ্যা বা উদাহরণ → কী ভাঙতে পারে, কীভাবে যাচাই
  • প্রশ্ন পরিষ্কার করা (clarifying question): “পড়া বেশি না লেখা?”, “পুরোনো ডেটা কতক্ষণ চলে?” — বেশিরভাগ trade-off-এর উত্তর এই দুই প্রশ্নেই বদলে যায়।
  • জোরে ভাবা (think aloud): অনুমান মুখে বলুন — “ধরছি একই data center, RTT প্রায় ০.৫ ms” — যাতে ইন্টারভিউয়ার ভুল অনুমান ধরিয়ে দিতে পারেন।
  • সংখ্যা: একটি মোটা দাগের সংখ্যা বিশ্বাসযোগ্যতা অনেক বাড়ায়: “৯০% থেকে ৯৯% hit মানে ডেটাবেসে চাপ দশ গুণ কম।” বানানো নির্দিষ্ট সংখ্যার চেয়ে “মাত্রা এরকম” বলা ভালো।
  • Follow-up-এর জন্য তৈরি থাকা (follow-up): প্রতিটি উত্তরের শেষ বাক্যই পরের প্রশ্ন ডেকে আনে। ইচ্ছা করে সেই দরজাটি খোলা রাখুন যেখানে আপনি গভীরে যেতে পারেন।

রেস্তোরাঁয় নতুন একজন ওয়েটারকে জিজ্ঞেস করুন “কোনটা ভালো?” — তিনি বলবেন “সবই ভালো”। অভিজ্ঞ ওয়েটার আগে জিজ্ঞেস করেন, “ঝাল চলে? কতজন? তাড়া আছে?” তারপর বলেন, “কাচ্চি ভালো, তবে সময় লাগবে ২৫ মিনিট; তাড়া থাকলে খিচুড়ি।” তিনি সুপারিশ করেছেন, দামও বলেছেন, আর বিকল্পও দিয়েছেন। ধারণার প্রশ্নে ভালো উত্তর ঠিক এমন: প্রশ্ন, সিদ্ধান্ত, দাম, বিকল্প।

নিচের ছবিতে একটি সাধারণ web সেবার বাক্সগুলো, আর কোন বাক্স নিয়ে প্রশ্ন এই পাতার কোন অংশে। ইন্টারভিউর মাঝে যে বাক্সে আলোচনা পৌঁছায়, সেখানকার প্রশ্নগুলোই সাধারণত আসে।

একটি সাধারণ web সেবা — কোন বাক্সের প্রশ্ন কোন অংশে

Request path from client to data, with the section of this page that covers each box

ক্লায়েন্ট থেকে database পর্যন্ত একটি সাধারণ সেবার বাক্স আর এই পাতার কোন অংশে কোন প্রশ্ন ক্লায়েন্ট DNS · CDN · edge Load balancer · API gateway সার্ভিস A সার্ভিস B সার্ভিস C Cache Queue · log Database Worker Coordination · Raft · lock Observability · নিরাপত্তা · deploy অ্যাপ · ব্রাউজার অংশ ৩ · ৪ rate limiter · অংশ ৪ · ৮ stateless অংশ ৪ · ৮ stateless অংশ ৪ অংশ ৬ leader · replica shard · অংশ ৫ stream processor অংশ ৬ membership · clock · অংশ ৭ সব স্তরে · অংশ ৮ miss
প্রতিটি বাক্সের প্রশ্ন একই ছাঁচের: এটি কী দেয়, কী দামে, আর মরলে বা ধীর হলে বাকিদের কী হয়। অংশ ২-এর হিসাব আর অংশ ৯-এর আচরণ সব বাক্সেই খাটে।

সবচেয়ে বেশি চোখে পড়া ভুল: প্রশ্ন শেষ হওয়ার আগেই টুলের নাম বলা (“Kafka দিয়ে করব”); “সবসময়” আর “কখনো না” দিয়ে উত্তর; ACID-এর C আর CAP-এর C গুলিয়ে ফেলা; আর বানানো নির্দিষ্ট সংখ্যা আত্মবিশ্বাসের সাথে বলা। “নিশ্চিত নই, তবে মাত্রা এরকম, আর এভাবে মেপে দেখব” — এটি দুর্বলতা নয়, পরিণত বিচারের চিহ্ন।

২ · ভিত্তি আর হিসাবের অনুভূতি — latency, percentile, availability আর মাথায় QPS

রিভিশন: পর্ব ১ · System design কী, পর্ব ২ · Requirement আর trade-off, পর্ব ৩ · Back-of-the-envelope হিসাব, পর্ব ৪ · Latency আর percentile, পর্ব ৫ · Availability, পর্ব ৬ · নকশার কাঠামো। পূর্ণ সমাধানের হিসাব পর্ব ৬২-এ।

প্র ০১শুরু · Latency আর throughput কি একই জিনিসের দুই নাম? একটি ভালো করতে গিয়ে অন্যটি খারাপ হয় কখন? (সহজ)

শক্তিশালী উত্তর: না। Latency হলো একটি অনুরোধে কত সময়; throughput হলো প্রতি সেকেন্ডে কতগুলো কাজ শেষ। Batching-এ দুটি উল্টো দিকে যায়: ডেটাবেস ১০ ms ধরে commit জমিয়ে একটি fsync-এ লিখলে (group commit) সেকেন্ডে অনেক বেশি commit হয়, কিন্তু প্রতিটি commit বড়জোর ১০ ms বেশি অপেক্ষা করে। উল্টো দিকে, latency একই রেখে একসাথে বেশি কাজ চালালে throughput বাড়ে — যতক্ষণ না কোনো ধাপ bottleneck হয়। কোনটি আগে, তা ঠিক করে requirement: ব্যবহারকারীর সামনের অনুরোধে p99 latency, রাতের batch কাজে throughput.

দুর্বল উত্তর দেখতে যেমন: “throughput বাড়লে latency এমনিই কমে।” — Queue ভরা সার্ভারে উল্টোটাই ঘটে।

ফলো-আপ:

  • “Bandwidth আর throughput কি এক?” → না; bandwidth পথের সর্বোচ্চ ক্ষমতা, throughput আসলে যতটা বইছে।
  • “Batch-এর আকার কীভাবে ঠিক করবেন?” → দুটি সীমা একসাথে: সর্বোচ্চ আকার আর সর্বোচ্চ অপেক্ষা — যেটি আগে পূরণ হয়।
প্র ০২শুরু · Dashboard বলছে গড় response time ৮০ ms. এটি কি ভালো খবর? (সহজ)

শক্তিশালী উত্তর: গড় লেজ লুকায়। ধরা যাক ৯৯% অনুরোধ ৫০ ms-এ, ১% লাগে ৩ সেকেন্ড: গড় = ০.৯৯ × ৫০ + ০.০১ × ৩০০০ = ৭৯.৫ ms — “সুন্দর” সংখ্যা, অথচ প্রতি ১০০টি অনুরোধে একটি ৩ সেকেন্ড আটকে। যিনি দিনে শত অনুরোধ করেন, তিনি প্রায় নিশ্চিতভাবে সেই লেজে পড়বেন। তাই histogram থেকে percentile — p50, p99, p99.9 — আর লক্ষ্য লিখুন সেভাবে: “p99 ৩০০ ms-এর কম”।

ফলো-আপ:

  • “তিন সার্ভারের p99-এর গড় নিলে মোট p99?” → না, percentile-এর গড় হয় না; histogram-এর bucket যোগ করে তারপর percentile (পর্ব ৫০)।
  • “Load test-এ p99 ভালো, production-এ খারাপ কেন?” → প্রায়ই coordinated omission: load generator ধীর উত্তরের অপেক্ষায় পরের অনুরোধ পাঠায় না, তাই ধীর সময়টাই কম মাপা হয়; সাথে ঠান্ডা cache আর ছোট test ডেটা।
প্র ০৩মাঝারি · একটি search অনুরোধ ১০০টি shard-এর উত্তরের অপেক্ষা করে। প্রতিটি shard মাত্র ১% সময় ধীর। ব্যবহারকারী কত ঘনঘন ধীর উত্তর পাবেন, আর কী করবেন? (মাঝারি)

শক্তিশালী উত্তর: অনুরোধ ধীর হয় যদি অন্তত একটি shard ধীর: ১ − (১ − p)N = ১ − ০.৯৯১০০ ≈ ৬৩.৪%. “বিরল” ১% fan-out-এ সাধারণ ঘটনা হয়ে যায় — tail latency-ই অনুরোধের সময় ঠিক করে। প্রতিকার: (১) hedged request — একটি shard ধরা যাক p95 সময় পেরিয়েও চুপ থাকলে আরেকটি replica-তে একই অনুরোধ; (২) fan-out কমানো — বড় shard বা আগে জোড়া ফল; (৩) deadline-এ যা এসেছে তা দিয়ে আংশিক উত্তর, যেখানে তা চলে। নিচের ছোট simulator সংখ্যাটি মিলিয়ে দেখায়।

দুর্বল উত্তর দেখতে যেমন: “প্রতিটি shard তো ৯৯% দ্রুত, তাই অনুরোধও প্রায় ৯৯% দ্রুত।”

ফলো-আপ:

  • “Hedge কি সবসময় ভালো?” → না; বাড়তি ভার আনে। Overload-এ বন্ধ রাখতে হয়, আর শুধু idempotent পড়ায়।
  • “আংশিক উত্তর কোথায় চলে না?” → টাকার হিসাব বা সিটের তালিকায়; search বা feed-এ প্রায়ই চলে।
// Fan-out tail: a request waits for ALL N leaf calls. Each leaf is "slow" with probability p.
// Closed form: P(at least one slow) = 1 - (1 - p)^N. Seeded simulation checks the formula.
// Hedging: if a leaf is slow, a second copy is sent; the leaf stays slow only if BOTH are slow
// (assumes the two copies are independent), so per-leaf slowness becomes p * p.
function mulberry32(a) { return () => { a = (a + 0x6D2B79F5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a);
  t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; }
const rnd = mulberry32(42), TRIALS = 20000;
function simulate(N, p, hedge) {
  let slowReq = 0;
  for (let t = 0; t < TRIALS; t++) {
    let slow = false;
    for (let i = 0; i < N && !slow; i++) {
      const a = rnd() < p, b = hedge ? rnd() < p : true;
      if (a && b) slow = true;
    }
    if (slow) slowReq++;
  }
  return (100 * slowReq / TRIALS).toFixed(2);
}
console.log("   N      p   formula %   sim %   hedged formula %   hedged sim %");
for (const N of [1, 10, 100]) for (const p of [0.01, 0.001]) {
  const f = (100 * (1 - (1 - p) ** N)).toFixed(2), fh = (100 * (1 - (1 - p * p) ** N)).toFixed(4);
  console.log(String(N).padStart(4) + String(p).padStart(7) + f.padStart(12) + simulate(N, p, false).padStart(8) +
    fh.padStart(19) + simulate(N, p, true).padStart(15));
}

আউটপুট:

   N      p   formula %   sim %   hedged formula %   hedged sim %
   1   0.01        1.00    0.91             0.0100           0.01
   1  0.001        0.10    0.08             0.0001           0.00
  10   0.01        9.56    9.57             0.1000           0.11
  10  0.001        1.00    1.04             0.0010           0.00
 100   0.01       63.40   63.34             0.9951           1.09
 100  0.001        9.52    9.63             0.0100           0.01

Seed-দেওয়া simulation সূত্রের সাথে মেলে: N = ১০০, p = ০.০১-এ সূত্র ৬৩.৪০%, simulation ৬৩.৩৪%. Hedge-এর পরে একটি shard ধীর থাকে শুধু দুটি কপিই ধীর হলে, অর্থাৎ p² = ০.০০০১ — তখন ১০০টির fan-out-এও মাত্র প্রায় ১%. দাম: যত অনুরোধ hedge হয় তত বাড়তি কাজ; p95-এ hedge করলে প্রায় ৫%. শর্তটিও লক্ষ করুন — দুই কপির ধীরতা স্বাধীন ধরা হয়েছে। দুটি replica একই কারণে ধীর হলে (একই hot key, একই GC-ঝড়), লাভ অনেক কম।

প্র ০৪মাঝারি · সার্ভারগুলো ৯০% CPU-তে চলছে — খরচের দিক থেকে তো দারুণ দক্ষতা, তাই না? (মাঝারি)

শক্তিশালী উত্তর: Latency-র দিক থেকে বিপজ্জনক। সরল M/M/1 মডেলে গড় সময় = S ÷ (১ − ρ): ρ = ০.৫-এ ২S, ০.৮-এ ৫S, ০.৯-এ ১০S, ০.৯৫-এ ২০S. ৫০% থেকে ৯০%-এ গড় সময় পাঁচ গুণ, আর লেজ আরও বেশি। তার ওপর একটি instance মরলে বাকিদের ভার বাড়ে: ৪টির একটি গেলে বাকি তিনটিতে ৪/৩ গুণ — ৯০% হয়ে যায় ১২০%, queue অসীমের দিকে। তাই ব্যবহারকারীর সামনের সেবায় লক্ষ্য utilization সাধারণত মাঝামাঝি, যাতে N + ১ আর হঠাৎ ভিড় সামলানো যায়। রাতের batch কাজে ৯০% ঠিকই আছে — সেখানে লক্ষ্য throughput.

ফলো-আপ:

  • “M/M/1 কি বাস্তবে খাটে?” → অনুমানগুলো (Poisson আগমন, exponential সেবা) কাঁচা; কিন্তু “হাঁটু”-র আকৃতি সত্য। আসল হাঁটু load test দিয়ে খুঁজুন।
  • “CPU ছাড়া আর কী দেখবেন?” → queue-র দৈর্ঘ্য, connection pool আর thread pool-এর ব্যস্ততা — এগুলো আগে ভরে।
প্র ০৫মাঝারি · প্রতিটি সার্ভিস ৯৯.৯% available. তাহলে পুরো সিস্টেমও ৯৯.৯%? (মাঝারি)

শক্তিশালী উত্তর: নির্ভর করে তারা পরপর (series) না পাশাপাশি (parallel). একটি অনুরোধ যদি ২০টি সার্ভিসের সবাইকে চায়, availability গুণ হয়: ০.৯৯৯২০ ≈ ৯৮.০২% — বছরে কয়েক দিনের সমান downtime. দুটি স্বাধীন ৯৯% কপি পাশাপাশি থাকলে ব্যর্থতার গুণ: ১ − ০.০১² = ৯৯.৯৯%. শর্ত “স্বাধীন”: একই config push, একই bug, একই rack বা region সব কপিকে একসাথে ফেলে — correlated failure. তুলনার জন্য: ৯৯.৯% মানে ৩৬৫ দিনের বছরে প্রায় ৮ ঘণ্টা ৪৫ মিনিট।

দুর্বল উত্তর দেখতে যেমন: “সব সার্ভিসের দুটি করে কপি দিলেই ৯৯.৯৯%.” — failover-এর সময় আর একই ধরনের ব্যর্থতা হিসাবের বাইরে।

ফলো-আপ:

  • “Series-এর ক্ষতি কমাবেন কীভাবে?” → অনুরোধের পথে কম dependency, কিছু কাজ queue দিয়ে পথের বাইরে, আর graceful degradation — recommendation বন্ধ হলে সাধারণ তালিকা।
  • “Parallel-এর লাভ কে খায়?” → বিকলতা ধরতে আর failover করতে যে সময় লাগে, আর failover নিজেই যে মাঝে মাঝে ব্যর্থ হয়।
প্র ০৬শুরু · “১ কোটি দৈনিক ব্যবহারকারী” শুনে মাথায় প্রথম কোন সংখ্যা আসা উচিত, আর তা নকশা কীভাবে বদলায়? (সহজ)

শক্তিশালী উত্তর: প্রতি সেকেন্ডে অনুরোধ। ধরা যাক জনপ্রতি দিনে ২০টি অনুরোধ: ১ কোটি × ২০ ÷ ৮৬,৪০০ ≈ ২,৩১৫ QPS গড়; peak গড়ের ৩ গুণ ধরলে প্রায় ৬,৯৪৪ — মাথায় “দিন ≈ ১০৫ সেকেন্ড” ধরলে ২,০০০ আর ৬,০০০, একই মাত্রা। অর্থাৎ কয়েক হাজার QPS: কয়েকটি stateless app সার্ভার, সামনে cache, আর পড়ার জন্য read replica-সহ একটি ভালো database সাধারণত যথেষ্ট; sharding এখনই নয়। সংখ্যাটি নির্ভুল হওয়া জরুরি নয় — মাত্রাটি সিদ্ধান্ত বদলায়।

দুর্বল উত্তর দেখতে যেমন: “এক কোটি ব্যবহারকারী, তাই microservices, Kafka আর sharding লাগবে।” — কোনো হিসাব ছাড়াই বড় নকশা।

ফলো-আপ:

  • “জনপ্রতি ২০টি কোথা থেকে?” → অনুমান — আগেই মুখে বলুন, ইন্টারভিউয়ার বদলাতে পারেন।
  • “লেখা কতগুলো?” → read:write ধরা যাক ১০:১ হলে গড় প্রায় ২১০টি লেখা/সেকেন্ড; লেখার চাপই সাধারণত shard-এর প্রশ্ন আনে।
প্র ০৭অভিজ্ঞ · Availability বাড়াতে বাজেট কোথায় দেবেন — কম ভাঙা (MTBF বাড়ানো), নাকি দ্রুত সারানো (MTTR কমানো)? (কঠিন)

শক্তিশালী উত্তর: A = MTBF ÷ (MTBF + MTTR). MTBF ১,০০০ ঘণ্টা, MTTR ১ ঘণ্টা হলে ৯৯.৯০%; MTTR অর্ধেক করলে ৯৯.৯৫% — যা MTBF দ্বিগুণ করারও ফল। গাণিতিকভাবে সমান, কিন্তু খরচে নয়: দ্রুত টের পাওয়া (MTTD), এক ক্লিকে rollback, feature flag আর runbook প্রায়ই অনেক সস্তা, আর সব ব্যর্থতা ঠেকানোও যায় না। তাই প্রায়ই আগে MTTR. ব্যতিক্রম যেখানে একটি ব্যর্থতাই অপূরণীয় — ডেটা হারানো, টাকা দুবার কাটা — সেখানে প্রতিরোধ, অর্থাৎ MTBF আর durability.

ফলো-আপ:

  • “MTTR-এর মধ্যে সবচেয়ে বড় অংশ কোনটি?” → প্রায়ই টের পেতে আর কারণ খুঁজতে যাওয়া সময়; তাই লক্ষণভিত্তিক alert আর সাম্প্রতিক পরিবর্তনের তালিকা।
  • “Blast radius কমানো কোন দিকে পড়ে?” → কোনোটিতে নয়, তৃতীয় হাতিয়ার — canary আর cell দিয়ে একটি ব্যর্থতায় কম মানুষ ক্ষতিগ্রস্ত।

৩ · API আর যোগাযোগ — idempotency, pagination, API-র ধরন, real-time আর schema

রিভিশন: পর্ব ৭ · Networking, পর্ব ৮ · REST API নকশা, পর্ব ৯ · gRPC আর GraphQL, পর্ব ১০ · Real-time যোগাযোগ, পর্ব ১১ · API gateway, পর্ব ১২ · Serialization আর schema

প্র ০৮শুরু · PUT আর POST-এর মধ্যে কোনটি idempotent? একটি payment API-তে এর বাস্তব মানে কী? (সহজ)

শক্তিশালী উত্তর: Idempotent মানে একই অনুরোধ একাধিকবার পাঠালে ফল একবার পাঠানোর মতোই। সংজ্ঞায় GET, PUT আর DELETE idempotent, POST নয়। টাকা কাটার POST-এ timeout হলে client জানে না কাটা হয়েছে কি না; আবার পাঠালে দুবার কাটতে পারে, না পাঠালে লেনদেন হারাতে পারে। সমাধান: client প্রতিটি কাজে একটি Idempotency-Key দেয়; সার্ভার key আর ফল একই transaction-এ রাখে, unique constraint-সহ। একই key-তে আগের উত্তর ফেরত, একই key-তে ভিন্ন body এলে 422 (পর্ব ৮)।

দুর্বল উত্তর দেখতে যেমন: “POST-এ কখনো retry করব না।” — তখন প্রতিটি timeout একটি হারানো বা অনিশ্চিত লেনদেন।

ফলো-আপ:

  • “একই key নিয়ে দুটি অনুরোধ একসাথে এলে?” → প্রথমটি key-এর সারি “চলছে” অবস্থায় বসায়; দ্বিতীয়টি unique constraint-এ আটকে 409 পায় বা অপেক্ষা করে।
  • “Key কতদিন রাখবেন?” → সম্ভাব্য retry-এর সময়ের চেয়ে বেশি — ঘণ্টা থেকে দিন; তারপর TTL দিয়ে মোছা।
প্র ০৯মাঝারি · একটি বড় তালিকার API-তে offset pagination না cursor? (মাঝারি)

শক্তিশালী উত্তর: OFFSET 100000 LIMIT 20-এ database-কে ১,০০,০২০টি সারি হেঁটে ২০টি দিতে হয় — গভীর পাতা ধীর; আর পড়ার মাঝে নতুন সারি এলে একটি সারি দুবার আসে বা বাদ পড়ে। Cursor বা keyset-এ শেষ দেখা সারি থেকে index ধরে পরের ২০টি — যেকোনো গভীরতায় একই খরচ, আর তালিকা বদলালেও স্থির। দাম: “পাতা ৫৭-এ লাফ” নেই, মোট সংখ্যা দেখানো আলাদা খরচ, sort বদলালে cursor-ও বদলায়। কখন offset: ছোট admin তালিকা, যেখানে পাতার নম্বর জরুরি।

ফলো-আপ:

  • “Cursor-এ শুধু created_at কেন নয়?” → একই সময়ের দুই সারি আলাদা করতে id-ও লাগে — (created_at, id) জোড়া।
  • “Cursor client-কে কীভাবে দেবেন?” → একটি অস্বচ্ছ string; ভেতরের গঠন পরে বদলানো যায়, আর client নিজে বানাতে পারে না।
প্র ১০মাঝারি · REST, gRPC না GraphQL — কখন কোনটি জেতে? (মাঝারি)

শক্তিশালী উত্তর: প্রশ্নটি “কোনটি ভালো” নয়, “client কারা”। বাইরের পাবলিক API-তে REST: HTTP caching, সব ভাষায় সহজ, সবাই বোঝে। ভেতরের সার্ভিস-থেকে-সার্ভিসে gRPC: .proto চুক্তি থেকে কোড, ছোট binary, HTTP/2 stream, deadline আর cancellation. মোবাইলের একটি পাতায় অনেক সার্ভিসের ডেটা লাগলে GraphQL বা একটি BFF — এক round trip-এ ঠিক যতটুকু দরকার। দাম: gRPC ব্রাউজারে সরাসরি চলে না আর L4 load balancer-এ দীর্ঘ সংযোগ ভার অসম করে; GraphQL-এ N+1 query, কঠিন HTTP caching আর খরচের সীমা টানার দায়।

দুর্বল উত্তর দেখতে যেমন: “gRPC দ্রুত, তাই সবখানে gRPC.”

ফলো-আপ:

  • “একটি ভারী GraphQL query সার্ভার ডুবাতে পারে?” → পারে; depth limit, query-র খরচ হিসাব আর persisted query দিয়ে সীমা।
  • “BFF আর GraphQL কি একই সমস্যার উত্তর?” → অনেকটা; BFF সরল কোড, GraphQL নমনীয় কিন্তু নিজের পরিকাঠামো চায়।
প্র ১১মাঝারি · Live score বা notification দেখাতে polling, long polling, SSE না WebSocket? (মাঝারি)

শক্তিশালী উত্তর: Short polling সহজ কিন্তু দামি: বিরতি I হলে গড় দেরি I/২, অনুরোধ N/I — ১ লাখ client প্রতি সেকেন্ডে poll করলে সেকেন্ডে ১ লাখ অনুরোধ, যার প্রায় সবই খালি। Long polling উত্তর আটকে রাখে, খালি উত্তর কমে। SSE এক দিকের স্থায়ী HTTP স্রোত, Last-Event-ID দিয়ে নিজেই ফাঁক পূরণ করে — live score আর notification-এ মানানসই। WebSocket দুই দিকের নালি — chat বা game; কিন্তু ack, resume আর ক্রম নিজেকে বানাতে হয়। সব স্থায়ী সংযোগের দাম একই: stateful gateway, প্রতি সংযোগে memory, আর deploy-এ সবার একসাথে ফেরা।

দুর্বল উত্তর দেখতে যেমন: “Real-time মানেই WebSocket.”

ফলো-আপ:

  • “Gateway restart-এ কী হয়?” → হাজারো client একই মুহূর্তে reconnect — reconnect storm; প্রতিকার backoff আর full jitter, আর সংযোগ ধাপে ধাপে drain.
  • “App পটভূমিতে থাকলে?” → OS সংযোগ কেটে দেয়; platform push দিয়ে জাগিয়ে তারপর sync.
প্র ১২অভিজ্ঞ · Rolling deploy চলছে; নতুন সংস্করণ বার্তায় একটি field যোগ করেছে আর একটি সরিয়েছে। কী ভাঙতে পারে? (কঠিন)

শক্তিশালী উত্তর: Rolling deploy-এ পুরোনো আর নতুন কোড একসাথে চলে, rollback-এ উল্টো দিকেও। তাই দুটোই লাগে: backward (নতুন কোড পুরোনো ডেটা পড়ে) আর forward (পুরোনো কোড নতুন ডেটা পড়ে)। Default-সহ optional field যোগ নিরাপদ। যে field পুরোনো কোড চায় তা সরালে পুরোনো reader ভাঙে; Protobuf-এ মোছা field-এর নম্বর আবার ব্যবহার করলে পুরোনো ডেটা নতুন অর্থে পড়া হয় — নিঃশব্দ ভুল। Queue আর log-এ পুরোনো বার্তা দিন পরেও পড়া হতে পারে, তাই সময়ের হিসাবও লাগে। প্রতিকার: মোছা নম্বর reserved, CI-তে schema registry-র compatibility check, আর expand → migrate → contract.

ফলো-আপ:

  • “Required field যোগ করলে?” → পুরোনো writer সেটি দেয় না, নতুন reader ব্যর্থ হয়; তাই optional আর default.
  • “JSON-এ ID সংখ্যা হিসেবে পাঠালে?” → ২৫৩-এর বড় integer JavaScript-এ নিঃশব্দে বদলায়; ID পাঠান string হিসেবে।
প্র ১৩শুরু · নতুন একটি HTTPS সংযোগে প্রথম উত্তর আসতে কয়টি round trip লাগে, আর কেন তা নকশায় জরুরি? (সহজ)

শক্তিশালী উত্তর: TCP-র handshake ১, TLS 1.3 ১, অনুরোধ-উত্তর ১ — মোট ৩ RTT; TLS 1.2-এ ৪, QUIC-এ ২। RTT ১৫০ ms হলে শুধু এতেই ৪৫০ ms, সার্ভার কিছু করার আগেই। তাই keep-alive, connection pool আর HTTP/2-এর multiplexing দিয়ে সংযোগ বারবার ব্যবহার, আর CDN বা edge দিয়ে TLS ব্যবহারকারীর কাছে শেষ করা। দূরত্ব কোড দিয়ে কমে না: fibre-এ প্রতি ১০০ km-এ RTT অন্তত প্রায় ১ ms, তাই প্রায় ১২,৯০০ km দূরের region-এ অন্তত প্রায় ১২৯ ms.

ফলো-আপ:

  • “0-RTT-এর ঝুঁকি?” → early data আবার পাঠানো (replay) যায়, তাই শুধু idempotent অনুরোধে।
  • “Connection pool কত বড়?” → Little-এর সূত্রে: প্রতি সেকেন্ডে call × গড় সময়, সাথে কিছু বাড়তি।

৪ · Scaling, load balancing আর caching — stateless, consistent hashing, stale data আর stampede

রিভিশন: পর্ব ১৩ · Scaling, পর্ব ১৪ · Load balancing, পর্ব ১৫ · Session আর state, পর্ব ১৬ · Consistent hashing, পর্ব ১৭ · CDN, পর্ব ১৮ · Overload, পর্ব ২৮ · Caching কৌশল, পর্ব ২৯ · Eviction আর invalidation, পর্ব ৩০ · Distributed cache

প্র ১৪মাঝারি · L4 না L7 load balancer? আর algorithm — round robin, least connections না power of two choices? (মাঝারি)

শক্তিশালী উত্তর: L4 দেখে IP আর port; একটি সংযোগের পুরোটা একই backend-এ যায় — দ্রুত আর সস্তা। L7 HTTP পড়ে, প্রতিটি অনুরোধ আলাদা করে বাছে, path ধরে routing আর retry করে — বিনিময়ে TLS খোলা আর বেশি CPU. HTTP/2 বা gRPC-র দীর্ঘ সংযোগে L4 ভার অসমান করে, কারণ একটি সংযোগে হাজারো অনুরোধ। Algorithm: সমান সার্ভারে round robin যথেষ্ট; গতি অসমান হলে least connections অনেক ভালো (পর্ব ১৪-এর simulator-এ p99 প্রায় ১,৯৪৫ বনাম ১২৪ ms); অনেক load balancer আর পুরোনো তথ্যে power of two choices — এলোমেলো দুটি দেখে কম ব্যস্তটি — সবাই একই “সেরা” সার্ভারে ঝাঁপিয়ে পড়ে না।

ফলো-আপ:

  • “একটি সার্ভার মরলে কতক্ষণ অনুরোধ যায়?” → প্রায় fall × interval + timeout; interval ২ সেকেন্ড, পরপর ৩টি ব্যর্থতা আর timeout ১ সেকেন্ড হলে ৭ সেকেন্ড পর্যন্ত — passive check আর retry দিয়ে কমানো।
  • “Load balancer নিজে মরলে?” → জোড়া LB, virtual IP সরানো বা anycast; LB-ও একটি বাক্স।
প্র ১৫মাঝারি · লগইন রাখবেন sticky session-এ, shared session store-এ, না JWT-তে? (মাঝারি)

শক্তিশালী উত্তর: Sticky session সবচেয়ে সহজ, কিন্তু সার্ভারটি মরলে তার সব session হারায়, ভার অসম হয়, deploy যন্ত্রণার। Shared session store সাধারণ উত্তর: cookie-তে শুধু একটি এলোমেলো ID, তথ্য TTL-সহ store-এ; যেকোনো সার্ভার পড়ে, আর logout মানে একটি key মোছা — দাম প্রতি অনুরোধে একটি store-lookup আর store-এর নিজের HA. JWT store ছাড়াই যাচাই হয় — অনেক সেবা বা অঞ্চলে সুবিধা — কিন্তু ফেরত নেওয়া কঠিন: মেয়াদ না ফুরানো পর্যন্ত চুরি যাওয়া token চলে। তাই ছোট মেয়াদ, refresh token, আর জরুরি ক্ষেত্রে deny list.

দুর্বল উত্তর দেখতে যেমন: “JWT encrypted, তাই ভেতরে যা খুশি রাখা যায়।” — সাধারণ JWT-র payload শুধু Base64URL, যে কেউ পড়তে পারে।

ফলো-আপ:

  • “Deny list রাখলে তো আবার store লাগল?” → হ্যাঁ, তবে ছোট — শুধু বাতিল token, মেয়াদ পর্যন্ত।
প্র ১৬মাঝারি · Cache সার্ভার ৪ থেকে ৫টি করবেন। hash(key) mod N-এ সমস্যা কী, আর consistent hashing কী বাঁচায় — কী বাঁচায় না? (মাঝারি)

শক্তিশালী উত্তর: mod N-এ N থেকে N + ১ করলে N/(N + ১) ভাগ key-এর ঠিকানা বদলায় — ৪ থেকে ৫-এ ৮০%; cache-এ তা মানে হঠাৎ প্রায় সব miss আর database-এ ঢল। Consistent hashing-এ সার্ভার আর key একই ring-এ; নতুন সার্ভার শুধু নিজের অংশটুকু নেয় — গড়ে ১/(N + ১), অর্থাৎ ২০%. অল্প সার্ভারে ring-এর ভাগ অসমান, তাই প্রতিটি সার্ভার অনেক virtual node হয়ে বসে। যা বাঁচায় না: এটি key-এর সংখ্যা সমান করে, অনুরোধের চাপ নয় — একটি hot key তবু একটি সার্ভারেই পড়ে।

ফলো-আপ:

  • “Hot key-এর উপায়?” → অ্যাপের ভেতরে ছোট TTL-এর local cache, key-এর কয়েকটি কপি (key#1…key#k) ছড়িয়ে পড়া, আর একই key-এর অনুরোধ এক করা।
  • “Ring ছাড়া বিকল্প?” → rendezvous hashing — প্রতিটি সার্ভারের score, সর্বোচ্চ জেতে; virtual node লাগে না, খরচ O(N).
প্র ১৭শুরু · Cache-aside, write-through আর write-behind — কোনটি কখন? (সহজ)

শক্তিশালী উত্তর: Cache-aside: app আগে cache দেখে, miss হলে database থেকে এনে বসায় — শুধু চাওয়া ডেটা cache-এ ওঠে, cache মরলেও সেবা চলে; সবচেয়ে প্রচলিত। Write-through: প্রতিটি লেখা cache আর database দুটিতেই — টাটকা, কিন্তু লেখা ধীর আর অনেক না-পড়া ডেটাও cache-এ। Write-behind: আগে cache, পরে batch-এ database — খুব দ্রুত লেখা, কিন্তু cache crash করলে লেখা হারায়; view counter-এর মতো ডেটায় চলে, টাকায় নয়। সংখ্যায় লাভ: cache ১ ms আর database ২০ ms ধরলে hit ৯০%-এ গড় ৩ ms, ৯৯%-এ ১.২ ms.

ফলো-আপ:

  • “Wallet-এর balance cache থেকে দেখাবেন?” → দেখানো চলতে পারে, কিন্তু টাকা কাটার সিদ্ধান্ত কখনো cache থেকে নয় — database-এ শর্তসহ লেখা।
প্র ১৮অভিজ্ঞ · Cache-aside-এ ব্যবহারকারী মাঝে মাঝে পুরোনো দাম দেখছেন। কেন, আর কতটা গভীরে যাবেন? (কঠিন)

শক্তিশালী উত্তর: এটি আসলে একটি প্রশ্নের শিকল — প্রতিটি উত্তরের পরে ইন্টারভিউয়ার এক ধাপ নিচে নামেন। ছয়টি স্তর: (১) invalidation নেই, শুধু TTL; (২) delete আর commit-এর উল্টো ক্রম; (৩) commit-এর পরে delete করলেও stale set-এর race; (৪) delete বার্তাটাই হারানো; (৫) miss-এ পিছিয়ে থাকা replica থেকে পড়া; (৬) সব মিলিয়ে চূড়ান্ত নকশা। নিচের stepper প্রতিটি ধাপ সংখ্যাসহ দেখায়। শক্তিশালী উত্তরের চিহ্ন হলো প্রথম বাক্যেই “কতটা পুরোনো চলে?” জিজ্ঞেস করা — কয়েক সেকেন্ড চললে TTL আর delete যথেষ্ট, এক মুহূর্তও না চললে সেই পড়া cache থেকে নয়।

দুর্বল উত্তর দেখতে যেমন: “TTL ছোট করে দেব।” — Race-এর জানালা ছোট হয়, বন্ধ হয় না, আর database-এ চাপ বাড়ে।

  1. শুধু TTLলেখা cache জানে না
  2. উল্টো ক্রমআগে DEL, পরে COMMIT
  3. Stale setদেরিতে আসা SET
  4. হারানো DELcrash বা timeout
  5. Replica lagপুরোনো কপি থেকে ভরা
  6. চূড়ান্ত নকশাস্তরে স্তরে প্রতিরক্ষা
এই ধাপে
ইন্টারভিউয়ারের প্রশ্ন
ঘড়ি · DB · cache
প্রতিকার
দাম
  1. শুধু TTL. লেখা যায় database-এ, cache-এর কপি তা জানে না। দাম ১০০ থেকে ১২০ হলো, অথচ cache-এর কপির TTL-এর ৩০০ সেকেন্ড বাকি — এই পুরো সময় সবাই ১০০ দেখবেন। প্রথম উত্তর: লেখার পরে key delete — পরের পাঠক miss করে নতুন মান আনবেন।
  2. উল্টো ক্রম. কেউ আগে delete করে তারপর database বদলান। ০ ms-এ DEL, ২ ms-এ একজন পাঠক miss করে database থেকে তখনো-পুরোনো ১০০ পড়ে বসালেন, ৩ ms-এ COMMIT ১২০. Cache আবার ১০০ — জানালাটি পুরো লেখার সময়জুড়ে। উত্তর: আগে COMMIT, তারপর DEL.
  3. Stale set. ক্রম ঠিক থাকলেও race বাকি। পাঠক A miss করে ১০০ পড়লেন, তারপর থেমে গেলেন — GC বা network-এর দেরি। ৩ ms-এ B-র COMMIT ১২০, ৪ ms-এ DEL — মোছার কিছু নেই। ৬০ ms-এ A SET ১০০ পাঠালেন। কোনো লেখা বাকি নেই যে মুছবে। উত্তর: miss-এ cache একটি lease token দেয়, DEL তা বাতিল করে, তাই A-র set প্রত্যাখ্যাত (পর্ব ২৮)।
  4. হারানো DEL. COMMIT হলো, তারপর app crash করল বা cache-এ পৌঁছাতে timeout — DEL কখনো গেল না। কোড নির্ভুল, তবু cache ১০০. উত্তর: app-এর বদলে database-এর commit log পড়ে delete পাঠানো (change data capture), retry-সহ; আর প্রতিটি key-তে TTL — যত বিরল race-ই হোক, ভুল কপি বড়জোর TTL পর্যন্ত টেকে।
  5. Replica lag. DEL ঠিকমতো পৌঁছাল, কিন্তু miss-এর পড়া গেল একটি read replica-তে, যা ৫০০ ms পিছিয়ে — সেখানে এখনো ১০০. সেটিই cache-এ বসল। উত্তর: cache ভরার পড়া primary থেকে, বা মানের সাথে version রেখে শুধু নতুনতর set গ্রহণ। Delayed double delete জানালা ছোট করে, বন্ধ করে না।
  6. চূড়ান্ত নকশা. স্তরে স্তরে: COMMIT-এর পরে DEL, CDC দিয়ে নিশ্চিত, lease বা version দিয়ে race বন্ধ, আর প্রতিটি key-তে TTL — সবচেয়ে খারাপ ক্ষেত্রেও staleness TTL-এর মধ্যে। শেষ বাক্যটি সবচেয়ে জরুরি: যে পড়ায় এক মুহূর্তও পুরোনো চলে না — balance থেকে টাকা কাটা, শেষ সিট — তা cache থেকে নয়।
প্র ১৯অভিজ্ঞ · একটি জনপ্রিয় key-এর মেয়াদ ফুরাতেই database-এর CPU লাফিয়ে উঠছে। কী ঘটছে, আর প্রতিকার কী? (কঠিন)

শক্তিশালী উত্তর: Cache stampede: মেয়াদ শেষে যত অনুরোধ আসে, recompute শেষ হওয়ার আগ পর্যন্ত সবাই miss করে database-এ যায়। Little-এর সূত্রে সংখ্যাটি সরল — সেকেন্ডে ২,০০০ অনুরোধ × ৫০ ms recompute = প্রায় ১০০টি একই query একসাথে। প্রতিকার: (১) single-flight — একটি lock বা lease, একজনই হিসাব করেন, বাকিরা অপেক্ষা করেন বা পুরোনো মান পান; (২) soft TTL বা stale-while-revalidate — মেয়াদ শেষেও পুরোনো মান দিয়ে পেছনে নবায়ন; (৩) মেয়াদের আগেই সম্ভাবনাভিত্তিক নবায়ন (XFetch); (৪) অনেক key একসাথে লেখা হলে TTL jitter — নইলে সবার মেয়াদ একই সেকেন্ডে।

ফলো-আপ:

  • “অস্তিত্বহীন key-এর ঢল?” → ভিন্ন রোগ (penetration): “নেই” উত্তরটিই অল্প TTL-এ cache করা, বা সামনে Bloom filter.
  • “Lock-ধারক মরে গেলে?” → lock-এর নিজের ছোট মেয়াদ; ধারক না ফিরলে পরের জন নেন।
প্র ২০অভিজ্ঞ · Hit ratio ৯০% থেকে ৯৯% করা কি শুধু ৯ শতাংশের উন্নতি? আর cache পুরো খালি হলে কী হবে? (কঠিন)

শক্তিশালী উত্তর: না — database দেখে miss, hit নয়। Database-এর ভার = মোট অনুরোধ × (১ − h): ১০% থেকে ১% মানে চাপ দশ গুণ কম। উল্টো পিঠ বিপজ্জনক: ৯৯% hit-এর সেবায় cache হারালে database-এ চাপ হঠাৎ ১০০ গুণ — যে database কখনো এত চাপ দেখেনি। তাই নকশায় প্রশ্ন: cache ঠান্ডা হলে কী? উত্তর হতে পারে replica-সহ cache, ধীরে গরম করা (ধাপে ধাপে traffic ঢোকানো), database-এর সামনে concurrency limit আর load shedding, আর জরুরি অবস্থায় কম-জরুরি feature বন্ধ। CDN-এর ক্ষেত্রেও একই অঙ্ক: ৯৯% hit-এর সাইটে CDN বিকল হলে origin-এ ১০০ গুণ।

ফলো-আপ:

  • “৬টি cache shard-এর একটি মরলে?” → তার ভাগের hit মুহূর্তে miss; পর্ব ৩০-এর হিসাবে ৯৫% hit-এ database-এর চাপ ৪.১৭ গুণ — gutter pool বা replica সেই ধাক্কা নেয়।
প্র ২১অভিজ্ঞ · চাপ সামর্থ্যের দ্বিগুণ হলে সিস্টেম ধীরে না নেমে হঠাৎ ধসে পড়ে কেন? Queue বড় করলে কি সমাধান? (কঠিন)

শক্তিশালী উত্তর: চাপ সামর্থ্য ছাড়ালে queue লম্বা হয়, অপেক্ষা client-এর timeout ছাড়ায়, client আবার চেষ্টা করে — চাপ আরও বাড়ে। সার্ভার পুরো ব্যস্ত, অথচ সময়মতো সফল উত্তর — goodput — প্রায় শূন্য, কারণ সে এমন কাজ করছে যার অপেক্ষক আগেই চলে গেছে। বড় queue এটি আরও খারাপ করে: অসীম queue একটি bug. পর্ব ১৮-এর simulator-এ চাপ দ্বিগুণে bounded queue আর fail fast-এ goodput সেকেন্ডে প্রায় ১০০ থাকে, অসীম queue-তে নামে প্রায় ৬-এ। প্রতিকার: সীমিত queue, মেয়াদ-পেরোনো কাজ বাদ, দরজায় সস্তায় আর অগ্রাধিকার বুঝে 503 বা 429 (load shedding), ভেতরে backpressure, আর retry-কে বাজেটে বাঁধা।

ফলো-আপ:

  • “চাপ কমে গেলেও সিস্টেম ফেরে না কেন?” → metastable failure: retry আর ঠান্ডা cache নিজেরাই চাপ টিকিয়ে রাখে; retry budget আর ধীরে traffic ফেরানো লাগে।
  • “কাকে আগে ফেরাবেন?” → কম-জরুরি অনুরোধ (prefetch, analytics) আগে; লগইন আর payment শেষে।

৫ · ডেটাবেস — storage engine, index, replication, sharding আর transaction

রিভিশন: পর্ব ১৯ · Storage engine, পর্ব ২০ · SQL বনাম NoSQL, পর্ব ২১ · Index, পর্ব ২২ · Replication, পর্ব ২৩ · Sharding, পর্ব ২৪ · Isolation, পর্ব ২৫ · Distributed transaction, পর্ব ২৬ · Object storage, পর্ব ২৭ · Search, পর্ব ৫৪ আর পর্ব ৬০-এর case study

প্র ২২শুরু · নতুন একটি সেবার জন্য SQL না NoSQL? (সহজ)

শক্তিশালী উত্তর: প্রশ্নটিকে উল্টে দিন: কোন ডেটা, কোন প্রশ্নে কতবার পড়া-লেখা, আর কোন নিশ্চয়তা লাগে। Relational database দেয় schema, join, ACID transaction আর আগে না-ভাবা প্রশ্নেও উত্তর — টাকা, অর্ডার, সিটের মতো সম্পর্কভরা ডেটায় শক্ত শুরু। NoSQL-এর পরিবারগুলো নির্দিষ্ট access pattern-এ জেতে: key দিয়ে আনা-রাখা, বিশাল লেখার চাপ, সহজে ভাগ করা — বিনিময়ে প্রশ্ন ধরে আগে নকশা, ডেটার কপি আর join-এর অভাব। বেশিরভাগ সিস্টেমের সাধারণ শুরু একটি relational database আর একটি cache; বিশেষ store আসে মাপা প্রয়োজনে।

দুর্বল উত্তর দেখতে যেমন: “NoSQL scale করে, SQL করে না।” — SQL-ও replica আর sharding-এ বাড়ে; আর “schemaless” মানে schema কোডে চলে গেছে।

ফলো-আপ:

  • “পণ্যের নাম দিয়ে search?” → LIKE '%x%' নয়; আলাদা search engine-এ inverted index, primary database থেকে CDC দিয়ে হালনাগাদ — ফল একটু পিছিয়ে থাকে।
প্র ২৩মাঝারি · B-tree না LSM-tree — লেখা-ভারী আর পড়া-ভারী কাজে কোনটি, আর কেন? (মাঝারি)

শক্তিশালী উত্তর: B-tree জায়গায় বদলায়: প্রতিটি লেখা একটি random page বদল, পড়া অনুমানযোগ্য — fan-out ৫০০-র ৩ স্তরেই ১২.৫ কোটি key. LSM-tree জমিয়ে রাখে: memtable থেকে ক্রমিকভাবে SSTable, পেছনে compaction — লেখা দ্রুত, কিন্তু একটি পড়ায় কয়েক জায়গা দেখতে হতে পারে (Bloom filter সেটা কমায়), আর compaction CPU ও ডিস্ক খায়। তাই লেখা-ভারী (log, event, time-series) কাজে LSM প্রায়ই জেতে, পড়া-ভারী আর range-ভারী OLTP-তে B-tree. Read, write আর space amplification একসাথে কমানো যায় না — একটি কমালে অন্যটি বাড়ে।

ফলো-আপ:

  • “LSM-এ মাঝে মাঝে লেখা থেমে যায় কেন?” → compaction পিছিয়ে পড়লে engine লেখা ধীর করে (write stall) — p99-এ ধরা পড়ে।
  • “Analytics-এ কোনটি?” → দুটির কোনোটি নয় — column store; ৫০টির ২টি কলাম পড়লে ৪% byte.
প্র ২৪মাঝারি · Query: WHERE status = ? ORDER BY created_at DESC LIMIT 20. কোন index দেবেন, আর প্রতিটি index-এর দাম কী? (মাঝারি)

শক্তিশালী উত্তর: Composite index (status, created_at): সমতার কলাম আগে, sort বা range-এর কলাম পরে — index ঠিক সেই ক্রমেই সারি দেয়, sort লাগে না, ২০টি পেয়েই থামে। উল্টো ক্রম (created_at, status) এখানে কম কাজের, কারণ index কাজে লাগে বাঁ দিক থেকে মেলা অংশে — leftmost prefix. দরকারি সব কলাম index-এ থাকলে টেবিলে যেতেই হয় না (covering index). দাম: প্রতিটি INSERT আর UPDATE সব index হালনাগাদ করে — লেখা ধীর, জায়গা বাড়ে। আর অনুমান নয়: EXPLAIN দিয়ে plan দেখা।

ফলো-আপ:

  • “status-এর মাত্র তিনটি মান, তবু index?” → একা status-এ selectivity কম; কিন্তু sort-এর সাথে জোড়ায় লাভ বড়।
  • “Sharded টেবিলে এই query?” → status shard key না হলে সব shard-এ যায় (scatter-gather) — প্র ২৬।
প্র ২৫মাঝারি · ব্যবহারকারী প্রোফাইল বদলে সাথে সাথে রিফ্রেশ করলেন, পুরোনোটাই দেখছেন। কেন, আর replication sync না async? (মাঝারি)

শক্তিশালী উত্তর: লেখা গেছে leader-এ, পড়া গেছে একটি follower-এ যে এখনো পিছিয়ে — replication lag. প্রতিকার read-your-writes: লেখার কিছুক্ষণ পর পর্যন্ত সেই ব্যবহারকারীর পড়া leader-এ, বা client শেষ লেখার অবস্থান (LSN) মনে রেখে ততটা এগোনো replica বাছে। Sync বনাম async একটি দর-কষাকষি: async-এ commit দ্রুত, কিন্তু leader মরলে “OK” পাওয়া লেখাও হারাতে পারে; সব follower-এর ack চাইলে একটি follower বন্ধ হলেই লেখা আটকায়। মাঝের পথ semi-sync — অন্তত একটি follower-এর ack.

ফলো-আপ:

  • “Replica বাড়ালে লেখার ক্ষমতা বাড়ে?” → না; replication পড়া বাড়ায়, লেখা নয় — প্রতিটি replica সব লেখাই করে।
  • “Failover-এ সবচেয়ে বড় ঝুঁকি?” → পুরোনো leader জেগে উঠে লেখা নেওয়া — split brain; তাকে fencing করা লাগে (প্র ৩৮)।
প্র ২৬অভিজ্ঞ · একটি orders টেবিল shard করবেন। Shard key কী হবে, আর কোন ভুলগুলো পরে সবচেয়ে দামি? (কঠিন)

শক্তিশালী উত্তর: আগে সবচেয়ে ঘন query: “একজন ব্যবহারকারীর অর্ডার” হলে user_id — একজনের সব ডেটা এক shard-এ, query এক জায়গায়। চারটি শর্ত: অনেক ভিন্ন মান, সমান ছড়ানো, ঘন query এক shard-এ, আর বৃদ্ধিতেও টেকে। দামি ভুল: (১) created_at-এর মতো ক্রমিক key-এ range ভাগ — আজকের সব লেখা এক shard-এ (hot spot); (২) hash mod N — node বাড়ালে প্রায় সব সরে; বদলে node-এর চেয়ে অনেক বেশি নির্দিষ্ট partition (যেমন ২৫৬টি) বানিয়ে পুরো partition সরানো — ৪ থেকে ৫ node-এ সরে ৫১টি, প্রায় ২০%; (৩) shard key ছাড়া ঘন query — সব shard-এ scatter-gather, tail latency বাড়ে।

ফলো-আপ:

  • “একজন বিক্রেতার লাখো অর্ডার?” → hot key: key-এ salt যোগ করে কয়েক ভাগে, পড়ায় মিলিয়ে নেওয়া।
  • “কেন্দ্রীয় counter ছাড়া order ID?” → UUIDv7 বা Snowflake-ধাঁচ: প্রতি worker প্রতি ms-এ ৪,০৯৬টি, ৪১-bit সময়ে প্রায় ৬৯.৭ বছর; ঘড়ি পেছালে সাবধান।
প্র ২৭অভিজ্ঞ · Wallet থেকে দুটি অনুরোধ একসাথে ৮০০ আর ৬০০ টাকা তুলল, ব্যালান্স ছিল ১,০০০. দুটিই সফল। Database তো ACID — কীভাবে? (কঠিন)

শক্তিশালী উত্তর: App দুজনেই আগে পড়েছে ১,০০০, নিজে বিয়োগ করে লিখেছে — lost update. বহুল ব্যবহৃত ডিফল্ট READ COMMITTED এটি ঠেকায় না; ACID-এর I মানে “কোনো একটি isolation level”, সবসময় serializable নয়। হাতিয়ার, সরল থেকে কঠিন: শর্তসহ atomic UPDATE — SET balance = balance - 800 WHERE id = ? AND balance >= 800, প্রভাবিত সারি ০ হলে প্রত্যাখ্যান; SELECT … FOR UPDATE; version কলাম দিয়ে optimistic লেখা; বা SERIALIZABLE আর ব্যর্থ হলে পুরো transaction আবার। আরও সূক্ষ্ম রোগ write skew: দুজন দুটি আলাদা সারিতে লেখেন, নিয়মটি ভাঙে দুটি মিলিয়ে — snapshot isolation-এও ঘটে।

দুর্বল উত্তর দেখতে যেমন: “Transaction-এর ভেতরে রাখলেই হবে।”

ফলো-আপ:

  • “PostgreSQL-এর REPEATABLE READ আর MySQL-এর একই নামের level কি এক?” → না; প্রথমটি আসলে snapshot isolation, দ্বিতীয়টির আচরণ আলাদা — নাম নয়, আচরণ যাচাই।
প্র ২৮অভিজ্ঞ · অর্ডার, পেমেন্ট আর স্টক তিনটি সেবার তিনটি database-এ। 2PC, saga না outbox? (কঠিন)

শক্তিশালী উত্তর: 2PC সত্যিকারের atomic commit দেয়, কিন্তু দামে: অতিরিক্ত round trip আর fsync, পুরো সময় lock, আর coordinator মরলে প্রস্তুত participant lock ধরে আটকে থাকে। একই সংস্থার কয়েকটি database-এ, কম লেনদেনে চলে; স্বাধীন microservice বা বাইরের payment provider-এ সাধারণত নয়। Saga: local transaction-এর শিকল, প্রতিটির একটি compensation — ব্যর্থ হলে উল্টো ক্রমে “ফেরত”। দাম: isolation নেই, তাই “স্টক ধরে রাখা” ধরনের pending অবস্থা লাগে। আর প্রতিটি ধাপে event পাঠাতে outbox: event আর ব্যবসার পরিবর্তন একই local transaction-এ, relay পরে পাঠায় — হারায় না, দুবার যেতে পারে, তাই consumer idempotent.

ফলো-আপ:

  • “Compensation নিজেই ব্যর্থ হলে?” → retry করতে হয়, তাই compensation-ও idempotent; শেষে মানুষের হাতে যাওয়ার পথ।
  • “Choreography না orchestration?” → ধাপ বেশি আর compensation জটিল হলে orchestrator — পুরো অবস্থা এক জায়গায় দেখা যায়।
প্র ২৯মাঝারি · ঈদের আগে বাসের টিকিটের ভিড়: একই সিট দুজন কিনছেন। Double booking কোথায় ঠেকাবেন? (মাঝারি)

শক্তিশালী উত্তর: সত্যের এক জায়গায় — seat database-এ শর্তসহ লেখা: UPDATE seats SET status = 'held', hold_until = ? WHERE id = ? AND status = 'available'; প্রভাবিত সারি ১ হলে আপনার, ০ হলে অন্য কেউ আগে পেয়েছেন। Hold-এর মেয়াদ থাকে, পেমেন্ট না হলে সিট ফেরে। Cache, app-এর memory বা শুধু একটি Redis lock সত্যের উৎস নয় — lock-এর মেয়াদ ফুরিয়ে দুজন ধারক হতে পারেন। ভিড় সামলানো আলাদা স্তরে: edge-এ virtual waiting room, যা database-এর সামর্থ্য বুঝে সেকেন্ডে নির্দিষ্ট সংখ্যক মানুষ ঢোকায়।

ফলো-আপ:

  • “পেমেন্ট timeout হলো — টাকা কাটল কি না জানি না?” → payment-এর অবস্থায় UNKNOWN, একই idempotency key দিয়ে খোঁজ, আর দিনশেষে gateway-এর রিপোর্টের সাথে reconciliation.
প্র ৩০মাঝারি · ব্যবহারকারীর ছবি database-এর BLOB-এ রাখবেন, না object storage-এ? (মাঝারি)

শক্তিশালী উত্তর: Object storage-এ, আর database-এ শুধু metadata (key, আকার, মালিক, checksum). কারণ: ছবি বড় আর বদলায় না, database-এর buffer pool আর backup ভারী করে, আর object store সস্তায় প্রায় সীমাহীন বাড়ে। Upload-এ client সরাসরি store-এ যায় presigned URL দিয়ে — অল্প মেয়াদ, একটি key, একটি কাজ — app সার্ভার বিপুল byte বইতে বাধ্য নয়। পড়া যায় CDN দিয়ে। Store-এর ভেতরে দামের খেলা: ৩ কপি মানে ৩ গুণ জায়গা, RS(6,3) erasure coding-এ ১.৫ গুণ আর যেকোনো ৩টি টুকরো হারানো সয় — কিন্তু মেরামতে বেশি পড়া।

ফলো-আপ:

  • “Upload সফল, কিন্তু metadata লেখার আগে app crash?” → orphan object; store-এর completion event থেকে metadata লেখা, আর lifecycle rule দিয়ে অসম্পূর্ণ upload মোছা।
  • “ছবি নয়, ভিডিও হলে?” → খরচের কেন্দ্র সরে যায় বিতরণে (egress); পর্ব ৫৯-এর অনুমানে যত byte ঢোকে, তার প্রায় ৪৬৯ গুণ বেরোয় — তাই CDN আর adaptive bitrate.

৬ · Messaging, stream আর async — queue বনাম log, delivery, ক্রম আর সময়

রিভিশন: পর্ব ৩১ · Message queue, পর্ব ৩২ · Pub/sub, পর্ব ৩৩ · Log streaming, পর্ব ৩৪ · Delivery semantics, পর্ব ৩৫ · Event sourcing আর CQRS, পর্ব ৩৬ · Batch আর stream, পর্ব ৩৭ · Job আর workflow, আর পর্ব ৫৫, পর্ব ৫৬, পর্ব ৫৭-এর case study

প্র ৩১শুরু · অর্ডার হলে ইমেইল পাঠাতে সরাসরি call না message queue? Queue কখন ক্ষতি করে? (সহজ)

শক্তিশালী উত্তর: ইমেইল ধীর আর বাইরের সেবার ওপর নির্ভরশীল; request path-এ রাখলে ব্যবহারকারী অপেক্ষা করেন আর ইমেইল-সেবার ত্রুটি অর্ডারের ত্রুটি হয়ে যায়। Queue-তে কাজ রেখে উত্তর দিলে দুই পক্ষ আলাদা গতিতে চলে, ভিড় সমান হয় (load levelling) — ৪০/সেকেন্ড ক্ষমতায় ২০ সেকেন্ড ধরে ৮০/সেকেন্ড এলে প্রায় ৮০০টি জমে, পরে সরে। ক্ষতি যেখানে: ব্যবহারকারীর এখনই উত্তর লাগে (balance দেখা), ক্রম আর duplicate সামলানোর দায় আসে, আর debugging কঠিন হয়। Queue আসলে at-least-once দেয়, তাই consumer idempotent.

ফলো-আপ:

  • “একটি বার্তা বারবার consumer-কে crash করাচ্ছে?” → poison message: backoff-সহ কয়েকবার চেষ্টা, তারপর dead letter queue — আর DLQ-তে alert, নইলে সেটি কবরস্থান।
  • “Consumer বাড়াবেন কিসের ভিত্তিতে?” → CPU নয়; queue depth আর সবচেয়ে পুরোনো বার্তার বয়স।
প্র ৩২মাঝারি · RabbitMQ-ধাঁচের queue আর Kafka-ধাঁচের log — পার্থক্য কী, কখন কোনটি? (মাঝারি)

শক্তিশালী উত্তর: Queue-তে বার্তা ack হলে মুছে যায়; প্রতিটি বার্তা একজন কর্মী নেন — কাজ ভাগের জন্য আদর্শ, প্রতি বার্তায় আলাদা retry আর delay সহজ। Log-এ record মোছে না, প্রতিটির একটি offset; প্রতিটি consumer group নিজের offset রাখে — একই ঘটনা অনেক দল আলাদাভাবে পড়ে, আর পুরোনো offset থেকে আবার পড়া (replay) যায়। দাম: log-এ ক্রম শুধু partition-এর ভেতরে, আর একটি ধীর বা বিষাক্ত record পুরো partition আটকে দিতে পারে। তাই কাজ ভাগে queue, ঘটনার ধারা আর একাধিক পাঠকে log.

ফলো-আপ:

  • “Pub/sub-এ ১০টি subscription থাকলে খরচ?” → গুণফল: সেকেন্ডে E event × N subscription = E·N delivery.
  • “Retention কত?” → replay-র প্রয়োজন আর disk-এর দাম; key ধরে শেষ মান রাখতে log compaction.
প্র ৩৩মাঝারি · “আমাদের broker exactly-once delivery দেয়” — এই দাবিতে কী প্রশ্ন করবেন? (মাঝারি)

শক্তিশালী উত্তর: Network-এ timeout মানে “জানি না” — বার্তা হারাল, নাকি কাজ হয়ে ack হারাল, প্রেরক আলাদা করতে পারে না। তাই পাঠানোর স্তরে exactly-once সম্ভব নয়; সম্ভব effectively-once = at-least-once delivery + idempotent প্রক্রিয়াকরণ। শর্ত: কাজের ফল আর “এটি দেখা হয়েছে” চিহ্ন (inbox সারি বা offset) একই local transaction-এ। Kafka-ধাঁচের idempotent producer আর transaction broker-এর ভেতরে এটি দেয়; কিন্তু শিকলের বাইরের কড়া — database, ইমেইল, payment provider — নিজের idempotency key ছাড়া সুরক্ষিত নয়। তাই প্রশ্ন: “শেষ side effect পর্যন্ত কি?”

ফলো-আপ:

  • “Dedup store কত বড়?” → হার × window × প্রতি entry-র byte; সেকেন্ডে ১০ হাজার, ২৪ ঘণ্টা, ৪০ byte ধরলে প্রায় ৩৪.৫৬ GB — তাই প্রায়ই per-producer sequence number.
  • “Offset কখন commit?” → কাজের পরে; আগে করলে crash-এ বার্তা হারায়।
প্র ৩৪অভিজ্ঞ · প্রতিটি ব্যবহারকারীর ঘটনা ক্রমে প্রক্রিয়া করতে হবে, অথচ throughput-ও লাগবে। কীভাবে? (কঠিন)

শক্তিশালী উত্তর: সারা বিশ্বের এক ক্রম লাগে না — লাগে প্রতি key-তে ক্রম। User ID-কে partition key দিন: একই ব্যবহারকারীর সব record একই partition-এ, সেখানে ক্রম রক্ষা; আলাদা ব্যবহারকারী আলাদা partition-এ সমান্তরালে। সমান্তরালতার ছাদ partition-এর সংখ্যা: একটি group-এ partition-এর চেয়ে বেশি consumer অলস বসে থাকেন, তাই partition আগেই যথেষ্ট রাখুন। ঝুঁকি: একজন খুব সক্রিয় ব্যবহারকারী একটি partition-কে গরম করেন, আর একটি বিষাক্ত record সেই partition-এর পেছনের সবাইকে আটকায় — তাকে আলাদা retry পথে সরাতে হয়, তবে তখন সেই key-এর ক্রম ভাঙে কি না ভাবতে হয়।

ফলো-আপ:

  • “Partition সংখ্যা পরে বাড়ালে?” → key থেকে partition-এর হিসাব বদলায়, একই key-এর পুরোনো আর নতুন record দুই partition-এ — বদলের মুহূর্তে ক্রম ভাঙতে পারে।
  • “Consumer-এর ভেতরে thread pool দিলে?” → partition-এর ক্রম ভাঙে, যদি না key ধরে thread ভাগ করেন।
প্র ৩৫অভিজ্ঞ · Event sourcing আর CQRS কখন নেবেন — আর কখন একেবারেই নয়? (কঠিন)

শক্তিশালী উত্তর: Event sourcing শুধু বর্তমান অবস্থা নয়, প্রতিটি ঘটনা রাখে — মুদি দোকানের খাতার পুরো পাতার মতো, শুধু শেষ যোগফল নয়। লাভ: পূর্ণ audit, অতীতের যেকোনো মুহূর্তের অবস্থা, আর নতুন read model পরে বানানো। CQRS লেখা আর পড়ার মডেল আলাদা করে; read model একটু পিছিয়ে থাকে, তাই read-your-writes আলাদা করে সামলাতে হয়। দাম: event-এর schema চিরকাল বহন, replay-র সময় (snapshot লাগে), “মুছে ফেলার অধিকার”-এর কঠিন প্রশ্ন, আর দলের শেখার খরচ। টাকার খাতা বা নিয়ন্ত্রক-চাহিদার ডোমেইনে মানানসই; সাধারণ CRUD অংশে প্রায়ই over-engineering. দুটি আলাদা — একটি অন্যটি ছাড়াই সম্ভব।

ফলো-আপ:

  • “একই stream-এ দুজন একসাথে লিখলে?” → expected version: “version ৪ দেখে লিখছি” — মাঝে কেউ লিখলে conflict, আবার পড়ে চেষ্টা।
প্র ৩৬মাঝারি · প্রতি মিনিটে কতবার অর্ডার হলো — stream-এ গুনছেন, কিন্তু মোবাইল offline থেকে দেরিতে ঘটনা পাঠায়। কোন সময় ধরে গুনবেন? (মাঝারি)

শক্তিশালী উত্তর: ঘটনা কখন ঘটেছে (event time), processor কখন দেখল তা নয় (processing time). Processing time ধরলে দেরিতে আসা ঘটনা ভুল মিনিটে পড়ে — পর্ব ৩৬-এর simulator-এ প্রতি মিনিটের সঠিক ৬-এর জায়গায় এল ৪, ৫, ৬, ৭, ২। কিন্তু event time-এ প্রশ্ন জাগে: window কখন বন্ধ? Watermark হলো processor-এর অনুমান — “এর চেয়ে পুরোনো ঘটনা আর আসবে না।” Trade-off: আগে বন্ধ করলে দ্রুত ফল, কিন্তু দেরির ঘটনা বাদ বা সংশোধন; দেরিতে বন্ধ করলে ঠিক ফল, কিন্তু দেরি আর বেশি state. দেরির ঘটনা allowed lateness পর্যন্ত ফল সংশোধন করে, তারপর আলাদা পথে।

ফলো-আপ:

  • “Batch-এ এই সমস্যা নেই?” → কম, কারণ গতকালের সব ডেটা এসে গেছে বলে ধরা হয় — দাম পুরো একদিনের দেরি।
  • “রাত ১২টায় ১০ হাজার tenant-এর রিপোর্ট job?” → এক সেকেন্ডে ১০ হাজার job-এর ঢল; tenant-এর hash দিয়ে এক ঘণ্টায় ছড়ালে সেকেন্ডে কয়েকটি মাত্র।

৭ · Distributed systems-এর তত্ত্ব — CAP, consistency, quorum, consensus, ঘড়ি, lock আর CRDT

রিভিশন: পর্ব ৩৮ · Partial failure, পর্ব ৩৯ · সময় আর ক্রম, পর্ব ৪০ · CAP আর consistency, পর্ব ৪১ · Quorum, পর্ব ৪২ · Raft, পর্ব ৪৩ · Lock আর fencing, পর্ব ৪৪ · Gossip, পর্ব ৪৫ · Bloom আর HLL, পর্ব ৪৬ · CRDT, আর পর্ব ৬১ · ক্যাপস্টোন KV store

প্র ৩৭শুরু · একটি call-এ timeout হলো। এ থেকে আপনি নিশ্চিতভাবে কী জানলেন? (সহজ)

শক্তিশালী উত্তর: প্রায় কিছুই না — timeout মানে “জানি না”। তিনটি ঘটনা বাইরে থেকে হুবহু এক: অনুরোধ পৌঁছায়নি, কাজ হয়ে উত্তর হারিয়েছে, বা node শুধু ধীর। এটাই partial failure: এক যন্ত্রে “সব বা কিছুই না”, অনেক যন্ত্রে “কিছু, আর অজানা”। তাই নকশার তিনটি অভ্যাস: retry নিরাপদ করতে idempotency, “মরেছে” সিদ্ধান্তকে একক node-এর হাতে না রেখে quorum বা consensus-এ, আর পুরোনো ধারককে fencing দিয়ে আটকানো। Timeout-এর মান নিজেই trade-off: ছোট হলে সুস্থ node-কে মৃত ভাবা, বড় হলে সত্যিকারের মৃত্যু ধরা পড়ে দেরিতে।

ফলো-আপ:

  • “শত শত node-এ কে বেঁচে আছে জানবেন কীভাবে?” → সবাই সবাইকে heartbeat দিলে বার্তা n(n − ১); gossip বা SWIM-এ প্রতি সদস্যের ভার n-নিরপেক্ষ, খবর ছড়ায় প্রায় log n রাউন্ডে।
প্র ৩৮অভিজ্ঞ · Redis-এ TTL-সহ একটি lock নিয়ে শুধু একজন worker যেন স্টক কমায়। এতে কী ভুল হতে পারে? (কঠিন)

শক্তিশালী উত্তর: আগে প্রশ্ন: lock কীসের জন্য? Efficiency lock ব্যর্থ হলে বাড়তি কাজ মাত্র; correctness lock ব্যর্থ হলে টাকা বা স্টক ভুল। বিপদ থেমে থাকা ধারক: worker A lock পেল, তারপর GC বা VM-এর বিরতিতে থেমে রইল, lease ফুরাল, B lock পেয়ে লিখল, A জেগে উঠে না জেনেই লিখল — দুজন ধারক। Lock service একে থামাতে পারে না, কারণ A নিজেই জানে না সে থেমে ছিল। প্রতিকার fencing token: প্রতিবার lock-এর সাথে বাড়তে থাকা নম্বর (৩৩, ৩৪), আর storage ছোট নম্বরের লেখা প্রত্যাখ্যান করে। অনেক ক্ষেত্রে lock-ই লাগে না: শর্তসহ লেখা (CAS বা version), বা প্রতিটি key-এর একজন লেখক।

দুর্বল উত্তর দেখতে যেমন: “TTL বড় করে দেব।” — বিরতি যেকোনো দৈর্ঘ্যের হতে পারে।

ফলো-আপ:

  • “Storage যদি token যাচাই করতে না পারে?” → তখন lock একা সঠিকতার নিশ্চয়তা দেয় না; শর্তসহ লেখা বা ভিন্ন নকশা লাগে।
  • “একজন চালককে দুই যাত্রীর কাছে পাঠানো ঠেকাবেন কীভাবে?” → চালকের অবস্থা বদলান শুধু compare-and-set দিয়ে; পর্ব ৫৮-এর simulator-এ সাধারণ “আগে পড়া, তারপর লেখা”-তে ৩৬% ক্ষেত্রে double offer, CAS-এ শূন্য।
প্র ৩৯মাঝারি · CAP theorem নিজের ভাষায় বলুন। “আমাদের database CA” — এই দাবির সমস্যা কী? (মাঝারি)

শক্তিশালী উত্তর: Network ভাগ হলে একটি সিস্টেম একসাথে linearizable থাকতে আর প্রতিটি চালু node থেকে উত্তর দিতে পারে না — Brewer-এর অনুমান (২০০০), Gilbert আর Lynch-এর প্রমাণ (২০০২)। Partition বাছাইয়ের জিনিস নয়, network ভাঙবেই; বাছাই শুধু তখন C না A. তাই একাধিক যন্ত্রের সিস্টেমকে “CA” বলা অর্থহীন। আর CAP-এর A মানে “উঁচু uptime” নয় — majority-র দিক চালু রাখা CP সিস্টেমও প্রায় সবসময় সেবা দেয়। বেশিরভাগ দিনের প্রশ্ন PACELC-এ (Abadi, ২০১২): partition না থাকলেও শক্ত consistency মানে প্রতিটি কাজে অন্য replica-র সাথে round trip, অর্থাৎ latency.

ফলো-আপ:

  • “ACID-এর C আর CAP-এর C কি এক?” → না; প্রথমটি অ্যাপের নিয়ম রক্ষা, দ্বিতীয়টি linearizability — পর্ব ২৪ আর ৪০।
  • “একটি সিস্টেমে কি দুই বাছাই একসাথে?” → হ্যাঁ, feature ধরে: শেষ সিট আর টাকা কাটা linearizable; প্রোফাইল ছবি eventual, সাথে read-your-writes; like counter eventual আর CRDT.
  • “Serializable আর linearizable কি এক?” → না; serializability একাধিক object-এর transaction যেন কোনো এক ক্রমে চলেছে — বাস্তব সময় মানতে বাধ্য নয়; linearizability একটি object-এর, বাস্তব সময় মেনে। দুটি একসাথে হলে strict serializability.
প্র ৪০মাঝারি · N = ৩ replica-য় W = ২, R = ২. কেন কাজ করে, কতগুলো বিকলতা সয়, আর তবু পুরোনো মান আসতে পারে কেন? (মাঝারি)

শক্তিশালী উত্তর: R + W > N হলে যেকোনো লেখার দল আর যেকোনো পড়ার দল অন্তত W + R − N = ১টি replica-তে মেলে — পড়া অন্তত একটি নতুন কপি ছোঁয় (quorum intersection). একটি replica বিকল হলেও পড়া আর লেখা দুটিই চলে। কিন্তু quorum মানেই linearizable নয়: চলমান লেখা কিছু replica-তে পৌঁছেছে, ব্যর্থ আংশিক লেখা থেকে গেছে, sloppy quorum অন্য node-এ লিখেছে, বা একসাথে দুটি লেখায় LWW একটি ফেলেছে — overlap থাকলেও পুরোনো বা হারানো মান আসতে পারে। নিচের ছোট script সব সম্ভাব্য দল গুনে overlap যাচাই করে।

ফলো-আপ:

  • “লেখা দ্রুত চাই — W = ১?” → তখন R = N লাগবে overlap-এর জন্য, আর একটি replica বন্ধ হলেই পড়া আটকায়।
  • “Replica-গুলো মিলবে কীভাবে?” → hinted handoff, read repair আর Merkle tree দিয়ে anti-entropy.
// Quorum check by brute force: for N replicas, list EVERY possible write set of size W and
// read set of size R, and find the smallest overlap. Also: how many replicas may be down
// while writes (N - W) and reads (N - R) still succeed.
function subsets(n, k, start = 0, cur = [], out = []) {
  if (cur.length === k) { out.push(new Set(cur)); return out; }
  for (let i = start; i < n; i++) subsets(n, k, i + 1, [...cur, i], out);
  return out;
}
function minOverlap(N, W, R) {
  let min = Infinity;
  for (const w of subsets(N, W)) for (const r of subsets(N, R)) {
    let common = 0; for (const x of r) if (w.has(x)) common++;
    min = Math.min(min, common);
  }
  return min;
}
console.log(" N  W  R   R+W>N?   min overlap   writes survive   reads survive");
for (const [N, W, R] of [[3, 2, 2], [3, 3, 1], [3, 1, 1], [5, 3, 3], [5, 4, 2], [5, 2, 2]]) {
  const ok = R + W > N ? "yes" : "no";
  console.log(String(N).padStart(2) + String(W).padStart(3) + String(R).padStart(3) + ok.padStart(9) +
    String(minOverlap(N, W, R)).padStart(14) + (`${N - W} down`).padStart(17) + (`${N - R} down`).padStart(16));
}

আউটপুট:

 N  W  R   R+W>N?   min overlap   writes survive   reads survive
 3  2  2      yes             1           1 down          1 down
 3  3  1      yes             1           0 down          2 down
 3  1  1       no             0           2 down          2 down
 5  3  3      yes             1           2 down          2 down
 5  4  2      yes             1           1 down          3 down
 5  2  2       no             0           3 down          3 down

R + W > N যেখানে “yes”, সেখানে প্রতিটি সম্ভাব্য জোড়ায় অন্তত ১টি replica মেলে; “no” হলে এমন জোড়া আছে যারা একটিও replica ভাগ করে না — তখন পড়া একটিও নতুন কপি না ছুঁয়ে পুরোনো মান দিতে পারে। শেষ দুই কলামে দাম: (৩, ৩, ১)-এ পড়া দ্রুত আর ২টি বিকলতা সয়, কিন্তু একটি replica বন্ধ হলেই লেখা থামে; (৫, ৩, ৩)-এ দুই দিকেই ২টি। তাই উত্তরটি হওয়া উচিত “কোন কাজ বেশি, আর কোনটির থামা বেশি ক্ষতির” — একটি সংখ্যা নয়।

প্র ৪১অভিজ্ঞ · Raft cluster-এ ৩টির বদলে ৪টি সার্ভার রাখলে কি বেশি নিরাপদ? (কঠিন)

শক্তিশালী উত্তর: না। Raft-এ প্রতিটি সিদ্ধান্তে majority লাগে: ২f + ১টি সার্ভার f-টি crash সয়। ৩-এ majority ২, সয় ১; ৪-এ majority ৩, সয় তবুও ১; ৫-এ majority ৩, সয় ২। জোড় সংখ্যায় লাভ নেই, বরং প্রতিটি commit-এ বেশি জনের অপেক্ষা। কেন majority: যেকোনো দুটি majority অন্তত একজনে মেলে, তাই নতুন leader পুরোনো commit-এর খবর পায়ই — ভোট পায় কেবল সেই candidate, যার log অন্তত ভোটদাতার মতো হালনাগাদ। দাম: প্রতিটি commit-এ majority-র সাথে একটি round trip — region পেরোলে দশ থেকে শত ms. তাই consensus রাখা হয় metadata, leader election আর config-এর মতো ছোট কিন্তু জরুরি ডেটায়।

ফলো-আপ:

  • “Leader থেকে পড়লেই কি সর্বশেষ মান?” → না-ও হতে পারে; সে নিজে জানে না নতুন leader হয়ে গেছে কি না — read index বা lease লাগে।
  • “Paxos-এর সাথে সম্পর্ক?” → একই সমস্যার পুরোনো সমাধান; Raft (২০১৪) বোঝার সুবিধার জন্য নকশা করা।
প্র ৪২মাঝারি · দুই region-এ একই প্রোফাইল বদলাল; timestamp দেখে পরেরটি রাখি (last-write-wins). এতে সমস্যা কী? (মাঝারি)

শক্তিশালী উত্তর: আলাদা যন্ত্রের ঘড়ি আলাদা চলে — ২০ ppm সরলে দিনে প্রায় ১.৭ সেকেন্ড — আর NTP-র পরে লাফায়। ঘড়ির পার্থক্যের চেয়ে কাছাকাছি দুটি লেখায় “পরের” লেখাটি ছোট timestamp পেতে পারে, আর LWW তা নিঃশব্দে ফেলে দেয় — কোনো error নেই। Lamport clock কারণ-কার্যের ক্রম রাখে, কিন্তু দুটি ঘটনা একসাথে (concurrent) কি না বলতে পারে না; vector clock পারে — তখন দুটি সংস্করণই (sibling) রেখে মেলানো যায়। কখন LWW চলে: মান পুরোপুরি বদলে দেওয়া হয় আর মাঝে মাঝে একটি হারানো সহনীয়, যেমন “শেষ দেখা সময়”।

ফলো-আপ:

  • “সময়কাল মাপতে কোন ঘড়ি?” → monotonic clock; wall clock পেছাতে পারে।
  • “সবচেয়ে সস্তা প্রতিকার?” → conflict এড়ানো — প্রতিটি ব্যবহারকারীর লেখা তাঁর “বাড়ির” region-এ।
প্র ৪৩অভিজ্ঞ · Offline-এ চলা একটি অ্যাপে CRDT কখন ঠিক উত্তর, আর কখন CRDT দিয়েও হবে না? (কঠিন)

শক্তিশালী উত্তর: CRDT-র merge commutative, associative আর idempotent — যেকোনো ক্রমে, যতবার খুশি মেলালেও একই ফল, coordination ছাড়াই (strong eventual consistency). Counter (G-Counter, PN-Counter), set (OR-Set — add-wins), আর collaborative লেখায় চমৎকার। দাম: metadata আর tombstone জমে, আর merge-এর অর্থ সবসময় ব্যবসার অর্থ নয়। যা পারে না: “ব্যালান্স শূন্যের নিচে নয়” বা “সিট একজনেরই” — এমন নিয়ম দুই পক্ষের আলাদা সিদ্ধান্তে ভাঙতে পারে; দুই offline ফোন একই শেষ টাকা খরচ করলে merge তা ফেরাতে পারে না। সেখানে coordination লাগবেই, বা আগে থেকে ভাগ করা কোটা।

ফলো-আপ:

  • “Shopping cart-এ union-এ মেলালে কী হয়?” → মুছে ফেলা জিনিস ফিরে আসে — Dynamo-র cart-এর পরিচিত উদাহরণ; OR-Set তা সামলায়।
প্র ৪৪মাঝারি · ১০ কোটি username-এর “নেই” প্রশ্ন দ্রুত দিতে Bloom filter দেবেন। কত memory, আর ভুল কোন দিকে? (মাঝারি)

শক্তিশালী উত্তর: Bloom filter বলে “নিশ্চিত নেই” বা “হয়তো আছে”; ভুল শুধু এক দিকে — false positive. ১% ভুলে প্রতি key-এ প্রায় ৯.৬ bit আর ৭টি hash: ১০ কোটি × ৯.৫৮৫ bit ≈ ১২০ MB; ০.১%-এ প্রায় ১৪.৪ bit আর ১০টি hash. Trade-off কে দাম দেয় তাতে: “হয়তো আছে” এলে database-এ নিশ্চিত হতে হয় — সামান্য বাড়তি কাজ, তাই এখানে মানানসই। কিন্তু চূড়ান্ত সিদ্ধান্তে নয় — “নামটি নেওয়া হয়েছে” বলে কাউকে ফিরিয়ে দেওয়া ভুল হবে। সাধারণ Bloom থেকে মোছা যায় না; লাগলে counting বা cuckoo filter.

ফলো-আপ:

  • “আলাদা দর্শক কতজন, প্রায় কম memory-তে?” → HyperLogLog: ১৬,৩৮৪টি register, প্রায় ১২ KB, ভুল প্রায় ০.৮১%; দুই sketch ঘর ধরে max নিলে মিলিত গণনা।
  • “সবচেয়ে জনপ্রিয় URL?” → count-min sketch আর একটি ছোট heap — কখনো কম দেখায় না, বাড়তি দেখাতে পারে।

৮ · Reliability আর operations — resilience, rate limiting, SLO, DR, deployment আর নিরাপত্তা

রিভিশন: পর্ব ৪৭ · Microservices, পর্ব ৪৮ · Resilience, পর্ব ৪৯ · Rate limiting, পর্ব ৫০ · Observability, পর্ব ৫১ · Disaster recovery, পর্ব ৫২ · নিরাপত্তা, পর্ব ৫৩ · Deployment

প্র ৪৫শুরু · নতুন একটি পণ্য শুরু করছেন। Monolith না microservices? (সহজ)

শক্তিশালী উত্তর: সাধারণত modular monolith: একটি deployable, ভেতরে পরিষ্কার module-সীমানা। Microservices দেয় দলের স্বাধীনতা, আলাদা deploy আর আলাদা scaling — বিনিময়ে network call, ছড়ানো ডেটা, distributed transaction, বেশি operations আর কঠিন debugging. লাভটি মূলত সংগঠনের: অনেক দল একই কোডে একে অপরকে আটকালে। ছোট দলে সেই সমস্যা নেই, দাম আছে। পরে ভাঙতে হলে strangler fig — একটি একটি feature কেটে আলাদা করা।

দুর্বল উত্তর দেখতে যেমন: “Microservices আধুনিক আর scalable, তাই শুরু থেকেই।”

ফলো-আপ:

  • “Distributed monolith চিনবেন কীভাবে?” → কয়েকটি সেবা একই টেবিলে লেখে, একটি অনুরোধে অনেক call, আর সবাইকে একসাথে deploy করতে হয়।
  • “সেবার সীমানা কীসে?” → ব্যবসার ভাষায় — bounded context আর ডেটার মালিকানা; টেবিল বা কোডের স্তর ধরে নয়।
প্র ৪৬মাঝারি · Dependency ব্যর্থ হলে retry করবেন — কতবার, কতক্ষণ পরপর, আর কোন স্তরে? (মাঝারি)

শক্তিশালী উত্তর: শুধু ক্ষণিকের ত্রুটিতে (timeout, 503) আর শুধু idempotent কাজে; ভুল ইনপুটে নয়। মাঝে exponential backoff আর full jitter — jitter না থাকলে সব client একই মুহূর্তে ফেরে; পর্ব ৪৮-এর simulator-এ ১০০টি client-এর ভিড় সরতে jitter ছাড়া ৪৬২ সেকেন্ড, full jitter-এ ৮.৮. স্তরে স্তরে retry গুণ হয়: তিন স্তরের প্রত্যেকে ৩ বার চেষ্টা করলে সবচেয়ে নিচের সেবা দেখে ৩ × ৩ × ৩ = ২৭টি — ঠিক যখন সে আগেই কষ্টে। তাই retry একটি স্তরে, আর একটি retry budget — যেমন মোট অনুরোধের বড়জোর ১০% retry.

ফলো-আপ:

  • “Retry-র মোট সময়ের সীমা?” → পুরো অনুরোধের deadline, যা নিচের সব call-এ পৌঁছায়; deadline পেরোলে retry অর্থহীন।
প্র ৪৭মাঝারি · Timeout, circuit breaker আর bulkhead — তিনটির কাজ আলাদা কোথায়? (মাঝারি)

শক্তিশালী উত্তর: ধীর dependency মৃতের চেয়েও খারাপ: মৃত সেবা ১ ms-এ “না” বলে, ধীর সেবা প্রতিটি thread কয়েক সেকেন্ড আটকে রাখে, আর Little-এর সূত্রে thread ফুরিয়ে সুস্থ কাজও থামে — cascading failure. Timeout একটি call-এর অপেক্ষা সীমিত করে; ঊর্ধ্বসীমাও হিসাব করা যায় — ২০০ thread-এর pool আর সেকেন্ডে ১০০ call হলে গড় অপেক্ষা ২ সেকেন্ড ছাড়ালেই pool ভরে। Circuit breaker বারবার ব্যর্থ dependency-কে কিছুক্ষণ ডাকাই বন্ধ করে (closed → open → half-open), দ্রুত “না” দেয়। Bulkhead প্রতিটি dependency-কে আলাদা pool দেয় — একটি ধীর হলেও বাকিরা চলে। তিনটি একসাথে লাগে, আর সাথে একটি fallback.

ফলো-আপ:

  • “Health check-এ database-ও দেখবেন?” → সাবধানে; database ধীর হলে সব instance একসাথে “অসুস্থ” হয়ে বাদ পড়তে পারে — liveness অগভীর রাখা।
প্র ৪৮মাঝারি · “মিনিটে ১০০ অনুরোধ” সীমা দেবেন। Fixed window, sliding window না token bucket? (মাঝারি)

শক্তিশালী উত্তর: Fixed window সবচেয়ে সস্তা — একটি counter — কিন্তু ঘড়ির সীমানায় ২ সেকেন্ডে ২০০টি ছাড়ে। Sliding window counter দুটি সংখ্যায় কাছাকাছি অনুমান দেয়। Token bucket দুটি knob দেয়: গড় হার r আর একসাথে সর্বোচ্চ b; যেকোনো T সেকেন্ডে বড়জোর b + r·T — burst ইচ্ছা করে অনুমোদিত, কিন্তু সীমিত। বাছাই নির্ভর করে burst কতটা সহনীয় তাতে। Distributed হলে “পড়ে তারপর লেখা” counter-এ সীমা ফুটো হয়; atomic INCR বা script লাগে। আর কার হিসাব: user, API key বা tenant — IP শুধু মোটা দাগে, কারণ CGNAT-এর পেছনে বহু মানুষ একই ঠিকানায়। নিচের script সীমানার burst মেপে দেখায়।

ফলো-আপ:

  • “সীমা পেরোলে কী উত্তর?” → 429 আর Retry-After; client-এ backoff আর jitter.
  • “Rate limit আর load shedding কি এক?” → না; rate limit নীতি — সার্ভার অলস থাকলেও; shedding ভিড়ে সবাইকে বাঁচানোর জরুরি ব্যবস্থা।
// Limit "100 requests per minute". A client sends 1 request every 10 ms from t = 59 s to t = 61 s:
// 200 attempts in 2 seconds, right across the minute boundary at 60 s. How many does each
// limiter admit, second by second? Times are integer milliseconds, so the output is exact.
const LIMIT = 100, WIN = 60000;
function fixedWindow() {
  const count = new Map();
  return t => { const w = Math.floor(t / WIN), c = count.get(w) || 0;
    if (c < LIMIT) { count.set(w, c + 1); return true; } return false; };
}
function slidingCounter() {            // estimate = prev window * overlap share + current window
  const count = new Map();
  return t => { const w = Math.floor(t / WIN), share = 1 - (t % WIN) / WIN;
    const est = (count.get(w - 1) || 0) * share + (count.get(w) || 0);
    if (est < LIMIT) { count.set(w, (count.get(w) || 0) + 1); return true; } return false; };
}
function tokenBucket(rate, burst) {    // rate tokens per ms, bucket starts full
  let tokens = burst, last = 0;
  return t => { tokens = Math.min(burst, tokens + (t - last) * rate); last = t;
    if (tokens >= 1) { tokens -= 1; return true; } return false; };
}
const limiters = { "fixed window": fixedWindow(), "sliding counter": slidingCounter(),
                   "token bucket": tokenBucket(LIMIT / WIN, LIMIT) };
console.log("limiter          59-60 s   60-61 s   total in 2 s");
for (const [name, allow] of Object.entries(limiters)) {
  let a = 0, b = 0;
  for (let t = 59000; t < 61000; t += 10) if (allow(t)) { if (t < 60000) a++; else b++; }
  console.log(name.padEnd(16) + String(a).padStart(8) + String(b).padStart(10) + String(a + b).padStart(15));
}

আউটপুট:

limiter          59-60 s   60-61 s   total in 2 s
fixed window         100       100            200
sliding counter      100         2            102
token bucket         100         3            103

একই ২ সেকেন্ডের ঝাঁক, তিন ফল। Fixed window ৫৯–৬০ সেকেন্ডে পুরোনো মিনিটের ১০০টি দেয়, ৬০ সেকেন্ডে counter শূন্য হতেই আরও ১০০ — ২ সেকেন্ডে ২০০, ঘোষিত হারের দ্বিগুণ। Sliding counter আগের মিনিটের ১০০-কে প্রায় পুরো ওজনে গোনে, তাই নতুন মিনিটের শুরুতে মাত্র ২টি। Token bucket ভরা bucket-এর ১০০টি দেয়, তারপর হার অনুযায়ী (১০০ ÷ ৬০ ≈ ১.৬৭/সেকেন্ড) আর ৩টি — সূত্র b + r·T = ১০০ + ১.৬৭ × ২ ≈ ১০৩-এর সাথে মেলে। প্রশ্ন তাই “কোনটি সঠিক” নয়: শুরুর এই ১০০-র burst আপনার backend সইতে পারে কি না।

প্র ৪৯অভিজ্ঞ · ৩০ দিনে ৯৯.৯% SLO. Error budget কত, আর alert দেবেন কিসের ভিত্তিতে? (কঠিন)

শক্তিশালী উত্তর: Error budget = ১ − SLO = ০.১%: সময়ে ৩০ × ২৪ × ৬০ × ০.০০১ = ৪৩.২ মিনিট, বা সেকেন্ডে ১,০০০ অনুরোধে ২৫,৯২,০০০টি ব্যর্থ অনুরোধ। Alert ব্যর্থতার হারে নয়, budget খরচের গতিতে — burn rate. Burn rate ১৪.৪ মানে এক ঘণ্টায় মাসের budget-এর ১৪.৪ ÷ ৭২০ = ২% শেষ, সেই গতিতে পুরো budget ৫০ ঘণ্টায়। একটি প্রচলিত ধাঁচ: ১ ঘণ্টা আর ৫ মিনিট — দুই জানালাতেই ১৪.৪ পেরোলে page; লম্বা জানালা ভুল alarm কমায়, ছোটটি সমস্যা থামলে alert দ্রুত বন্ধ করে। Budget শেষ হলে নীতি: নতুন feature-এর বদলে নির্ভরযোগ্যতার কাজ।

দুর্বল উত্তর দেখতে যেমন: “CPU ৮০% ছাড়ালে page দেব।” — কারণ ধরে alert; ব্যবহারকারী কষ্ট পাচ্ছেন কি না বলে না।

ফলো-আপ:

  • “SLI কী মাপবেন?” → ব্যবহারকারীর চোখে: সফল অনুরোধের অনুপাত, আর লক্ষ্যের চেয়ে দ্রুত অনুরোধের অনুপাত — load balancer বা client-এর কাছ থেকে।
  • “১০০% SLO কেন নয়?” → অসম্ভব আর অসীম দামি; budget-ই deploy আর পরীক্ষার জায়গা দেয়।
প্র ৫০মাঝারি · “তিনটি replica আছে, তাই আলাদা backup লাগবে না।” কী বলবেন? (মাঝারি)

শক্তিশালী উত্তর: Replica যন্ত্র বা zone হারানো থেকে বাঁচায়, কিন্তু ভুল DELETE, নীরবে নষ্ট ডেটা বা ransomware সেকেন্ডেই সব replica-তে পৌঁছায় — তখন লাগে অতীতে ফেরার backup. দুটি সংখ্যা ব্যবসা ঠিক করে: RPO — কত সময়ের ডেটা হারানো চলে; RTO — কতক্ষণ বন্ধ থাকা চলে। Point-in-time recovery (snapshot + WAL) RPO কমায়; warm standby বা active-active RTO কমায় — খরচ বাড়িয়ে। নিয়ম: 3-2-1, আলাদা account-এ বদলানো যায় না এমন কপি, আর নিয়মিত restore-মহড়া — যে backup কখনো restore করে দেখেননি, তা backup নয়; মহড়াতেই আসল RTO মাপা যায়।

ফলো-আপ:

  • “Failover-এর ধাপ?” → টের পাওয়া, সিদ্ধান্ত, পুরোনো primary-কে fencing, promote, traffic সরানো (DNS-এর TTL মাথায় রেখে), পরে ধীরে failback.
প্র ৫১অভিজ্ঞ · একটি কলামের নাম বদলাতে হবে, downtime ছাড়া। Rolling, blue-green না canary — আর database-এর ধাপগুলো কী? (কঠিন)

শক্তিশালী উত্তর: কোডের জন্য: rolling-এ বাড়তি যন্ত্র কম লাগে কিন্তু দুই সংস্করণ একসাথে চলে; blue-green-এ মুহূর্তে switch আর ফেরা, দ্বিগুণ capacity-র দামে; canary অল্প traffic দিয়ে মেপে এগোয় — পর্ব ৫৩-এর simulation-এ ১৫ মিনিটে ধরা পড়া bug-এ ক্ষতি big-bang-এর মাত্র ২.৭%. কিন্তু কলামের নাম এক ধাপে বদলালে যেকোনো কৌশলেই পুরোনো কোড ভাঙে। তাই expand → contract: নতুন কলাম যোগ → দুই জায়গায় লেখা → পুরোনো ডেটা backfill → পড়া নতুন কলামে → পুরোনো লেখা বন্ধ → শেষে পুরোনো কলাম মোছা। প্রতিটি ধাপ আগের কোডের সাথে মানানসই, তাই যেকোনো ধাপে rollback চলে।

ফলো-আপ:

  • “Canary ৪০০ অনুরোধে error দ্বিগুণ — rollback?” → ছোট নমুনায় পার্থক্য প্রায়ই প্রমাণিত নয় (পর্ব ৫৩-এ z = 1.73); ২,০০০ অনুরোধে পরিষ্কার (z = 5.44) — “সব ঠিক” প্রায়ই আসলে “এখনো জানি না”।
  • “Deploy আর release আলাদা কেন?” → feature flag দিয়ে কোড আগে পৌঁছায়, ফিচার পরে খোলে — বন্ধের সুইচ এক ক্লিকে।
প্র ৫২মাঝারি · API gateway token যাচাই করছে। তাহলে ভেতরের order সেবার কি নিজে কিছু যাচাই করতে হবে? (মাঝারি)

শক্তিশালী উত্তর: হ্যাঁ। Gateway বলে “আপনি কে” (authentication); “এই অর্ডারটি কি এঁর?” (authorization) প্রতিটি অনুরোধে সেবাকেই দেখতে হয় — role থাকলেই হবে না। এর অভাব (BOLA) API-র সবচেয়ে পরিচিত ঝুঁকি: শুধু URL-এর ID বদলে অন্যের ডেটা দেখা। আরও প্রতিরক্ষা: ভেতরেও mTLS আর least privilege (zero trust); token-এ স্বাক্ষর, algorithm, iss, aud, exp — সব যাচাই; ব্রাউজার আর মোবাইলে OAuth 2.0-র authorization code flow + PKCE; সংরক্ষণে envelope encryption — প্রতিটি ফাইলের নিজের DEK, তাকে মোড়ে KMS-এর KEK; secret vault-এ, কোডে নয়।

ফলো-আপ:

  • “Password কীভাবে রাখবেন?” → ধীর, salt দেওয়া hash — Argon2id, bcrypt বা scrypt; সাথে MFA বা passkey.
  • “OAuth আর OIDC-র পার্থক্য?” → OAuth অনুমতি দেয় (access token API-র জন্য), OIDC পরিচয় জানায় (ID token client-এর জন্য)।

৯ · ভালো ইন্টারভিউয়ের আচরণ — প্রশ্ন পরিষ্কার করা, আপত্তি সামলানো, না জানা স্বীকার, আর red flag

রিভিশন: পর্ব ৬ · নকশার কাঠামো (ইন্টারভিউর ৪৫ মিনিট), পর্ব ২ · Requirement; পূর্ণ নকশায় অনুশীলন পর্ব ৬৬-এ

কারিগরি জ্ঞান সমান হলেও দুইজনের ইন্টারভিউ আলাদা শোনায় — একজন প্রশ্ন বুঝে নেন, অনুমান বলেন, আপত্তিকে তথ্য হিসেবে নেন; আরেকজন তাড়াহুড়ো করেন বা তর্কে জড়ান। এই অংশের তিনটি প্রশ্ন সেই আচরণ নিয়ে।

প্র ৫৩শুরু · ইন্টারভিউয়ার শুধু বললেন, “এখানে একটি cache যোগ করবেন?” প্রথম ৩০ সেকেন্ডে কী বলবেন? (সহজ)

শক্তিশালী উত্তর: দুই-তিনটি ধারালো প্রশ্ন, তারপর একটি স্পষ্ট অনুমান আর সিদ্ধান্ত: “পড়া আর লেখার অনুপাত কেমন? ডেটা কতক্ষণ পুরোনো থাকলে ক্ষতি নেই? — যদি পড়া অনেক বেশি আর কয়েক সেকেন্ডের staleness চলে, তাহলে হ্যাঁ: cache-aside, ছোট TTL আর লেখার পরে delete. ভুল হলে জানাবেন।” তারপর জোরে ভাবতে ভাবতে এগোনো। দশটি প্রশ্নের তালিকা নয় — সেই প্রশ্নগুলোই, যার উত্তরে সিদ্ধান্ত বদলায়। উত্তর না পেলে নিজেই যুক্তিসংগত অনুমান ধরে নিন আর মুখে বলুন।

দুর্বল উত্তর দেখতে যেমন: দুই মিনিট চুপ করে ভেবে হঠাৎ “Redis দেব” — বা উল্টোটা, প্রশ্নের পর প্রশ্ন, কোনো সিদ্ধান্ত নয়।

ফলো-আপ:

  • “আমি কোনো তথ্য দেব না, আপনি ঠিক করুন।” → “তাহলে ধরে নিচ্ছি পড়া:লেখা ১০০:১ আর ৩০ সেকেন্ডের staleness চলে” — অনুমান লিখে রেখে এগোনো, পরে বদলানো সহজ।
প্র ৫৪মাঝারি · আপনি queue প্রস্তাব করলেন; ইন্টারভিউয়ার বললেন, “আমার মনে হয় এখানে queue লাগবে না।” কীভাবে সাড়া দেবেন? (মাঝারি)

শক্তিশালী উত্তর: আপত্তিকে নতুন তথ্য হিসেবে নিন, আক্রমণ হিসেবে নয়। আগে কারণ জিজ্ঞেস করুন: “কোন দিকটা ভাবছেন — latency, না জটিলতা?” তারপর trade-off খোলাখুলি আবার মাপুন। কারণ যুক্তিসংগত হলে মেনে নিন আর বলুন কী বদলাল: “ঠিক, ব্যবহারকারী এখনই ফল চান — তাহলে sync call, timeout আর retry.” আপনার পক্ষে সংখ্যা থাকলে বিনয়ের সাথে ধরে রাখুন: “তবে peak-এ সেকেন্ডে ৮০টি আসে আর ক্ষমতা ৪০টি — queue ছাড়া ভিড়ের ২০ সেকেন্ডে প্রায় ৮০০টি অনুরোধ ব্যর্থ হবে; বিকল্প হলে consumer বাড়ানো।” অনেক সময় আপত্তিটি পরীক্ষাই — আপনি যুক্তিতে দাঁড়ান, না প্রথম চাপেই সরে যান।

দুর্বল উত্তর দেখতে যেমন: সাথে সাথে “ঠিক আছে, বাদ দিলাম” — কোনো কারণ ছাড়াই; বা “না, queue-ই লাগবে” বলে তর্ক।

প্র ৫৫অভিজ্ঞ · এমন একটি প্রশ্ন এল যার উত্তর আপনি সত্যিই জানেন না — যেমন “Spanner-এর TrueTime ঠিক কীভাবে commit-এর ক্রম নিশ্চিত করে?” কী করবেন? (কঠিন)

শক্তিশালী উত্তর: সৎভাবে সীমানা টানুন, তারপর যতটুকু জানেন সেখান থেকে যুক্তি দিন: “বিস্তারিত নিশ্চিত নই। যতটুকু জানি — Google-এর প্রকাশিত Spanner গবেষণাপত্র (২০১২) অনুযায়ী ঘড়ি একটি সময় নয়, অনিশ্চয়তার একটি সীমা দেয়; commit-এর পরে সেই অনিশ্চয়তা পেরোনো পর্যন্ত অপেক্ষা (commit-wait) করে, যাতে পরের transaction বড় timestamp পায়। এখান থেকে অনুমান করছি — অনিশ্চয়তা যত ছোট, অপেক্ষা তত কম।” কোনটি জানা আর কোনটি অনুমান, আলাদা করে বলুন, আর বলুন কীভাবে যাচাই করতেন। বানানো খুঁটিনাটি বিশ্বাস ভাঙে; সৎ “জানি না, তবে এভাবে ভাবছি” বিশ্বাস বাড়ায়।

দুর্বল উত্তর দেখতে যেমন: আত্মবিশ্বাসের সাথে বানানো সংখ্যা আর নাম — একটি follow-up-এই ধরা পড়ে।

ফলো-আপ:

  • “তাহলে ঘড়ি ছাড়া এই সমস্যা কীভাবে সমাধান করতেন?” → logical clock, বা প্রতিটি commit-এ consensus-এর ক্রম — বাস্তব সময়ের সাথে মেলানোর দামসহ (প্র ৪২)।

Red flag — যে বাক্যগুলো শুনলে অগভীর বোঝাপড়া ধরা পড়ে

নিচের বাক্যগুলো নিজে থেকে “ভুল” নয় — কোনো প্রসঙ্গে সত্যও হতে পারে। Red flag হয় তখন, যখন এগুলো প্রশ্ন, সংখ্যা আর দাম ছাড়া বলা হয়।

Red flag বাক্যকেন অগভীর শোনায়বদলে যা বলবেন
“এখানে Kafka ব্যবহার করব।” (প্রশ্নের শুরুতেই)টুল আগে, প্রয়োজন পরে“কাজটি async হতে পারে কি না, ক্রম আর replay লাগে কি না — দেখে queue না log.”
“NoSQL বেশি scalable.”Access pattern আর নিশ্চয়তার প্রশ্ন বাদ“প্রধান query আর লেখার চাপ এই; তাই key-value-তে এটা পাই, join হারাই।”
“আমরা CA সিস্টেম বানাব।”Partition বাছাইয়ের জিনিস নয়“Partition হলে এই feature-এ consistency, ওটায় availability.”
“Cache দিলেই দ্রুত হবে।”Staleness, stampede আর ঠান্ডা cache উপেক্ষিত“Hit ratio কত আশা করি, কতটা পুরোনো চলে, cache খালি হলে database টিকবে কি না।”
“Retry দিলেই নির্ভরযোগ্য।”Duplicate আর retry storm“Idempotent কাজে, backoff আর jitter-সহ, একটি স্তরে, budget-এ বাঁধা।”
“Broker exactly-once দেয়, তাই duplicate নেই।”শিকলের শেষ side effect ভুলে যাওয়া“At-least-once আর idempotent consumer — effect আর dedup-চিহ্ন এক transaction-এ।”
“গড় latency ৫০ ms, তাই ঠিক আছে।”লেজ লুকানো“p99 আর p99.9 কত, fan-out-এ লেজ কতটা বাড়ে।”
“শুরু থেকেই microservices.”দাম না দেখে ফ্যাশন“Modular monolith থেকে শুরু; দল আর deploy-এর চাপ এলে সীমানা ধরে ভাঙা।”
“Replica আছে, backup লাগবে না।”ভুল DELETE আর নষ্ট ডেটাও replicate হয়“RPO আর RTO কত; point-in-time backup আর restore-মহড়া।”
“Distributed lock নিলেই একজনই লিখবে।”থেমে থাকা ধারক“Lease-এর সাথে fencing token, বা lock ছাড়াই শর্তসহ লেখা।”
“Timestamp দেখে নতুনটা রাখব।”ঘড়ির পার্থক্যে লেখা নিঃশব্দে হারায়“Version বা vector clock, বা প্রতিটি key-এর একজন লেখক।”
“৯৯.৯৯৯% availability দেব।”সংখ্যার দাম না জানা“বছরে প্রায় ৫ মিনিট — কোন অংশে সত্যিই লাগে, আর এর খরচ কত।”
“বড় প্রতিষ্ঠান এভাবেই করে।”যাচাই-অযোগ্য দাবি, প্রসঙ্গ আলাদা“প্রকাশিত গবেষণাপত্রে এই নকশা আছে; আমাদের requirement-এ মেলে কারণ …”
মূল ধারণা

প্রতিটি “সবসময়” আর “কখনো না” একটি follow-up ডাকে। শক্তিশালী উত্তর প্রায় সবসময় শর্তসাপেক্ষ: “যদি পড়া বেশি আর staleness চলে, তাহলে…”। শর্তটি মুখে বললে ইন্টারভিউয়ার দেখেন আপনি দামটা চেনেন — আর শর্ত বদলালে সিদ্ধান্তও বদলাতে প্রস্তুত।

১০ · AI-এর যুগে — AI দিয়ে ধারণার প্রশ্নের অনুশীলন, যাচাইসহ

AI একটি ধৈর্যশীল mock interviewer হতে পারে — অবিরাম follow-up দেয়, আপনার উত্তরে ফাঁক খোঁজে। কিন্তু system design-এর প্রশ্নে এর ভুলগুলো চেনা, আর ভুলগুলো আত্মবিশ্বাসের সাথে বলা হয়:

AI-এর সাধারণ ভুলকীভাবে ধরবেন
প্রতিটি প্রশ্নে একই ছাঁচ — “Kafka, Redis আর microservices যোগ করুন”জিজ্ঞেস করুন: কোন সংখ্যা বা requirement এই বাক্সটি দাবি করে? উত্তর না থাকলে বাক্সটি বাদ
হিসাবে একটি ×১,০০০ বা ×৮ হারানো; ৮৬,৪০০ আর ১০৫ মিশিয়ে ফেলাপ্রতিটি ধাপ এককসহ নিজে আবার গুনুন, বা ছোট script-এ চালান
ACID-এর C আর CAP-এর C, বা serializable আর linearizable গুলিয়ে ফেলাপর্ব ২৪ আর ৪০-এর সংজ্ঞার সাথে প্রতিটি দাবি মিলিয়ে দেখুন
“Quorum থাকলে সবসময় সর্বশেষ মান”, “exactly-once delivery সম্ভব” — শর্ত বাদ দেওয়া“কোন ব্যর্থতায় এটি ভাঙে?” — এই follow-up AI-কেই করুন, তারপর নিজে যাচাই
কোনো পণ্যের সীমা, দাম বা default বানিয়ে বলাঅফিসিয়াল documentation; সংস্করণভেদে বদলায়
“অমুক প্রতিষ্ঠানে এই প্রশ্ন আসে” — বানানো তালিকা আর প্রক্রিয়ার বর্ণনাএ ধরনের দাবি উপেক্ষা করুন; ধারণা আর পদ্ধতি অনুশীলন করুন

AI-কে mock interviewer বানাতে চাইলে নিয়মগুলো স্পষ্ট দিন — একবারে একটি প্রশ্ন, আপনার উত্তরের পরেই মূল্যায়ন আর follow-up:

তুমি একজন অভিজ্ঞ system design ইন্টারভিউয়ার। আমি backend পদের জন্য প্রস্তুতি নিচ্ছি। নিয়ম: - একবারে একটি ধারণাভিত্তিক প্রশ্ন করো (caching, database, messaging, consistency, resilience). আমার উত্তরের আগে নিজের উত্তর দেবে না। - আমার উত্তরের পরে মূল্যায়ন করো: প্রশ্ন পরিষ্কার করেছি কি না, trade-off বলেছি কি না, কখন কোন দিক জেতে বলেছি কি না, একটি সংখ্যা বা উদাহরণ দিয়েছি কি না, ব্যর্থতার ঘটনা ভেবেছি কি না। - তারপর একটি follow-up দাও যা এক ধাপ গভীরে যায়; তিন ধাপ পর্যন্ত চালাও। - কোনো হিসাব দিলে প্রতিটি ধাপ এককসহ দেখাও। - কোনো পণ্যের সীমা বা দাম নিশ্চিত না হলে বলবে নিশ্চিত নও। - কোনো প্রতিষ্ঠানের ইন্টারভিউ-প্রক্রিয়া নিয়ে দাবি করবে না। - নিরাপত্তার প্রশ্নে শুধু প্রতিরক্ষা নিয়ে কথা বলবে। প্রথম প্রশ্ন দিয়ে শুরু করো।

AI-এর দেওয়া উত্তর মুখস্থ করার আগে — চেকলিস্ট

নিজেকে যাচাই করুন

ইন্টারভিউর ধাঁচের ধারণা আর মুখে মুখে হিসাব। ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি ধারণাভিত্তিক প্রশ্নের শক্তিশালী উত্তরের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. ❓ প্রশ্ন পরিষ্কার করা — পড়া-লেখার অনুপাত, কতটা পুরোনো ডেটা চলে
  2. 📖 এক বাক্যে সংজ্ঞা
  3. ⚖️ Trade-off — কী পাই, কী দিই
  4. 🔢 কখন কোন দিক জেতে — একটি সংখ্যা বা উদাহরণসহ
  5. 🧪 কী ভাঙতে পারে, আর কীভাবে মেপে যাচাই করব

(সহজ) একটি অনুরোধ ১০০টি স্বাধীন সার্ভারের সবার উত্তরের অপেক্ষা করে। প্রতিটি সার্ভার আলাদাভাবে ১% সময় ধীর। মোটামুটি কত শতাংশ অনুরোধ অন্তত একটি ধীর উত্তরে আটকাবে?

  • প্রায় ১%
  • প্রায় ১০%
  • প্রায় ৬৩%
  • ১০০%

(মাঝারি) একটি সার্ভারে একটি অনুরোধের নিজস্ব সেবা-সময় ১০ ms. সরল M/M/1 মডেলে (গড় সময় = S ÷ (১ − ρ)) utilization ০.৫ থেকে ০.৯ হলে গড় সময় কত থেকে কত হয়?

  • ২০ ms থেকে ১০০ ms
  • ২০ ms থেকে ২২ ms
  • ১৫ ms থেকে ১৯ ms
  • দুটিতেই ১০ ms

(সহজ) একটি অনুরোধ পরপর তিনটি সার্ভিসের সবাইকে চায়; প্রত্যেকটির availability ৯৯.৯%, ব্যর্থতাগুলো স্বাধীন। পুরো অনুরোধের availability মোটামুটি কত?

  • ৯৯.৯%
  • প্রায় ৯৯.৭%
  • প্রায় ৯৯.৯৭%
  • প্রায় ৯৭%

(সহজ) HTTP-র সংজ্ঞা অনুযায়ী কোন method idempotent নয়, তাই টাকা কাটার মতো কাজে আলাদা Idempotency-Key লাগে?

  • GET
  • PUT
  • DELETE
  • POST

(মাঝারি) Cache-এর key সার্ভারে ভাগ হয় hash(key) mod N দিয়ে। সার্ভার ৪ থেকে ৫টি করলে মোটামুটি কত ভাগ key-এর সার্ভার বদলাবে?

  • প্রায় ২০%
  • প্রায় ২৫%
  • প্রায় ৮০%
  • ১০০%

(মাঝারি) একটি জনপ্রিয় key-এ সেকেন্ডে ২,০০০টি অনুরোধ আসে। মেয়াদ ফুরালে database থেকে মান আবার হিসাব করতে ৫০ ms লাগে, আর কোনো lock বা soft TTL নেই। মেয়াদ শেষের মুহূর্তে মোটামুটি কতগুলো একই query database-এ যাবে?

  • ১টি
  • প্রায় ১০০টি
  • প্রায় ২,০০০টি
  • প্রায় ৪০টি

(কঠিন) Wallet-এর balance ১,০০০ টাকা। দুটি অনুরোধ একসাথে balance পড়ে, app-এ বিয়োগ করে ৮০০ আর ৬০০ তুলে নতুন মান লেখে; database READ COMMITTED-এ। কোনটি এই lost update সবচেয়ে সরলভাবে ঠেকায়?

  • শর্তসহ atomic UPDATE — balance যথেষ্ট থাকলে তবেই বিয়োগ
  • কিছুই লাগবে না, READ COMMITTED এমনিই ঠেকায়
  • Balance cache-এ রেখে সেখান থেকে পড়া
  • balance কলামে একটি index যোগ করা

(মাঝারি) একটি leaderless store-এ প্রতিটি key-এর N = ৫টি replica, লেখা সফল হয় W = ৩টি ack-এ। প্রতিটি পড়া যেন অন্তত একটি সর্বশেষ সফল লেখার replica ছোঁয়, সেজন্য সবচেয়ে ছোট R কত?

  • ১
  • ২
  • ৫
  • ৩

(সহজ) ৫টি সার্ভারের একটি Raft cluster-এ একসাথে সর্বোচ্চ কতগুলো সার্ভার crash করলেও cluster নতুন লেখা commit করতে পারে?

  • ১টি
  • ২টি
  • ৩টি
  • ৪টি

(মাঝারি) একটি CP (consistency-অগ্রাধিকার) store-এ network দুই ভাগ হলো: এক দিকে ৩টি node, অন্য দিকে ২টি। ২টির দিকে একজন client লিখতে চাইলেন। সাধারণত কী ঘটবে?

  • লেখা সফল হবে, পরে দুই দিক মিলিয়ে নেওয়া হবে
  • লেখাটি নিঃশব্দে অন্য মান দিয়ে বদলে যাবে
  • লেখাটি ব্যর্থ হবে বা আটকে থাকবে, কারণ এই দিক সংখ্যালঘু
  • পুরো store, দুই দিকই, বন্ধ হয়ে যাবে

(মাঝারি) Storage সর্বশেষ যে fencing token দেখেছে তা ৩৪. এখন token ৩৩ নিয়ে একটি লেখা এল — পুরোনো একজন lock-ধারক দীর্ঘ বিরতির পর জেগে উঠেছেন। Storage-এর কী করা উচিত?

  • লেখাটি প্রত্যাখ্যান করা
  • লেখাটি গ্রহণ করা, কারণ ধারকের কাছে বৈধ token আছে
  • দুই লেখার গড় নেওয়া
  • Lock service-কে জিজ্ঞেস করে অপেক্ষা করা

(মাঝারি) একটি Bloom filter-এ false-positive হার ১% চাই, hash-এর সংখ্যা সেরা মানে। প্রতি key-এ মোটামুটি কত bit লাগবে?

  • প্রায় ১ bit
  • প্রায় ৪.৮ bit
  • প্রায় ৬৪ bit
  • প্রায় ৯.৬ bit

(মাঝারি) একটি token bucket-এ হার সেকেন্ডে ১০টি token, ধারণক্ষমতা ৫০, শুরুতে পূর্ণ। একজন client টানা যত দ্রুত সম্ভব অনুরোধ পাঠালে প্রথম ৫ সেকেন্ডে সর্বোচ্চ কতটি ছাড়া পাবে?

  • ৫০টি
  • ৬০টি
  • ১০০টি
  • ২৫০টি

(কঠিন) ৩০ দিনের SLO ৯৯.৯%. টানা ১ ঘণ্টা burn rate ১৪.৪ থাকলে ৩০ দিনের error budget-এর কত অংশ খরচ হয়?

  • ০.১%
  • ২%
  • ১৪.৪%
  • ৫০%

(মাঝারি) একটি consumer queue থেকে “wallet-এ টাকা যোগ” বার্তা পড়ে। Broker at-least-once দেয়। কোন নকশায় প্রতিটি যোগ ঠিক একবার কার্যকর হবে (effectively-once)?

  • কাজ শুরুর আগেই ack পাঠানো
  • Consumer-এ retry পুরো বন্ধ রাখা
  • Consumer-এর memory-তে দেখা বার্তার id রাখা
  • বার্তার id দিয়ে inbox সারি আর টাকা যোগ — একই database transaction-এ

(সহজ) একটি log topic-এ ৮টি partition. একই consumer group-এ ১২টি consumer চালু করা হলো। কতজন consumer কোনো partition পাবেন না?

  • ৪ জন
  • কেউ না — সবাই কিছু না কিছু পাবেন
  • ৮ জন
  • ১২ জন

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব শব্দ এখানে একসাথে:

মনে রাখুন

  1. ধারণার প্রশ্নের উত্তর একটি trade-off: সংজ্ঞা, কী পাই, কী দিই, কখন কোন দিক জেতে, আর একটি সংখ্যা।
  2. প্রথমে দুটি প্রশ্ন প্রায় সবখানে খাটে: পড়া না লেখা বেশি, আর কতটা পুরোনো ডেটা চলে।
  3. মুখে রাখার সংখ্যা: ১ − (১ − p)N, S ÷ (১ − ρ), series-এ গুণ, mod N-এ N/(N + ১), R + W > N, ২f + ১, b + r·T, burn rate ÷ ৭২০.
  4. প্রতিটি “সবসময়”-এর পেছনে একটি ব্যর্থতার ঘটনা খুঁজুন: stale set, থেমে থাকা lock-ধারক, quorum-এর ফাঁক, retry-র গুণফল, ঠান্ডা cache.
  5. আপত্তিকে তথ্য হিসেবে নিন, না জানলে সীমানা টেনে যুক্তি দিন, আর red flag বাক্যের বদলে শর্তসাপেক্ষ, মাপা উত্তর দিন।

পরের পর্বে: ধারণাগুলো এবার একসাথে — web crawler, leaderboard, pastebin আর আরও কয়েকটি নকশার পূর্ণ mock interview, requirement থেকে deep dive পর্যন্ত।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান