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

Estimation আর trade-off-এর অনুশীলন — পূর্ণ সমাধানসহ হিসাব

System Design Estimation and Trade-off Drills — Fully Worked Problems on QPS, Storage, Bandwidth, Little's Law, Percentiles, Availability, Error Budgets, Sharding, Caching, Quorums, Raft, Sketches, ID Spaces, Rate Limits, Retries, RPO/RTO and Releases

Taught in Bangla, this page is an estimation drill book with 45 fully worked problems: traffic, storage and bandwidth, Little's law, percentiles and server counts, availability, MTTR and error budgets, sharding, caching and replication lag, quorums, Raft, gossip, sketches and ID spaces, rate limits, retries, RPO/RTO and releases, plus trade-off drills, a one-page formula sheet and twelve JavaScript calculators.

এই পর্বে যা পাবেন

  • পুরো কোর্সের প্রতিটি ধরনের হিসাবের সূত্র, নিয়ম আর সাধারণ ফাঁদ — QPS থেকে burn rate, consistent hashing থেকে birthday bound
  • Requirement থেকে চূড়ান্ত সংখ্যা পর্যন্ত একটি পূর্ণ estimation, ধাপে ধাপে, আর সেই সংখ্যা নকশার ছবিতে কোথায় বসে
  • উল্টো দিকের প্রশ্ন সামলানো: “কত সার্ভার?”, “কত দিনের log রাখা যাবে?”, “কতটা error চললে alert?”, “কবে shard করতে হবে?”
  • “দুটির মধ্যে কোনটি” প্রশ্নে সংখ্যা দিয়ে যুক্তি দেওয়ার অভ্যাস — বিশ্ববিদ্যালয়ের লিখিত পরীক্ষা আর চাকরির ইন্টারভিউ দুই জায়গার জন্য
  • AI-এর দেওয়া estimation সন্দেহের চোখে দেখা আর ছোট প্রোগ্রামে মিলিয়ে নেওয়া

১ · মডিউল ১০-এর মানচিত্র, হিসাবের নিয়ম আর মৌলিক হাতিয়ার

মডিউল ১০-এ স্বাগতম। প্রথম ৬১টি পর্বে আপনি একটি অনুরোধের যাত্রা থেকে শুরু করে replication, cache, stream, consensus, observability আর সাতটি পূর্ণ case study পেরিয়ে একটি distributed key-value store পর্যন্ত এসেছেন। শেষ পাঁচটি পর্ব সেই জ্ঞান পরীক্ষার খাতায়, MCQ-এর ঘড়ির সামনে আর ইন্টারভিউর হোয়াইটবোর্ডে কাজে লাগানোর অনুশীলন। এগুলো নতুন ধারণা শেখায় না; শেখা ধারণা দ্রুত, নির্ভুলভাবে আর গুছিয়ে প্রয়োগ করতে শেখায়।

পাঁচটি অনুশীলন-পর্ব কীভাবে একসাথে কাজ করে

পর্বকী অনুশীলনকোথায় কাজে লাগে
৬২ · এই পাতাসংখ্যা: QPS, storage, latency, availability, quorum, sketch, DR; আর সংখ্যা দিয়ে trade-offলিখিত পরীক্ষার numerical, ইন্টারভিউর প্রথম ৫–১০ মিনিটের হিসাব আর deep dive-এর যুক্তি
৬৩ · MCQ প্রশ্নব্যাংকমডিউল ধরে বহুনির্বাচনি প্রশ্ন, প্রতিটি অপশনের ব্যাখ্যাসহচাকরির লিখিত পরীক্ষা আর দ্রুত ঝালাই; এখানের সূত্র সেখানে দ্রুত সিদ্ধান্তে লাগবে
৬৪ · লিখিত ও ভাইভাসংজ্ঞা, তুলনা, প্রমাণ আর ছোট নকশার মডেল উত্তরবিশ্ববিদ্যালয়ের লিখিত প্রশ্ন আর মৌখিক পরীক্ষা
৬৫ · ইন্টারভিউর ধারণা“কেন”, “কখন নয়” আর follow-up প্রশ্নের উত্তর সাজানোBackend, SRE আর platform ইন্টারভিউর আলোচনা-পর্ব
৬৬ · Mock interviewপূর্ণ নকশা, পর্ব ৬-এর আট ধাপে, শুরু থেকে wrap-up পর্যন্ত৪৫ মিনিটের system design ইন্টারভিউ

কীভাবে ব্যবহার করবেন, তা নির্ভর করে লক্ষ্যের ওপর। বিশ্ববিদ্যালয়ের পরীক্ষার জন্য আগে পর্ব ৬৪-এর সংজ্ঞা আর প্রমাণ, তারপর এই পাতার মাঝারি ও কঠিন হিসাব — বিশেষ করে availability, quorum, Bloom filter আর consistent hashing-এর অঙ্ক, যেগুলোতে সূত্র লিখে প্রমাণের লাইন দিতে হয়; শেষে পর্ব ৬৩-এর MCQ দিয়ে ঘাটতি খোঁজা। চাকরির ইন্টারভিউর জন্য উল্টো ক্রম কাজ করে: এই পাতার ভাগ ১–৩ মুখে মুখে, ঘড়ি ধরে, পাঁচ মিনিটে করা; তারপর ভাগ ৮-এর trade-off, পর্ব ৬৫-এর follow-up, আর শেষে পর্ব ৬৬-এর পূর্ণ mock — জোরে বলে, যেন সামনে কেউ বসে আছেন। দুই ক্ষেত্রেই নিয়ম একটাই: উত্তর খোলার আগে খাতায় নিজে করুন।

এই পাতার নিয়ম (convention) — প্রশ্নে অন্য কিছু না বললে

বিষয়নিয়ম
সময়১ দিন = ৮৬,৪০০ সেকেন্ড; চূড়ান্ত উত্তরে এটিই। মাথার হিসাবে ১০৫ (উত্তর প্রায় ১৪% কম আসে, তাই ১.১৬ দিয়ে গুণ করে ঠিক করুন)। বছর = ৩৬৫ দিন ≈ ৩.১৫ × ১০৭ সেকেন্ড, মাস = ৩০ দিন = ৪৩,২০০ মিনিট (পর্ব ৩ আর ৫)
এককStorage আর network দশমিকে: KB = ১০৩, MB = ১০৬, GB = ১০৯, TB = ১০১২ byte; KiB লাগলে স্পষ্ট লেখা থাকবে। Network-এর গতি bit-এ: byte/s × ৮ = bit/s
TrafficQPS = দিনের অনুরোধ ÷ ৮৬,৪০০; peak = গড় × peak factor (প্রশ্নে দেওয়া); read আর write আলাদা
Capacityএকটি সার্ভারের ক্ষমতা আসে load test থেকে; peak-এ লক্ষ্য utilization ৬০%; সার্ভার-সংখ্যা ওপরে গোল, তারপর বাড়তি (N+1 বা N+2) (পর্ব ৩)
QueueM/M/1: W = S ÷ (1 − ρ), L = ρ ÷ (1 − ρ), p99 ≈ ln 100 × W ≈ ৪.৬ × W; Little: L = λW (পর্ব ৪)
PercentileNearest-rank: n টি সাজানো নমুনায় p-তম percentile = ⌈p × n⌉-তম মান (পর্ব ৪)
Availabilityব্যর্থতা স্বাধীন ধরা (না হলে প্রশ্নে বলা থাকবে); series-এ গুণ, parallel-এ ব্যর্থতার গুণ; downtime = (1 − A) × সময়কাল (পর্ব ৫)
SLO৩০ দিনের চলমান জানালা; burn rate = দেখা error ratio ÷ (1 − SLO) (পর্ব ৫০)
খাতায় আর হোয়াইটবোর্ডে উত্তর সাজানোর ছয় নিয়ম

১. ধরে নেওয়া মান এক জায়গায়। “ধরা যাক DAU ১ কোটি, প্রতি জন দিনে ৩টি লেনদেন, peak factor ১০” — আলাদা একটি বাক্সে। পরে কোনো মান বদলালে কোন সংখ্যা বদলাবে, তা এখান থেকেই দেখা যায়।

২. সূত্র আগে, সংখ্যা পরে। “Storage = record/day × আকার × দিন × কপি” লিখে তারপর মান বসান। হিসাবে ভুল হলেও সূত্রের নম্বর থাকে, আর পরীক্ষক কোথায় ভুল তা দেখতে পান।

৩. প্রতিটি সংখ্যার সাথে একক। (অনুরোধ/দিন) ÷ (সেকেন্ড/দিন) = অনুরোধ/সেকেন্ড। একক না মিললে সূত্রই ভুল।

৪. ১০-এর ঘাতে লিখুন। ৩ × ১০৭ × ১.৪ × ১০৩ = ৪.২ × ১০১০ — শূন্য গোনার ভুল এভাবেই কমে।

৫. একটি উল্টো চেক। প্রতি ব্যবহারকারীর হিসাবে যুক্তিসংগত কি না, বা একটি সার্ভার-disk-লিংকের পরিচিত সীমার সাথে তুলনা — এটিই sanity check (পর্ব ৩)।

৬. শেষে এক লাইনের সিদ্ধান্ত। “চাপ পড়ার পথে, তাই cache আগে; storage মাঝারি” — ইন্টারভিউতে সংখ্যার চেয়ে এই লাইনটির দাম বেশি।

মৌলিক হাতিয়ার — সময়, একক আর latency-র মাত্রা

১.১(সহজ) একটি সেবায় দিনে ৫ কোটি অনুরোধ আসে। (ক) ৮৬,৪০০ দিয়ে ভাগ করে গড় QPS কত? (খ) মাথায় ১০৫ দিয়ে ভাগ করলে কত আসে, আর কত শতাংশ কম?
(a) QPS = 5 x 10^7 / 86,400 = 578.7 req/s
(b) mental: 5 x 10^7 / 10^5 = 500 req/s
    500 / 578.7 = 0.864  -> 13.6% low;  fix: 500 x 1.16 = 580

মাথার হিসাবের কৌশল: “দিনে ১ লাখ ≈ সেকেন্ডে ১”, তাই ৫ কোটি = ৫০০ লাখ ≈ সেকেন্ডে ৫০০। মাত্রা ঠিক, শুধু ১৪%-এর মতো কম। যাচাই: একক — (অনুরোধ/দিন) ÷ (সেকেন্ড/দিন) = অনুরোধ/সেকেন্ড. উত্তর: ≈ ৫৭৯ req/s; মাথায় ৫০০, প্রায় ১৩.৬% কম। ঝালাতে: পর্ব ০৩।

১.২(সহজ) (ক) ১ Gbit/s লিংকে সর্বোচ্চ কত MB/s? (খ) ১০০ Mbit/s লাইনে ১ TB ডেটা নামাতে কত সময়? (গ) একটি data center-এর ভেতরে ১ Gbit/s লিংকে ৫০০ GB-এর একটি backup কপি করতে কত মিনিট? Protocol-এর বাড়তি byte উপেক্ষা করুন।
(a) 10^9 bit/s / 8 = 1.25 x 10^8 B/s = 125 MB/s
(b) 1 TB = 8 x 10^12 bit;  8 x 10^12 / 10^8 = 80,000 s = 22.2 h
(c) 500 GB = 4 x 10^12 bit; 4 x 10^12 / 10^9 = 4,000 s = 66.7 min

সবচেয়ে বড় ফাঁদ ৮ গুণের: “১০০ Mbit/s মানে ১০০ MB/s” ধরলে (খ)-এর উত্তর ২.৮ ঘণ্টা আসত — আসলের আট ভাগের এক ভাগ। যাচাই: ১২৫ MB/s-এ ৫০০ GB = ৫০০,০০০ ÷ ১২৫ = ৪,০০০ সেকেন্ড — একই। এই ধরনের সংখ্যা DR-এ restore-সময়ের হিসাবে সরাসরি লাগে (ভাগ ৭)। উত্তর: ১২৫ MB/s; প্রায় ২২.২ ঘণ্টা; প্রায় ৬৬.৭ মিনিট। ঝালাতে: পর্ব ০৩।

১.৩(মাঝারি) ধরা যাক RAM থেকে পড়া ১০০ ns, SSD-এর random read ১০০ µs, hard disk-এর seek ১০ ms, একই data center-এ round trip ০.৫ ms, মহাদেশ পেরোনো round trip ১৫০ ms. (ক) একটি পাতা খুলতে মহাদেশ পেরিয়ে পরপর ৬টি call, আর data center-এর ভেতরে পরপর ১০০টি call — শুধু network-এ কত সময়? (খ) ১,০০০টি random read RAM, SSD আর hard disk-এ কত সময় নেয়? (গ) ফাইবারে আলো প্রায় ২ × ১০৫ km/s; ৩,০০০ km দূরের সার্ভারে round trip-এর তাত্ত্বিক সর্বনিম্ন কত?
(a) 6 x 150 ms = 900 ms;   100 x 0.5 ms = 50 ms;   total = 950 ms
(b) RAM : 1,000 x 100 ns = 0.1 ms
    SSD : 1,000 x 100 us = 0.1 s
    HDD : 1,000 x 10 ms  = 10 s
(c) RTT >= 2 x 3,000 km / 200,000 km/s = 0.03 s = 30 ms

(ক)-এর শিক্ষা: পরপর করা call-এর সংখ্যাই latency ঠিক করে। ছয়টি মহাদেশ-পেরোনো call-কে একসাথে (parallel) পাঠালে বা কাছের region-এ সরালে প্রায় ৭৫০ ms বাঁচে। (খ)-তে RAM থেকে hard disk পর্যন্ত লাফ এক লাখ গুণ — এজন্যই cache. (গ)-এর ৩০ ms কোনো প্রকৌশলে কমে না; বাস্তবে পথ বাঁকা আর router-এর অপেক্ষা যোগ হয় বলে মাপা মান বেশি। যাচাই: hard disk-এ সেকেন্ডে ১ ÷ ১০ ms = ১০০টি random read — পরিচিত IOPS-এর মাত্রা। উত্তর: ≈ ৯৫০ ms; ০.১ ms, ০.১ s আর ১০ s; অন্তত ৩০ ms. ঝালাতে: পর্ব ০৩ আর ০৭।

১.৪(মাঝারি) Storage = ২৩ লাখ ব্যবহারকারী × প্রতি জন ৩৭টি record × প্রতিটি ১,৮০০ byte. (ক) প্রতিটি সংখ্যাকে এক significant figure-এ গোল করে মাথায় হিসাব করুন, আর ঠিক উত্তরের সাথে তুলনা করুন। (খ) তিনটিকেই ওপরের দিকে গোল করলে (৩০ লাখ, ৪০, ২,০০০) ভুল কত গুণ হয়?
exact : 2.3 x 10^6 x 37 x 1,800 = 1.532 x 10^11 B  (153 GB)
(a)   : 2 x 10^6 x 4 x 10^1 x 2 x 10^3 = 16 x 10^10 = 1.6 x 10^11 B
        1.6 / 1.532 = 1.045  -> only 4.5% high (errors cancel)
(b)   : 3 x 10^6 x 4 x 10^1 x 2 x 10^3 = 2.4 x 10^11 B
        2.4 / 1.532 = 1.567  -> 57% high (errors add up)

(ক)-তে ২৩ লাখ নিচে (প্রায় ১৩%), ৩৭ আর ১,৮০০ ওপরে (৮% আর ১১%) গোল হয়েছে, তাই ভুলগুলো অনেকটা কাটাকাটি। (খ)-তে সব একদিকে বলে জমে গেছে — তবু এক মাত্রার (১০ গুণ) অনেক ভেতরে, তাই নকশার সিদ্ধান্ত বদলায় না। যাচাই: ঘাত যোগ — ৬ + ১ + ৩ = ১০, আর a-গুলোর গুণফল ১৬, তাই ১.৬ × ১০১১. উত্তর: মাথায় ≈ ১৬০ GB বনাম ঠিক ≈ ১৫৩ GB (৪.৫% বেশি); সব ওপরে গোল করলে ≈ ২৪০ GB, প্রায় ১.৫৭ গুণ। ঝালাতে: পর্ব ০৩ (order of magnitude).

(সহজ) একটি সেবায় দিনে ১০ কোটি অনুরোধ আসে। ১ দিন = ৮৬,৪০০ সেকেন্ড ধরে গড় QPS প্রায় কত?

  • ≈ ১,১৫৭
  • ≈ ১,০০০
  • ≈ ২৭,৭৭৮
  • ≈ ১১,৫৭৪

(সহজ) ২০০ Mbit/s লিংকে পূর্ণ গতিতে ১০ GB-এর একটি ফাইল পাঠাতে কত সময় লাগে? (GB = ১০৯ byte, protocol-এর বাড়তি byte উপেক্ষা করুন।)

  • ৫০ সেকেন্ড
  • ৪০০ সেকেন্ড
  • ৩,২০০ সেকেন্ড
  • ০.৪ সেকেন্ড

(মাঝারি) একটি পাতা খুলতে মহাদেশ পেরিয়ে পরপর ৪টি call (প্রতিটির round trip ১৫০ ms) আর একই data center-এ পরপর ২০টি database call (প্রতিটি ০.৫ ms) লাগে। শুধু network-এর অপেক্ষা মোট কত?

  • ১৫০ ms
  • ১৭০ ms
  • ৬১০ ms
  • ৩,৬০০ ms

(সহজ) একটি hard disk-এর একটি random read-এ প্রায় ১০ ms লাগে। একটি disk সেকেন্ডে মোটামুটি কয়টি random read করতে পারে?

  • ১০,০০০
  • ১,০০০
  • ১০
  • ১০০

২ · Traffic আর storage — QPS, peak, বছরের storage আর bandwidth

সূত্রের কার্ড

Traffic: QPS = DAU × প্রতি জনের অনুরোধ ÷ ৮৬,৪০০; peak = গড় × peak factor; read:write আলাদা লিখুন।

Storage: নতুন record/দিন × আকার × দিন × replication factor × overhead (index, metadata: প্রায়ই ১.২–১.৫). বড় ফাইলে erasure coding দিলে ×৩-এর জায়গায় প্রায় ×১.৫।

Bandwidth: QPS × payload (byte) × ৮ = bit/s; ingress আর egress আলাদা। বৃদ্ধি g হারে হলে n বছরের মোট = প্রথম বছর × ((1 + g)n − 1) ÷ g.

২.১(সহজ) একটি কাল্পনিক সামাজিক অ্যাপ: DAU ২ কোটি, প্রতি জন দিনে ১০ বার feed পড়েন আর ১টি পোস্ট দেন। Peak factor ৪। গড় আর peak-এ read ও write QPS কত, read:write অনুপাত কত?
reads/day  = 2 x 10^7 x 10 = 2 x 10^8   -> 2 x 10^8 / 86,400 = 2,314.8 /s
writes/day = 2 x 10^7 x 1  = 2 x 10^7   -> 2 x 10^7 / 86,400 =   231.5 /s
peak x 4   : read 9,259 /s,  write 926 /s,  total 10,185 /s
read:write = 10 : 1

Read আর write আলাদা রাখার কারণ: দুটির নকশা আলাদা — read বাড়লে cache আর replica, write বাড়লে sharding আর queue. যাচাই: মাথায় ২ × ১০৮ ÷ ১০৫ = ২,০০০ — ২,৩১৫-এর মাত্রার সাথে মেলে। উত্তর: গড়ে read ≈ ২,৩১৫/s, write ≈ ২৩১.৫/s; peak-এ ≈ ৯,২৫৯ আর ≈ ৯২৬/s; অনুপাত ১০:১। ঝালাতে: পর্ব ০৩।

২.২(মাঝারি) একই অ্যাপে প্রতিটি পোস্টের লেখা আর metadata ১ KB; ১০% পোস্টে একটি ৫০০ KB-এর ছবি থাকে। লেখা ৫ বছর রাখতে হবে, ৩টি কপিতে, index-এর জন্য ২৫% বাড়তি। ছবি object storage-এ, ৩টি কপিতে। (ক) লেখার ৫ বছরের storage কত? (খ) ছবির এক বছরের storage কত? (গ) ছবিতে ৩ কপির বদলে ১.৫ গুণের erasure coding দিলে এক বছরে কত লাগে?
(a) 2 x 10^7 posts/day x 1 KB = 20 GB/day
    x 365 x 5 = 36.5 TB raw;  x 3 = 109.5 TB;  x 1.25 = 136.9 TB
(b) 0.1 x 2 x 10^7 = 2 x 10^6 photos/day x 500 KB = 1 TB/day
    x 365 = 365 TB raw;  x 3 = 1,095 TB = 1.095 PB per year
(c) 365 TB x 1.5 = 547.5 TB  (saves 547.5 TB a year)

মাত্র ১০% পোস্টে ছবি, তবু ছবির এক বছর লেখার পাঁচ বছরের প্রায় আট গুণ। Storage-এর নকশা তাই বড় ফাইলের দিকে তাকিয়ে হয়: ছবি database-এ নয়, object storage-এ; database-এ শুধু তার key (পর্ব ২৬)। যাচাই: প্রতি ছবি-পোস্টে ৫০০ গুণ বড় byte, আর ছবি-পোস্ট ১০ ভাগের ১ ভাগ, তাই প্রতিদিন ছবি লেখার ৫০ গুণ (১ TB বনাম ২০ GB) — মেলে। উত্তর: ≈ ১৩৬.৯ TB; ≈ ১.০৯৫ PB; ≈ ৫৪৭.৫ TB. ঝালাতে: পর্ব ০৩ আর ২৬।

২.৩(মাঝারি) একটি কাল্পনিক খেলা-সম্প্রচার অ্যাপে ফাইনাল ম্যাচের সময় একসাথে ১০ লাখ দর্শক গড়ে ৩ Mbit/s-এর stream দেখেন। (ক) মোট egress কত? (খ) CDN ৯৫% traffic নিজের cache থেকে দিলে origin-এর egress কত? (গ) offload ৯৫% থেকে ৯৯% হলে origin-এর চাপ কত গুণ কমে?
(a) 10^6 x 3 x 10^6 bit/s = 3 x 10^12 bit/s = 3 Tbit/s
(b) origin = 3 Tbit/s x (1 - 0.95) = 150 Gbit/s
(c) 99%: 3 Tbit/s x 0.01 = 30 Gbit/s  -> 150 / 30 = 5x less

৩ Tbit/s কোনো একক data center-এর লিংকে আঁটে না — এই সংখ্যাই বলে দেয়, বিতরণ করতে হবে ব্যবহারকারীর কাছের CDN-এর edge থেকে (পর্ব ১৭)। লক্ষ করুন, offload ৯৫ থেকে ৯৯ — মাত্র ৪ শতাংশ বিন্দু — অথচ origin-এর চাপ ৫ গুণ কমে, কারণ চাপ ঠিক করে miss-এর অংশ (৫% বনাম ১%). যাচাই: ১০ লাখ × ৩ Mbit = ৩০ লাখ Mbit = ৩ × ১০৬ Mbit = ৩ Tbit. উত্তর: ৩ Tbit/s; ১৫০ Gbit/s; ৫ গুণ (৩০ Gbit/s). ঝালাতে: পর্ব ১৭ আর ৫৯।

২.৪(কঠিন) একটি কাল্পনিক chat অ্যাপ: DAU ৫ কোটি, প্রতি জন দিনে ৪০টি বার্তা পাঠান। ৮০% বার্তা একজনকে (১টি delivery), ২০% বার্তা গড়ে ২০ জনের group-এ (প্রেরক ছাড়া বাকি ১৯ জনকে delivery). Peak factor ৫, delivery-প্রতি ২০০ byte. গড় আর peak-এ প্রতি সেকেন্ডে কয়টি বার্তা আর কয়টি delivery, আর peak-এ বাইরে যাওয়া bandwidth কত?
messages/day   = 5 x 10^7 x 40 = 2 x 10^9      -> 23,148 /s avg
deliveries/msg = 0.8 x 1 + 0.2 x 19 = 0.8 + 3.8 = 4.6
deliveries/day = 2 x 10^9 x 4.6 = 9.2 x 10^9   -> 106,481 /s avg
peak x 5       : 115,741 msg/s,  532,407 deliveries/s
egress at peak = 532,407 x 200 B x 8 = 851.9 Mbit/s

বার্তা লেখা হয় একবার, কিন্তু পৌঁছাতে হয় গড়ে ৪.৬ বার — এই fan-out-ই chat-এর আসল চাপ (পর্ব ৫৫)। “গড় group-এ ২০ জন” বললে ২০-কে নয়, ১৯-কে গুনতে হয় — প্রেরক নিজেকে পাঠান না (তবে তাঁর অন্য device-এ sync লাগতে পারে, সেটি আলাদা ধরে নেওয়া)। যাচাই: প্রতি ব্যবহারকারীর দিক থেকে — দিনে ৪০টি পাঠান, ৪০ × ৪.৬ = ১৮৪টি গ্রহণ — group-ভারী ব্যবহারে বিশ্বাসযোগ্য। উত্তর: গড়ে ≈ ২৩,১৪৮ বার্তা আর ≈ ১,০৬,৪৮১ delivery/s; peak-এ ≈ ১,১৫,৭৪১ আর ≈ ৫,৩২,৪০৭/s; egress ≈ ৮৫২ Mbit/s. ঝালাতে: পর্ব ০৩, ৩২ আর ৫৫।

২.৫(মাঝারি) (ক) প্রথম বছরে ১০০ TB নতুন ডেটা, আর প্রতি বছর নতুন ডেটা ৫০% বাড়ে। চার বছরে মোট কত? (খ) উল্টো প্রশ্ন: সেকেন্ডে ৫০,০০০টি log event, প্রতিটি ১ KB, ৩টি কপি। ১ PB জায়গায় কত দিনের log রাখা যাবে?
(a) years: 100 + 150 + 225 + 337.5 = 812.5 TB
    formula: 100 x (1.5^4 - 1) / 0.5 = 100 x 4.0625 / 0.5 = 812.5 TB
(b) per day = 5 x 10^4 x 10^3 B x 86,400 = 4.32 TB raw;  x 3 = 12.96 TB
    days = 1,000 TB / 12.96 TB = 77.2 days

(ক)-তে বৃদ্ধি না ধরলে ৪০০ TB আসত — অর্ধেক। বৃদ্ধি একটি geometric series, আর চতুর্থ বছর একাই প্রায় মোটের ৪২%. (খ) হলো retention-এর উল্টো প্রশ্ন: জায়গা স্থির, দিন বের করতে হবে। সিদ্ধান্ত: ৭৭ দিনের বেশি রাখতে চাইলে পুরোনো log সস্তা storage-এ সরানো বা sampling. যাচাই: ৫০,০০০ × ১ KB = ৫০ MB/s; × ৮৬,৪০০ ≈ ৪.৩২ TB/দিন — মেলে। উত্তর: ৮১২.৫ TB; প্রায় ৭৭ দিন। ঝালাতে: পর্ব ০৩ আর ৫০।

এবার একটি পূর্ণ estimation — requirement থেকে চূড়ান্ত সংখ্যা পর্যন্ত। ইন্টারভিউতে প্রথম ৫–১০ মিনিটে ঠিক এই কাজটি করতে হয় (পর্ব ৬-এর ধাপ ২), আর লিখিত পরীক্ষায় “একটি সিস্টেমের capacity হিসাব করুন” প্রশ্নের পূর্ণ উত্তর এটিই।

  1. ধরে নেওয়া10^7 DAU৩ লেনদেন/দিন
  2. Write347 → 3,472/s× ১০ peak
  3. Read579 → 5,787/sমোট 9,259/s
  4. Storage460 TB১০ বছর, ৩ কপি
  5. App11 + 2৬০% লক্ষ্য
  6. DB shard4লেখার চাপে
  7. যাচাই51%একটি সার্ভার নষ্টে
হিসাবের খাতা
বিষয়
সূত্র
মান
  1. ধাপ ১ — requirement থেকে ধরে নেওয়া মান। একটি কাল্পনিক mobile banking সেবা: দৈনিক সক্রিয় ব্যবহারকারী ১ কোটি, প্রতি জন দিনে গড়ে ৩টি লেনদেন আর ৫ বার লেনদেনের ইতিহাস দেখেন। মাসের শুরু বা ঈদের আগে ভিড় গড়ের ১০ গুণ (peak factor ১০)। একটি লেনদেনের record ১ KB, সাথে double-entry ledger-এর দুটি সারি, প্রতিটি ২০০ byte — মোট ১.৪ KB. ডেটা ১০ বছর, ৩টি কপিতে। সব মান কাল্পনিক, “ধরা যাক”।
  2. ধাপ ২ — write QPS. ৩ × ১০৭ লেনদেন ÷ ৮৬,৪০০ ≈ ৩৪৭.২/s গড়ে; peak-এ ১০ গুণ, ≈ ৩,৪৭২/s. মাথায়: ৩ কোটি ÷ ১ লাখ = ৩০০ — মাত্রা মেলে।
  3. ধাপ ৩ — read আর মোট QPS. ৫ × ১০৭ ÷ ৮৬,৪০০ ≈ ৫৭৮.৭/s, peak-এ ≈ ৫,৭৮৭/s. Read:write মাত্র ৫:৩ — banking-এ লেখা অনেক সামাজিক অ্যাপের চেয়ে ভারী, আর প্রতিটি লেখা হারানো চলে না। মোট peak ≈ ৯,২৫৯/s.
  4. ধাপ ৪ — storage. ৩ × ১০৭ × ১.৪ KB = ৪২ GB প্রতিদিন; ১০ বছরে (৩,৬৫০ দিন) ১৫৩.৩ TB raw; তিন কপিতে ≈ ৪৫৯.৯ TB. Index ধরলে আরও বেশি — একটি মেশিনে ধরানোর প্রশ্নই ওঠে না।
  5. ধাপ ৫ — bandwidth. Peak-এ ৩,৪৭২ × ১.৪ KB × ৮ ≈ ৩৮.৯ Mbit/s ভেতরে আসে; read-এর উত্তরও ছোট। Network এখানে bottleneck নয় — এটিও একটি কাজের উপসংহার।
  6. ধাপ ৬ — app server. ধরা যাক load test-এ একটি সার্ভার ১,৫০০ req/s পর্যন্ত p99 লক্ষ্যের ভেতরে রাখে; ৬০% লক্ষ্যে কার্যকর ৯০০/s. ৯,২৫৯ ÷ ৯০০ ≈ ১০.২৯ → ওপরে গোল ১১টি; একটি নষ্ট আর একটি deploy-এর জন্য N+2 = ১৩টি।
  7. ধাপ ৭ — database-এর লেখা. প্রতিটি লেনদেনে ৩টি সারি (লেনদেন + দুটি ledger), তাই peak-এ ৩,৪৭২ × ৩ ≈ ১০,৪১৭ সারি/s. ধরা যাক একটি primary মেপে ৫,০০০ সারি/s পারে; ৬০%-এ ৩,০০০. ১০,৪১৭ ÷ ৩,০০০ ≈ ৩.৪৭ → ৪টি shard, প্রতিটির ৩টি কপি। Read replica লেখার চাপ কমায় না — সেজন্যই sharding (পর্ব ২৩)।
  8. ধাপ ৮ — sanity check. প্রতি জন দিনে ৩টি লেনদেন — বিশ্বাসযোগ্য। একটি app server নষ্ট হলে বাকি ১২টিতে peak-এ ব্যস্ততা ৯,২৫৯ ÷ (১২ × ১,৫০০) ≈ ৫১.৪% — লক্ষ্যের ভেতরে। Storage: ১ বছরের hot ডেটা ১৫.৩৩ TB ÷ ৪ shard ≈ ৩.৮৩ TB প্রতি কপি — চলে; পুরোনো বছরগুলো archive-এ (object storage), না হলে ১০ বছরে shard-প্রতি ৩৮ TB-এর বেশি হতো।

Mobile banking-এর হিসাব — সংখ্যাগুলো নকশার কোথায় বসে

Peak QPS sizes the app tier, row writes size the shards, retention sizes the archive

Mobile banking estimation-এর সংখ্যা নকশার ছবিতে ব্যবহারকারী · mobile app DAU 10^7 · peak ×10 9,259 req/s peak Load balancer প্রতি সার্ভারে ≤ 900/s App servers × 11 (+2) ক্ষমতা 1,500/s · লক্ষ্য 60% 10,417 rows/s peak Shard 1 Shard 2 Shard 3 Shard 4 ×3 কপি ×3 কপি ×3 কপি ×3 কপি প্রতি shard ≤ 3,000 rows/s · hot ≈ 3.83 TB Archive · object storage ১০ বছরে মোট ≈ 460 TB (৩ কপি)
ছবি ৬২.১ — Peak QPS ঠিক করে app server-এর সংখ্যা, সারি-লেখার হার ঠিক করে shard-এর সংখ্যা, আর রাখার মেয়াদ ঠিক করে archive-এর আকার। দাগকাটা তীর মানে এক বছরের পুরোনো ডেটা পেছনে সরানো। সব মান ধরে নেওয়া input থেকে হিসাব করা।

নিচের ক্যালকুলেটর একই সূত্রে তিনটি পরিস্থিতি চালায় — ২.১–২.২-এর লেখা আর ছবি, আর stepper-এর লেনদেন। Input বদলে নিজের যেকোনো প্রশ্ন মেলান:

// QPS, peak, storage and bandwidth from daily counts. Every input is an assumption: edit and Run.
const DAY = 86400, YEAR = 365;
function plan(s) {
  const r = s.readsPerDay / DAY, w = s.writesPerDay / DAY;
  const raw = s.writesPerDay * s.bytesPerWrite * YEAR * s.years;  // bytes, one copy
  const stored = raw * s.copies * s.overhead;                     // with replicas and indexes
  const egress = r * s.bytesPerRead * 8;                          // bit/s, average
  return { r, w, peak: (r + w) * s.peak, raw, stored, egress };
}
function si(x, u) {                                               // powers of 10, as disks and links count
  const p = ["", "K", "M", "G", "T", "P", "E"]; let i = 0;
  while (x >= 1000 && i < p.length - 1) { x /= 1000; i++; }
  return x.toFixed(x >= 100 ? 0 : 2) + " " + p[i] + u;
}
const scenarios = [
  { name: "text posts", readsPerDay: 2e8, writesPerDay: 2e7, bytesPerWrite: 1e3, bytesPerRead: 2e3,
    years: 5, copies: 3, overhead: 1.25, peak: 4 },
  { name: "photos", readsPerDay: 2e8, writesPerDay: 2e6, bytesPerWrite: 5e5, bytesPerRead: 2e5,
    years: 1, copies: 3, overhead: 1, peak: 4 },
  { name: "bank tx", readsPerDay: 5e7, writesPerDay: 3e7, bytesPerWrite: 1400, bytesPerRead: 2e3,
    years: 10, copies: 3, overhead: 1, peak: 10 },
];
for (const s of scenarios) {
  const o = plan(s);
  console.log(s.name.padEnd(11) + "read " + o.r.toFixed(0) + "/s  write " + o.w.toFixed(1) +
    "/s  peak " + o.peak.toFixed(0) + "/s");
  console.log("".padEnd(11) + "raw " + si(o.raw, "B") + "  stored " + si(o.stored, "B") +
    "  egress avg " + si(o.egress, "bit/s"));
}

আউটপুট:

text posts read 2315/s  write 231.5/s  peak 10185/s
           raw 36.50 TB  stored 137 TB  egress avg 37.04 Mbit/s
photos     read 2315/s  write 23.1/s  peak 9352/s
           raw 365 TB  stored 1.09 PB  egress avg 3.70 Gbit/s
bank tx    read 579/s  write 347.2/s  peak 9259/s
           raw 153 TB  stored 460 TB  egress avg 9.26 Mbit/s

প্রথম জোড়া ২.১ আর ২.২(ক): read ২,৩১৫/s, write ২৩১.৫/s, peak ১০,১৮৫/s; raw ৩৬.৫ TB, কপি ও overhead-সহ ১৩৭ TB. দ্বিতীয় জোড়া ছবির: এক বছরে ৩৬৫ TB raw, তিন কপিতে ১.০৯ PB, আর দিনে ২০ কোটি বার ২০০ KB দেখালে গড় egress ৩.৭০ Gbit/s. তৃতীয়টি stepper-এর ৯,২৫৯/s আর ৪৬০ TB. peak ৪ থেকে ১০ করে দেখুন — শুধু peak-এর সংখ্যা বদলায়।

(সহজ) DAU ৫০ লাখ, প্রতি জন দিনে ২০ বার পড়েন, peak factor ৩। Peak read QPS প্রায় কত?

  • ≈ ৩,৪৭২
  • ≈ ১,১৫৭
  • ≈ ৩৪,৭২২
  • ≈ ৮৩,৩৩৩

(মাঝারি) প্রতিদিন ১ কোটি নতুন record, প্রতিটি ২ KB, রাখতে হবে ৩ বছর, replication factor ৩, overhead ধরবেন না। মোট storage কত?

  • ২১.৯ TB
  • ৬৫.৭ TB
  • ১৯৭.১ TB
  • ৭.৩ TB

(মাঝারি) একসাথে ২ লাখ দর্শক গড়ে ৪ Mbit/s-এর ভিডিও দেখেন, আর CDN ৯০% traffic নিজের cache থেকে দেয়। Origin-এর egress কত?

  • ৮০০ Gbit/s
  • ১০ Gbit/s
  • ৮০ Gbit/s
  • ৮ Gbit/s

(মাঝারি) প্রথম বছরে ২০০ TB নতুন ডেটা, আর প্রতি বছর নতুন ডেটা ৫০% বাড়ে। তিন বছরে মোট কত জমবে?

  • ৬০০ TB
  • ৪৫০ TB
  • ৬৭৫ TB
  • ৯৫০ TB

৩ · Latency আর capacity — Little-এর সূত্র, percentile, fan-out আর সার্ভারের সংখ্যা

সূত্রের কার্ড

Little: L = λW — একসাথে চলা অনুরোধ = আগমনের হার (arrival rate) × গড় সময়। Thread, connection আর queue-এর মাপ এখান থেকে।

M/M/1: ρ = λS; W = S ÷ (1 − ρ); L = ρ ÷ (1 − ρ); p99 ≈ ৪.৬W. লক্ষ্য W ≤ T হলে ρ ≤ 1 − S/T.

Tail: N-টি backend-এ fan-out, প্রতিটি p সম্ভাবনায় ধীর: P(অন্তত একটি ধীর) = 1 − (1 − p)N ≈ Np (ছোট হলে)। পুরো অনুরোধের p99 রাখতে প্রতিটিকে 0.991/N সম্ভাবনায় দ্রুত হতে হবে।

সার্ভার: ⌈peak ÷ (একটির ক্ষমতা × লক্ষ্য utilization)⌉ + বাড়তি; z-টি zone-এর একটি হারালে বাকি z − 1 টিকে পুরো peak টানতে হয়। Overload-এ (λ > μ, অসীম queue) সব অনুরোধ timeout D ছাড়ায় T* = Dμ ÷ (λ − μ) সেকেন্ড পরে।

৩.১(সহজ) (ক) একটি সেবায় সেকেন্ডে ২,০০০টি অনুরোধ আসে, প্রতিটি গড়ে ১৫০ ms সেবার ভেতরে থাকে। গড়ে একসাথে কতগুলো চলছে? ৮টি সার্ভারে সমান ভাগ হলে প্রতিটিতে কত? (খ) প্রতিটি সার্ভারে সেকেন্ডে ৩০০টি অনুরোধ, প্রতিটি database connection গড়ে ২৫ ms ধরে রাখে। কয়টি connection ব্যস্ত থাকে? Database ধীর হয়ে ১০০ ms নিলে? Pool-এর আকার ১০.
(a) L = lambda x W = 2,000 /s x 0.150 s = 300 in flight;  300 / 8 = 37.5 per server
(b) L = 300 /s x 0.025 s = 7.5 connections busy   (pool 10: ok, 75%)
    slow DB: 300 /s x 0.100 s = 30 needed > 10 in the pool
    -> requests queue for a connection, W grows, threads pile up

Little-এর সূত্রের জোর হলো এটি বণ্টন জানতে চায় না — স্থিতিশীল যেকোনো সিস্টেমে দীর্ঘ সময়ের গড়ে খাটে (পর্ব ৪)। (খ)-এর দ্বিতীয় অংশই cascading failure-এর বীজ: database মরেনি, শুধু ধীর — তবু pool ফুরিয়ে app-এর সব thread আটকে যায় (পর্ব ৪৮)। তাই timeout-এর ঊর্ধ্বসীমা = pool ÷ হার = ১০ ÷ ৩০০ s ≈ ৩৩ ms-এর মতো যুক্তিতে বসে। যাচাই: একক — (অনুরোধ/s) × s = অনুরোধ। উত্তর: ৩০০টি (সার্ভারপ্রতি ৩৭.৫); ৭.৫টি connection; ধীর database-এ ৩০টি লাগবে — pool ফুরাবে। ঝালাতে: পর্ব ০৪ আর ৪৮।

৩.২(মাঝারি) একটি endpoint-এর ২০টি latency নমুনা (ms, সাজানো): 12, 14, 15, 15, 16, 18, 19, 20, 21, 22, 24, 25, 27, 30, 33, 38, 45, 60, 110, 240. Nearest-rank পদ্ধতিতে p50, p90, p95 আর p99 কত? গড় কত, আর গড় কেন বিভ্রান্তিকর?
rank = ceil(p x n),  n = 20
p50: ceil(10)   = 10th -> 22 ms
p90: ceil(18)   = 18th -> 60 ms
p95: ceil(19)   = 19th -> 110 ms
p99: ceil(19.8) = 20th -> 240 ms   (= the maximum)
mean = 804 / 20 = 40.2 ms

গড় ৪০.২ ms — যা আসলে কোনো অনুরোধের অভিজ্ঞতা নয়: ১৬টি অনুরোধ এর চেয়ে দ্রুত, আর ২টি অনেক ধীর। দুটি ধীর নমুনা গড়কে প্রায় ২৫ থেকে ৪০ ms-এ (প্রায় ১.৬ গুণ) তুলেছে, কিন্তু p50-কে ছোঁয়নি। ২০টি নমুনায় p99 আর সর্বোচ্চ একই — এত ছোট নমুনায় p99 বলার অর্থ নেই; অনেক টুল interpolation ব্যবহার করে বলে উত্তর আলাদা হয়, তাই পদ্ধতি লিখুন (পর্ব ৪)। যাচাই: যোগফল ৮০৪ — দশটি করে দুই ভাগে ১৭২ আর ৬৩২. উত্তর: ২২, ৬০, ১১০ আর ২৪০ ms; গড় ৪০.২ ms. ঝালাতে: পর্ব ০৪ আর ৫০ (percentile).

৩.৩(মাঝারি) একটি search অনুরোধ একসাথে N-টি shard-এ যায় আর সবগুলোর উত্তরের অপেক্ষা করে। প্রতিটি shard স্বাধীনভাবে ১% সময় ধীর। (ক) N = ১০, ৫০ আর ১০০-এ কত শতাংশ অনুরোধ অন্তত একটি ধীর উত্তরে আটকায়? (খ) N = ৫০-এ পুরো অনুরোধের ৯৯% দ্রুত রাখতে প্রতিটি shard-কে কতটা ভালো হতে হবে?
(a) P = 1 - 0.99^N
    N = 10 : 1 - 0.904 = 9.6%
    N = 50 : 1 - 0.605 = 39.5%
    N = 100: 1 - 0.366 = 63.4%
(b) (1 - p)^50 = 0.99  ->  1 - p = 0.99^(1/50) = 0.999799
    each shard slow only 0.0201% of the time  (about its p99.98)

প্রতিটি shard-এর p99 যত ভালোই হোক, fan-out বড় হলে পুরো অনুরোধের tail latency সেই shard-গুলোর p99.৯৮-এর মতো দুর্লভ ধীরতায় গিয়ে ঠেকে। প্রতিকার: কম fan-out, hedged request, timeout-এ আংশিক ফল আর cache (পর্ব ৪)। Dean ও Barroso-র “The Tail at Scale” (২০১৩) এই হিসাবকে বিখ্যাত করে। যাচাই: ছোট Np-এ আসন্ন মান — N = ১০-এ ১০%, সঠিক ৯.৬%, কাছাকাছি; N = ১০০-এ Np = ১০০% অসম্ভব, তাই সূত্রই লাগে। উত্তর: ≈ ৯.৬%, ৩৯.৫% আর ৬৩.৪%; প্রতিটি shard-কে ≈ ৯৯.৯৮% সময় দ্রুত হতে হবে। ঝালাতে: পর্ব ০৪।

৩.৪(কঠিন) একটি worker-এর service time S = ২০ ms, আগমন এলোমেলো (M/M/1 ধরুন)। (ক) সেকেন্ডে ২৫, ৪০ আর ৪৫টি অনুরোধে ρ, গড় সময় W, গড়ে ভেতরে L আর আনুমানিক p99 কত? (খ) গড় সময় ৫০ ms-এর মধ্যে রাখতে সেকেন্ডে সর্বোচ্চ কতটি অনুরোধ নেওয়া যায়?
(a) rho = lambda x S;  W = S / (1 - rho);  L = rho / (1 - rho);  p99 ~ 4.6 W
    lambda 25: rho 0.5, W = 20/0.5 = 40 ms,  L = 1, p99 ~ 184 ms
    lambda 40: rho 0.8, W = 20/0.2 = 100 ms, L = 4, p99 ~ 461 ms
    lambda 45: rho 0.9, W = 20/0.1 = 200 ms, L = 9, p99 ~ 921 ms
(b) S / (1 - rho) <= 50  ->  1 - rho >= 0.4  ->  rho <= 0.6
    lambda <= 0.6 / 0.020 s = 30 req/s

৪০ থেকে ৪৫ — চাপ মাত্র সাড়ে বারো শতাংশ বাড়ল, গড় সময় দ্বিগুণ। ১-এর কাছে বক্ররেখা খাড়া — এজন্যই peak-এ ৬০% লক্ষ্য (পর্ব ৩)। p99 ≈ ৪.৬W আসে M/M/1-এ মোট সময়ের exponential বণ্টন থেকে: P(T > t) = e−t/W = ০.০১ হলে t = W ln ১০০. বাস্তব সিস্টেম এর চেয়ে বেশি এলোমেলো হলে tail আরও খারাপ। যাচাই: Little দিয়ে — λ = ৪০, W = ০.১ s, L = ৪ — সূত্রের L-এর সাথে মেলে। উত্তর: (০.৫, ৪০ ms, ১, ≈ ১৮৪ ms), (০.৮, ১০০ ms, ৪, ≈ ৪৬১ ms), (০.৯, ২০০ ms, ৯, ≈ ৯২১ ms); সর্বোচ্চ ৩০ req/s. ঝালাতে: পর্ব ০৪ (utilization).

৩.৫(মাঝারি) Peak-এ সেকেন্ডে ৫০,০০০ অনুরোধ। Load test-এ একটি সার্ভার ২,৫০০ req/s পর্যন্ত p99 লক্ষ্যের ভেতরে রাখে; লক্ষ্য utilization ৬০%. (ক) কয়টি সার্ভার, N+2-সহ? একটি নষ্ট হলে ব্যস্ততা কত? (খ) সার্ভারগুলো ৩টি zone-এ, আর একটি পুরো zone হারালেও peak সামলাতে হবে — প্রতি zone-এ কয়টি, মোট কয়টি?
(a) effective = 2,500 x 0.6 = 1,500 /s per server
    50,000 / 1,500 = 33.3 -> 34;  N + 2 = 36
    one down: 50,000 / (35 x 2,500) = 57.1% busy  (under 60%)
(b) 2 zones must carry everything: 50,000 / 2 = 25,000 /s per zone
    25,000 / 1,500 = 16.7 -> 17 per zone;  3 x 17 = 51 servers

(খ)-তে বাড়তি খরচ ৫১ বনাম ৩৪ — প্রায় ৫০%; দুটি zone হলে প্রতিটিকে পুরো peak টানতে হতো, ৩৪ + ৩৪ = ৬৮। Zone বাড়লে বাড়তি কমে, কিন্তু জটিলতা বাড়ে (ভাগ ৮-এর ৮.৫)। যাচাই: ৩৬টি সার্ভারের পূর্ণ ক্ষমতা ৯০,০০০/s — peak-এর ১.৮ গুণ, ৬০% লক্ষ্যের সাথে সংগত। উত্তর: ৩৪টি + ২ = ৩৬টি; একটি নষ্টে ≈ ৫৭.১%; zone-প্রতি ১৭টি, মোট ৫১টি। ঝালাতে: পর্ব ০৩, ০৫ আর ১৩ (headroom).

৩.৬(কঠিন) (ক) একটি সার্ভিস সেকেন্ডে μ = ৫০০টি অনুরোধ শেষ করতে পারে, কিন্তু আসছে λ = ৬০০টি; queue-এর সীমা নেই, ক্লায়েন্টের timeout D = ১.৫ সেকেন্ড। কত সেকেন্ড পরে নতুন আসা প্রতিটি অনুরোধ timeout ছাড়াবে? (খ) একটি পাতা তিনটি সার্ভিসকে পরপর ডাকে (৩০, ৫০ আর ৪০ ms); একসাথে ডেকে ফল জোড়া দিতে আরও ৫ ms লাগলে নতুন সময় কত?
(a) queue grows by (lambda - mu) = 100 per second
    wait of a new arrival at time t = 100 t / 500 s
    100 t / 500 > 1.5  ->  t > 1.5 x 500 / 100 = 7.5 s
(b) sequential: 30 + 50 + 40 = 120 ms
    parallel  : max(30, 50, 40) + 5 = 55 ms

(ক): ৭.৫ সেকেন্ড পরে সার্ভিস পুরো গতিতে কাজ করেও এমন অনুরোধ সারছে যার ক্লায়েন্ট আগেই চলে গেছে — throughput সর্বোচ্চ, কিন্তু goodput শূন্যের দিকে। প্রতিকার সীমিত queue আর load shedding: বাড়তি ১০০/s-কে দরজাতেই দ্রুত “না” বলা (পর্ব ১৮)। (খ): পরপর call-এ সময় যোগ হয়, একসাথে call-এ সবচেয়ে ধীরটি ঠিক করে — তবে তখন fan-out-এর tail (৩.৩) মাথায় রাখতে হয়। যাচাই: t = ১০ s-এ queue ১,০০০টি, অপেক্ষা ১,০০০ ÷ ৫০০ = ২ s > ১.৫ s — সত্যিই পেরিয়েছে। উত্তর: ৭.৫ সেকেন্ড পরে; ১২০ থেকে ৫৫ ms. ঝালাতে: পর্ব ০৪ আর ১৮।

// Little's law, M/M/1, fan-out tail and server count. Edit the inputs and Run.
const little = (lambda, W) => lambda * W;                 // L = lambda x W
const mm1 = (lambda, S) => {                              // one server, random arrivals
  const rho = lambda * S;
  if (rho >= 1) return { rho, W: Infinity, L: Infinity };
  const W = S / (1 - rho);
  return { rho, W, L: rho / (1 - rho), p99: Math.log(100) * W };
};
const fanout = (p, N) => 1 - Math.pow(1 - p, N);         // P(at least one slow backend)
const servers = (peak, perNode, util) => Math.ceil(peak / (perNode * util));
const ms = x => (x * 1000).toFixed(1) + " ms";

console.log("Little: 2000 req/s x 0.150 s = " + little(2000, 0.150) + " in flight");
console.log("Little: 300 req/s x 0.025 s = " + little(300, 0.025) + " DB connections");
for (const lambda of [25, 40, 45]) {
  const q = mm1(lambda, 0.020);
  console.log("M/M/1 S=20ms lambda=" + lambda + ": rho " + q.rho.toFixed(2) + ", W " + ms(q.W) +
    ", L " + q.L.toFixed(1) + ", p99 ~ " + ms(q.p99));
}
for (const N of [10, 20, 50, 100])
  console.log("fan-out N=" + String(N).padEnd(3) + " p=1%: " + (100 * fanout(0.01, N)).toFixed(1) + "% slow");
console.log("each backend must be fast with prob " + Math.pow(0.99, 1 / 50).toFixed(6) + " (N=50)");
const n = servers(50000, 2500, 0.6);
console.log("servers for 50000/s at 2500/s, 60%: " + n + ", +2 spares = " + (n + 2));
console.log("3 zones, survive 1: " + servers(50000 / 2, 2500, 0.6) + " per zone");

আউটপুট:

Little: 2000 req/s x 0.150 s = 300 in flight
Little: 300 req/s x 0.025 s = 7.5 DB connections
M/M/1 S=20ms lambda=25: rho 0.50, W 40.0 ms, L 1.0, p99 ~ 184.2 ms
M/M/1 S=20ms lambda=40: rho 0.80, W 100.0 ms, L 4.0, p99 ~ 460.5 ms
M/M/1 S=20ms lambda=45: rho 0.90, W 200.0 ms, L 9.0, p99 ~ 921.0 ms
fan-out N=10  p=1%: 9.6% slow
fan-out N=20  p=1%: 18.2% slow
fan-out N=50  p=1%: 39.5% slow
fan-out N=100 p=1%: 63.4% slow
each backend must be fast with prob 0.999799 (N=50)
servers for 50000/s at 2500/s, 60%: 34, +2 spares = 36
3 zones, survive 1: 17 per zone

প্রথম দুই লাইন ৩.১ (৩০০ আর ৭.৫); M/M/1-এর তিন লাইন ৩.৪ (p99 ১৮৪.২, ৪৬০.৫ আর ৯২১.০ ms); fan-out-এর লাইন ৩.৩ (N = ২০-এ ১৮.২%); শেষ তিন লাইন ৩.৫ (৩৬টি, zone-প্রতি ১৭টি)। ρ ≥ ১ হলে mm1() অসীম দেয় — তখন স্থিতিশীল গড়ই থাকে না।

(সহজ) একটি API-তে সেকেন্ডে গড়ে ৫০০টি অনুরোধ আসে, প্রতিটি গড়ে ৮০ ms ভেতরে থাকে। Little-এর সূত্রে গড়ে একসাথে কতগুলো চলছে?

  • ৪০
  • ৪০০
  • ৪০,০০০
  • ৬.২৫

(মাঝারি) একটি অনুরোধ ২০টি backend-এর উত্তরের অপেক্ষা করে; প্রতিটি স্বাধীনভাবে ১% সময় ধীর। কত শতাংশ অনুরোধ অন্তত একটি ধীর উত্তরে আটকায়?

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

(মাঝারি) একটি M/M/1 queue-এ service time ১০ ms, আর সেকেন্ডে ৯০টি অনুরোধ আসে। গড় মোট সময় কত?

  • ১০ ms
  • ১১.১ ms
  • ১০০ ms
  • ১,০০০ ms

(মাঝারি) Peak-এ সেকেন্ডে ২৪,০০০ অনুরোধ; একটি সার্ভার load test-এ ২,০০০ req/s সামলায়; লক্ষ্য utilization ৬০%, আর একটি বাড়তি (N+1). কয়টি সার্ভার?

  • ১২
  • ১৩
  • ২০
  • ২১

৪ · Availability — nines, series-parallel, MTTR আর error budget

সূত্রের কার্ড

Nines: downtime = (1 − A) × সময়কাল; বছর = ৫,২৫,৬০০ মিনিট, ৩০ দিন = ৪৩,২০০ মিনিট। প্রতিটি বাড়তি nine মানে দশ ভাগের এক ভাগ।

গঠন: series A = ΠAi; parallel A = 1 − Π(1 − Ai); k-of-n = Σi≥k C(n, i) ai(1 − a)n−i. ভাগ করা অংশ (zone, rack, config) series-এ আলাদা বসান।

মেরামত: A = MTBF ÷ (MTBF + MTTR); U ≈ MTTR ÷ MTBF; MTTR = টের পাওয়া (MTTD) + কারণ খোঁজা + সারানো + যাচাই।

বাজেট: error budget = (1 − SLO) × জানালা; burn rate = error ratio ÷ (1 − SLO); বাজেট ফুরায় জানালা ÷ burn সময়ে; এক ঘণ্টায় খরচ = burn ÷ ৭২০.

৪.১(সহজ) ৯৯.৯%, ৯৯.৯৫%, ৯৯.৯৯% আর ৯৯.৯৯৯% availability-তে বছরে (৩৬৫ দিন) আর ৩০ দিনের মাসে কত downtime চলে?
year = 525,600 min,  30-day month = 43,200 min
99.9%   : 525.6 min = 8 h 45 min 36 s / yr ;  43.2 min / month
99.95%  : 262.8 min = 4 h 22 min 48 s / yr ;  21.6 min / month
99.99%  :  52.56 min / yr                  ;   4.32 min / month
99.999% :   5.256 min = 5 min 15 s / yr    ;  25.9 s / month

একই শতাংশ, ভিন্ন প্রতিশ্রুতি: “৯৯.৯% মাসিক” প্রতি মাসে ৪৩ মিনিটের সীমা টানে, “৯৯.৯% বার্ষিক”-এ একটি ৮ ঘণ্টার বিপর্যয়ও চলে যায় (পর্ব ৫)। পাঁচ nine-এ মাসে ২৬ সেকেন্ড — মানুষ জেগে ল্যাপটপ খোলার আগেই শেষ, তাই লাগে স্বয়ংক্রিয় failover. যাচাই: প্রতিটি সারি আগেরটির দশ ভাগের এক (৯৯.৯৫% মাঝামাঝি)। উত্তর: টেবিলের মতো — যেমন ৯৯.৯৯%-এ বছরে ≈ ৫২.৬ মিনিট, মাসে ≈ ৪.৩২ মিনিট। ঝালাতে: পর্ব ০৫।

৪.২(মাঝারি) একটি নকশায় পরপর DNS (৯৯.৯৯%), একটি load balancer (৯৯.৯৫%), একটি app server (৯৯%) আর একটি database (৯৯.৯%). (ক) পুরো সেবার availability আর বছরের downtime কত? (খ) LB-কে জোড়া, app server ৩টি (peak-এ অন্তত ২টি লাগে) আর database-কে primary + standby করলে কত? ব্যর্থতা স্বাধীন আর failover তাৎক্ষণিক ধরুন।
(a) 0.9999 x 0.9995 x 0.99 x 0.999 = 0.988417  -> 98.84%, 101.5 h/yr
(b) LB pair      : 1 - 0.0005^2              = 0.99999975
    app 2 of 3   : 0.99^3 + 3 x 0.99^2 x 0.01 = 0.999702
    DB pair      : 1 - 0.001^2               = 0.999999
    total = 0.9999 x 0.99999975 x 0.999702 x 0.999999 = 0.999601
          -> 99.96%, about 3.50 h/yr

শিকল তার দুর্বলতম কড়ির চেয়েও দুর্বল: (ক)-এ ৯৮.৮৪%, অথচ সবচেয়ে খারাপ অংশটিও ৯৯%. (খ)-এ সবচেয়ে বড় unavailability এখন app স্তরের ০.০০০২৯৮ — “৩-এর মধ্যে ২” মানে মাত্র একটি ব্যর্থতা সহ্য হয়; চতুর্থ app server দিলে পরের দুর্বল জায়গা হবে DNS. এটিই availability বাড়ানোর পদ্ধতি: সবচেয়ে বড় U খুঁজে সেটিকে কমানো। যাচাই: ছোট U-এর যোগ — ০.০০০১ + ০.০০০০০০২৫ + ০.০০০২৯৮ + ০.০০০০০১ ≈ ০.০০০৩৯৯, অর্থাৎ ≈ ৯৯.৯৬%. উত্তর: ≈ ৯৮.৮৪% (বছরে ≈ ১০১.৫ ঘণ্টা); redundancy-তে ≈ ৯৯.৯৬% (≈ ৩.৫ ঘণ্টা)। ঝালাতে: পর্ব ০৫।

৪.৩(কঠিন) দুটি একই রকম সার্ভার, প্রতিটি ৯৯.৫%, যেকোনো একটি চালু থাকলেই সেবা চলে। Zone-এর বিদ্যুৎ আর network মিলে availability ৯৯.৯৯%. (ক) “স্বাধীন” ধরে কাগজের হিসাব কত? (খ) দুটিই একই zone-এ হলে? (গ) আলাদা দুটি zone-এ হলে? প্রতিটির বছরের downtime কত?
(a) 1 - 0.005^2 = 0.999975                     -> 13.1 min/yr
(b) zone in SERIES with the pair:
    0.9999 x 0.999975 = 0.999875                -> 65.7 min/yr
(c) each path = zone x server = 0.9999 x 0.995 = 0.9949005
    1 - (1 - 0.9949005)^2 = 0.999974            -> 13.7 min/yr

একই zone-এ দুটি কপি রাখলে কাগজের ১৩ মিনিট আসলে ৬৬ মিনিট — zone একাই series-এ বসে সব খেয়ে ফেলে। এটিই correlated failure হিসাবে আনার কৌশল: ভাগ করা অংশকে আলাদা করে series-এ বসানো (পর্ব ৫)। আলাদা availability zone-এ প্রায় কাগজের মানে ফেরা যায়। যাচাই: (খ)-এর U ≈ ০.০০০১ (zone) + ০.০০০০২৫ (জোড়া) = ০.০০০১২৫ — মেলে। উত্তর: ≈ ৯৯.৯৯৭৫% (১৩.১ মিনিট), ≈ ৯৯.৯৮৭৫% (৬৫.৭ মিনিট), ≈ ৯৯.৯৯৭৪% (১৩.৭ মিনিট)। ঝালাতে: পর্ব ০৫ আর ৫১।

৪.৪(মাঝারি) একটি সেবা গড়ে ৭২০ ঘণ্টা (প্রায় মাসে একবার) পরপর বিকল হয়। এখন MTTR ২ ঘণ্টা: টের পেতে ২০ মিনিট, কারণ খুঁজতে ৩০, সারাতে ৬০, যাচাইয়ে ১০. (ক) Availability আর বছরের downtime কত? (খ) MTTR ১ ঘণ্টা হলে? (গ) ভালো alert-এ টের পাওয়া ২ মিনিট আর এক ক্লিকের rollback-এ সারানো ১০ মিনিট হলে?
(a) A = 720 / (720 + 2)    = 0.997230 -> 24.27 h/yr
(b) A = 720 / (720 + 1)    = 0.998613 -> 12.15 h/yr
(c) MTTR = 2 + 30 + 10 + 10 = 52 min = 0.867 h
    A = 720 / 720.867      = 0.998798 -> 10.53 h/yr

(গ)-তে MTBF একটুও বাড়েনি — একই হারে ব্যর্থতা — অথচ downtime ২৪ থেকে সাড়ে ১০ ঘণ্টা। U ≈ MTTR ÷ MTBF বলে MTTR অর্ধেক করা আর MTBF দ্বিগুণ করা একই ফল দেয়, আর দ্রুত টের পাওয়া ও rollback প্রায়ই অনেক সস্তা (পর্ব ৫ আর ৫৩)। যাচাই: (ক) U ≈ ২ ÷ ৭২২ ≈ ০.০০২৭৭; × ৮,৭৬০ ≈ ২৪.৩ ঘণ্টা — মেলে। উত্তর: ≈ ৯৯.৭২% (২৪.৩ ঘণ্টা); ≈ ৯৯.৮৬% (১২.১৫); ≈ ৯৯.৮৮% (১০.৫ ঘণ্টা)। ঝালাতে: পর্ব ০৫।

// Availability composer: series, parallel, k-of-n, and the yearly downtime. Independence is ASSUMED.
const series = (...a) => a.reduce((x, y) => x * y, 1);
const parallel = (a, n) => 1 - Math.pow(1 - a, n);             // any 1 of n is enough
function kOfN(k, n, a) {                                         // at least k of n must be up
  let s = 0;
  for (let i = k; i <= n; i++) s += comb(n, i) * a ** i * (1 - a) ** (n - i);
  return s;
}
function comb(n, r) { let c = 1; for (let i = 1; i <= r; i++) c = c * (n - r + i) / i; return c; }
function down(A) {                                               // 365-day year
  const min = (1 - A) * 365 * 24 * 60;
  return min >= 120 ? (min / 60).toFixed(2) + " h/yr" : min.toFixed(1) + " min/yr";
}
const show = (name, A) => console.log(name.padEnd(26) + (A * 100).toFixed(5) + "%  " + down(A));
const dns = 0.9999, lb = 0.9995, app = 0.99, db = 0.999;

show("chain, no redundancy", series(dns, lb, app, db));
show("LB pair", parallel(lb, 2));
show("apps: 2 of 3 needed", kOfN(2, 3, app));
show("DB primary + standby", parallel(db, 2));
show("chain with redundancy", series(dns, parallel(lb, 2), kOfN(2, 3, app), parallel(db, 2)));
// a shared zone sits in SERIES with the pair (correlated failure)
const zone = 0.9999, server = 0.995;
show("pair, 'independent'", parallel(server, 2));
show("pair in one zone", series(zone, parallel(server, 2)));
show("pair across 2 zones", parallel(series(zone, server), 2));
for (const mttr of [2, 1, 52 / 60]) show("MTBF 720h MTTR " + mttr.toFixed(2) + "h", 720 / (720 + mttr));

আউটপুট:

chain, no redundancy      98.84166%  101.47 h/yr
LB pair                   99.99997%  0.1 min/yr
apps: 2 of 3 needed       99.97020%  2.61 h/yr
DB primary + standby      99.99990%  0.5 min/yr
chain with redundancy     99.96008%  3.50 h/yr
pair, 'independent'       99.99750%  13.1 min/yr
pair in one zone          99.98750%  65.7 min/yr
pair across 2 zones       99.99740%  13.7 min/yr
MTBF 720h MTTR 2.00h      99.72299%  24.27 h/yr
MTBF 720h MTTR 1.00h      99.86130%  12.15 h/yr
MTBF 720h MTTR 0.87h      99.87977%  10.53 h/yr

প্রথম পাঁচ লাইন ৪.২ (৯৮.৮৪% থেকে ৯৯.৯৬%), পরের তিনটি ৪.৩-এর correlated failure (একই zone-এ ৬৫.৭ মিনিট, আলাদা zone-এ ১৩.৭), শেষ তিনটি ৪.৪-এর MTTR. ক্যালকুলেটর স্বাধীনতা ধরে নেয় — ভাগ করা অংশ নিজে series()-এ বসাতে হয়, যেমন zone.

৪.৫(মাঝারি) SLO: ৩০ দিনে ৯৯.৯% অনুরোধ সফল। (ক) বাজেট কত মিনিটের পূর্ণ বিভ্রাট, আর সেই মাসে ৫০ কোটি অনুরোধ এলে কতটি ব্যর্থ অনুরোধ? (খ) একটি incident-এ ২৫ মিনিট সেবা পুরো বন্ধ ছিল, তারপর ২ ঘণ্টা ৩% অনুরোধ ব্যর্থ হয়েছে (traffic সমান ধরুন)। বাজেটের কত অংশ খরচ হলো, কত বাকি?
(a) budget = (1 - 0.999) x 43,200 min = 43.2 min
    or 0.001 x 5 x 10^8 = 500,000 failed requests
(b) full outage          : 25 min x 100% = 25.0 min-equivalent
    partial (2 h at 3%)  : 120 min x 0.03 = 3.6 min-equivalent
    used = 28.6 / 43.2 = 66.2%;   left = 14.6 min

অনুরোধ-ভিত্তিক SLO-তে বাজেট আসলে ব্যর্থ অনুরোধের সংখ্যা; “মিনিট” হলো পূর্ণ বিভ্রাটের সমতুল্য। আংশিক ত্রুটি তাই তার অনুপাতে খরচ হয় — ২ ঘণ্টার ৩% ত্রুটি মাত্র ৩.৬ মিনিটের সমান। দুই-তৃতীয়াংশ বাজেট শেষ বলে error budget policy অনুযায়ী ঝুঁকিপূর্ণ release ধীর করা যুক্তিসংগত (পর্ব ৫০)। যাচাই: অনুরোধ গুনে — ২ ঘণ্টায় ৫০ কোটি × ১২০ ÷ ৪৩,২০০ ≈ ১৩,৮৮,৮৮৯টি অনুরোধ, তার ৩% ≈ ৪১,৬৬৭টি ব্যর্থ, যা ৫,০০,০০০-এর ৮.৩৩%; আর ৩.৬ ÷ ৪৩.২-ও ৮.৩৩% — দুই পথে মেলে। উত্তর: ৪৩.২ মিনিট বা ৫,০০,০০০টি অনুরোধ; ব্যবহার ≈ ৬৬.২%, বাকি ≈ ১৪.৬ মিনিট। ঝালাতে: পর্ব ০৫ আর ৫০ (SLI).

৪.৬(কঠিন) SLO ৯৯.৯%, ৩০ দিনের জানালা। (ক) এখন error ratio স্থিরভাবে ০.৫% — burn rate কত, বাজেট কত ঘণ্টায় ফুরাবে, এক ঘণ্টায় কত শতাংশ খরচ হয়? (খ) “১ ঘণ্টায় বাজেটের ২% খরচ হলে page” — এর burn rate আর error ratio কত? (গ) burn rate ২ হলে বাজেট কবে ফুরায়?
window = 30 x 24 = 720 h;  budget fraction = 0.001
(a) burn = 0.005 / 0.001 = 5;  empty in 720 / 5 = 144 h = 6 days
    per hour: 5 / 720 = 0.694% of the budget
(b) 2% in 1 h: burn = 0.02 x 720 / 1 = 14.4 -> error ratio 14.4 x 0.1% = 1.44%
(c) burn 2: 720 / 2 = 360 h = 15 days

Burn rate ১ মানে ঠিক জানালার শেষে বাজেট শূন্য; ১৪.৪ মানে ৫০ ঘণ্টায় শূন্য। ১.৪৪% error শুনতে ছোট, কিন্তু এই গতিতে দুই দিনে পুরো মাসের বাজেট শেষ — তাই page. প্রচলিত multiwindow alert দুই জানালায় একসাথে দেখে, যেমন ১ ঘণ্টা আর ৫ মিনিট দুটিতেই ১৪.৪-এর বেশি, যাতে সমস্যা থামলে alert দ্রুত থামে (পর্ব ৫০)। যাচাই: (ক) ৬ দিন × ২৪ = ১৪৪ ঘণ্টা; ১৪৪ × ০.৬৯৪% ≈ ১০০% — মেলে। উত্তর: burn ৫, ১৪৪ ঘণ্টায় (৬ দিন), ঘণ্টায় ≈ ০.৬৯%; burn ১৪.৪ মানে error ≈ ১.৪৪%; ১৫ দিনে। ঝালাতে: পর্ব ৫০।

// Error budget and burn rate for a rolling window. Edit SLO, window and traffic, then Run.
const slo = 0.999, days = 30;
const budgetFrac = 1 - slo;                                     // allowed bad fraction
const windowMin = days * 24 * 60, windowH = days * 24;
console.log("SLO " + (slo * 100) + "% over " + days + " days");
console.log("budget = " + (budgetFrac * windowMin).toFixed(1) + " min of full outage");
const monthly = 5e8;                                            // requests in the window (assumed)
console.log("or " + Math.round(budgetFrac * monthly) + " failed requests out of " + monthly);

// an incident: 25 min fully down + 120 min at 3% errors
const used = 25 + 120 * 0.03;                                   // full-outage-equivalent minutes
const total = budgetFrac * windowMin;
console.log("incident used " + used.toFixed(1) + " min = " + (100 * used / total).toFixed(1) +
  "% of budget, " + (total - used).toFixed(1) + " min left");

console.log("error ratio  burn  empties in   budget per hour");
for (const err of [0.0005, 0.001, 0.002, 0.005, 0.0144, 0.05]) {
  const burn = err / budgetFrac;                                // 1 = exactly on budget
  console.log(((err * 100).toFixed(2) + "%").padStart(11) + burn.toFixed(1).padStart(6) +
    ((windowH / burn).toFixed(1) + " h").padStart(13) + ((100 * burn / windowH).toFixed(2) + "%").padStart(17));
}

আউটপুট:

SLO 99.9% over 30 days
budget = 43.2 min of full outage
or 500000 failed requests out of 500000000
incident used 28.6 min = 66.2% of budget, 14.6 min left
error ratio  burn  empties in   budget per hour
      0.05%   0.5     1440.0 h            0.07%
      0.10%   1.0      720.0 h            0.14%
      0.20%   2.0      360.0 h            0.28%
      0.50%   5.0      144.0 h            0.69%
      1.44%  14.4       50.0 h            2.00%
      5.00%  50.0       14.4 h            6.94%

বাজেট ৪৩.২ মিনিট বা ৫,০০,০০০টি অনুরোধ, incident খেয়েছে ৬৬.২% (৪.৫); টেবিলে ৪.৬-এর burn ৫ (১৪৪ ঘণ্টা) আর ১৪.৪ (৫০ ঘণ্টা, ঘণ্টায় ২%). slo ০.৯৯৯৫ করলে বাজেট অর্ধেক, একই error-এ burn দ্বিগুণ।

(সহজ) ৩০ দিনের মাসে ৯৯.৯৫% availability-র লক্ষ্যে সর্বোচ্চ কত downtime চলে?

  • ২১.৬ মিনিট
  • প্রায় ৪.৩৮ ঘণ্টা
  • ২.১৬ মিনিট
  • ৪৩.২ মিনিট

(সহজ) তিনটি অংশ পরপর (series), প্রতিটির availability ৯৯.৯%. স্বাধীন ব্যর্থতা ধরে পুরোটির availability প্রায় কত?

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

(মাঝারি) SLO ৯৯.৯% (৩০ দিনের জানালা)। Error ratio স্থিরভাবে ০.৪% থাকলে পূর্ণ বাজেট কত দিনে ফুরাবে?

  • ৩০ দিন
  • ৪ দিন
  • ৭.৫ দিন
  • ১২০ দিন

(মাঝারি) একটি সেবার MTBF ৫০০ ঘণ্টা আর MTTR ৩০ মিনিট। Availability প্রায় কত?

  • ৯৯.০%
  • ৯৯.৫%
  • ৯৯.৯৯%
  • প্রায় ৯৯.৯%

৫ · ডেটা আর partitioning — shard, consistent hashing, hot key, cache আর replication lag

সূত্রের কার্ড

Shard: সংখ্যা = max(ডেটা ÷ (node-এর disk × fill-লক্ষ্য), লেখা ÷ (primary-র ক্ষমতা × utilization)); node = shard × replication factor.

সরানো: hash mod N থেকে N + 1-এ সরে N ÷ (N + 1); ring-এ প্রত্যাশিত ১ ÷ (N + 1); নির্দিষ্ট partition-এ শুধু নতুন node-এর ন্যায্য ভাগ। Virtual node-এ ভাগের sd ÷ গড় ≈ √((N − 1) ÷ (NV + 1)) ≈ 1 ÷ √V; লক্ষ্য c হলে V ≈ (N − 1) ÷ (N c²).

Cache: database-এর চাপ = read × (1 − h); গড় latency = tcache + (1 − h) tdb; N-এর একটি cache shard বিকল হলে database-এর চাপ × (1 + h ÷ (N(1 − h))).

Lag: follower-এর হার কম হলে backlog = (লেখার হার − প্রয়োগের হার) × সময়; ধরে ফেলতে লাগে backlog ÷ (প্রয়োগের হার − নতুন লেখার হার).

৫.১(সহজ) (ক) একটি কপিতে মোট ৪০ TB ডেটা; প্রতিটি node-এ ২ TB disk, ৭০%-এর বেশি ভরানো হবে না। লেখার চাপ সেকেন্ডে ৬০,০০০, একটি primary ৫,০০০ সামলায়। কয়টি shard, আর replication factor ৩-এ কয়টি node? (খ) Fan-out ৫০০-র B+-tree-তে ১,০০০ কোটি key রাখতে কয়টি স্তর লাগে?
(a) storage: 40 TB / (2 TB x 0.7) = 28.6 -> 29 shards
    writes : 60,000 / 5,000       = 12 shards
    take the larger: 29 shards;  x 3 replicas = 87 nodes
(b) 500^3 = 1.25 x 10^8;  500^4 = 6.25 x 10^10 >= 10^10  -> 4 levels
    (log_500 10^10 = 3.71, round up)

দুটি আলাদা কারণে shard লাগে — জায়গা আর লেখার হার — আর যেটি বড়, সেটিই উত্তর। এখানে storage-ই ঠিক করছে; লেখার জন্য ১২টিই যথেষ্ট ছিল। (খ)-তে মাত্র ৪টি স্তর মানে প্রতিটি খোঁজায় সর্বোচ্চ ৪টি page — ওপরের স্তরগুলো সাধারণত memory-তে থাকে (পর্ব ১৯)। যাচাই: ২৯ × ১.৪ TB = ৪০.৬ TB ≥ ৪০ TB. উত্তর: ২৯টি shard, ৮৭টি node; ৪টি স্তর। ঝালাতে: পর্ব ১৯ আর ২৩ (sharding).

৫.২(মাঝারি) ১০০ কোটি key, cluster ১০ থেকে ১১ node হবে। (ক) hash mod N-এ কত key সরে? (খ) consistent hashing ring-এ প্রত্যাশিত কত? (গ) ১,০২৪টি নির্দিষ্ট partition ৮টি node-এ (প্রতিটিতে ১২৮টি) আছে; ১০টি node-এ নিলে সবচেয়ে কম কয়টি partition সরাতে হয়?
(a) mod N: moved fraction = N/(N+1) = 10/11 = 90.9% -> 9.09 x 10^8 keys
(b) ring : expected 1/(N+1) = 1/11 = 9.09%           -> 9.09 x 10^7 keys
(c) 1,024 / 10 = 102.4 -> 4 nodes keep 103, 6 nodes hold 102
    give each new node 102 (old nodes keep 4 x 103 + 4 x 102 = 820)
    moved = 2 x 102 = 204 partitions = 19.9%

mod N-এ cluster বড় হওয়াটাই শাস্তি — ৯১% key নতুন জায়গায়, cache-এ ঢল আর database-এ বিপুল কপি। Ring আর নির্দিষ্ট partition দুটিতেই সরে শুধু যতটা নতুন node-এর ন্যায্য ভাগ, আর তার কম সম্ভব নয় (পর্ব ১৬ আর ২৩)। যাচাই: (গ)-তে দুটি নতুন node পুরো ১০ ভাগের ২ ভাগ পায়, ২০% — ২০৪ ÷ ১,০২৪ = ১৯.৯%, মেলে। উত্তর: ≈ ৯০.৯ কোটি key (৯০.৯%); ≈ ৯.০৯ কোটি (৯.০৯%); ২০৪টি partition. ঝালাতে: পর্ব ১৬ আর ২৩।

৫.৩(মাঝারি) ২০টি সার্ভারের ring. (ক) প্রতিটির V = ১, ১০ আর ১০০টি virtual node হলে ভাগের sd ÷ গড় সূত্রে কত? (খ) sd গড়ের ৫%-এর মধ্যে রাখতে V কত লাগবে? (গ) কেন শুধু V বাড়িয়ে একটি hot key-এর সমস্যা মেটে না?
sd/avg = sqrt((N - 1) / (N V + 1)),  N = 20
(a) V = 1  : sqrt(19 / 21)   = 95.1%
    V = 10 : sqrt(19 / 201)  = 30.7%
    V = 100: sqrt(19 / 2001) =  9.7%
(b) V = (N - 1) / (N c^2) = 19 / (20 x 0.0025) = 380   (~ 1/c^2 = 400)

V দশ গুণ করলে ছড়ানো কমে মাত্র √১০ ≈ ৩.১৬ গুণে — ভাগ দশ গুণ সমান করতে বিন্দু লাগে একশো গুণ। (গ): V বাড়ায় key-সংখ্যার ভাগ সমান করে, কিন্তু একটি key একটিই জায়গায় থাকে; তার সব অনুরোধ একই সার্ভারে যায়, যত V-ই থাকুক। Hot key-এর ওষুধ আলাদা (৫.৪)। যাচাই: V = ৩৮০ বসালে √(১৯ ÷ ৭,৬০১) ≈ ০.০৫০০ — ঠিক ৫%. উত্তর: ≈ ৯৫%, ৩১% আর ৯.৭%; V ≈ ৩৮০ (মোটামুটি ৪০০)। ঝালাতে: পর্ব ১৬।

// Keys moved when a cluster grows 10 -> 11 nodes: hash mod N vs a ring with V virtual nodes.
function fnv(s) {                                               // FNV-1a 32-bit + murmur3 finaliser
  let h = 0x811c9dc5;
  for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 0x01000193); }
  h ^= h >>> 16; h = Math.imul(h, 0x85ebca6b); h ^= h >>> 13; h = Math.imul(h, 0xc2b2ae35); h ^= h >>> 16;
  return h >>> 0;
}
function ring(n, V) {
  const pts = [];
  for (let s = 0; s < n; s++) for (let v = 0; v < V; v++) pts.push([fnv("node" + s + "#" + v), s]);
  return pts.sort((a, b) => a[0] - b[0]);
}
function owner(pts, h) {                                        // first point >= h, wrap around
  let lo = 0, hi = pts.length;
  while (lo < hi) { const m = (lo + hi) >> 1; if (pts[m][0] < h) lo = m + 1; else hi = m; }
  return pts[lo % pts.length][1];
}
const K = 100000, keys = [];
for (let i = 0; i < K; i++) keys.push(fnv("key:" + i));
let mod = 0;
for (const h of keys) if (h % 10 !== h % 11) mod++;
console.log("mod N   10->11 moved " + (100 * mod / K).toFixed(1) + "%  (theory 10/11 = 90.9%)");
for (const V of [1, 10, 100, 400]) {
  const a = ring(10, V), b = ring(11, V), load = new Array(11).fill(0);
  let moved = 0;
  for (const h of keys) { const o = owner(b, h); load[o]++; if (owner(a, h) !== o) moved++; }
  const avg = K / 11, sd = Math.sqrt(load.reduce((s, x) => s + (x - avg) ** 2, 0) / 11);
  console.log(("V=" + V).padEnd(6) + "  moved " + (100 * moved / K).toFixed(1) + "%  max/avg " +
    (Math.max(...load) / avg).toFixed(2) + "  sd/avg " + (100 * sd / avg).toFixed(1) + "%");
}

আউটপুট:

mod N   10->11 moved 91.0%  (theory 10/11 = 90.9%)
V=1     moved 0.6%  max/avg 2.58  sd/avg 77.0%
V=10    moved 6.1%  max/avg 1.69  sd/avg 28.0%
V=100   moved 8.9%  max/avg 1.12  sd/avg 6.9%
V=400   moved 8.9%  max/avg 1.06  sd/avg 3.3%

১,০০,০০০টি key-এ mod N সরিয়েছে ৯১.০% (সূত্রে ৯০.৯%). V = ১-এ মাত্র ০.৬% — নতুন node ভাগ্যক্রমে ছোট্ট বৃত্তাংশ পেয়েছে; ১ ÷ ১১ = ৯.১% প্রত্যাশা, প্রতিবারের নিশ্চয়তা নয়। V = ১০০ আর ৪০০-এ সরানো ৮.৯%, max/avg ১.১২ ও ১.০৬, sd/avg সূত্রের মাত্রায়। Hash: FNV-1a, শেষে murmur3-এর mixing — শুধু FNV-1a প্রায় একই রকম নাম ভালো ছড়ায় না।

৫.৪(মাঝারি) একটি cache cluster-এ ৪০টি shard, মোট সেকেন্ডে ৪,০০,০০০ read. একটি জনপ্রিয় key (ধরুন একটি ভাইরাল পোস্ট) একাই সব read-এর ২%. একটি shard সর্বোচ্চ ১৫,০০০ read/s সামলায়। (ক) hot key-এর shard-এ কত চাপ? (খ) key-টিকে ৪টি shard-এ কপি করে এলোমেলোভাবে পড়লে? (গ) app সার্ভারে অল্প TTL-এর local cache ৯০% hot read নিজেই মেটালে?
average per shard = 400,000 / 40 = 10,000 /s
hot key = 0.02 x 400,000 = 8,000 /s;  the rest = 392,000 / 40 = 9,800 per shard
(a) hot shard = 9,800 + 8,000 = 17,800 /s  (1.78 x avg, over 15,000)
(b) 4 copies : 9,800 + 8,000 / 4 = 11,800 /s
(c) L1 90%   : 9,800 + 8,000 x 0.1 = 10,600 /s

গড়ের হিসাবে cluster-এ প্রচুর জায়গা (৪০ × ১৫,০০০ = ৬ লাখ/s), তবু একটি shard ডুবছে — ক্ষমতা ঠিক করে সবচেয়ে ব্যস্ত shard, গড় নয়। প্রতিকার: hot key চেনা (sampling বা top-k), কয়েকটি কপি, অল্প TTL-এর local cache আর একই key-এর অনুরোধ এক করা (পর্ব ৩০)। Local cache-এর দাম staleness: TTL ২ সেকেন্ড হলে like-সংখ্যা ২ সেকেন্ড পুরোনো থাকতে পারে। যাচাই: (ক)-এ মোট = ৩৯ × ৯,৮০০ + ১৭,৮০০ = ৪,০০,০০০ — মেলে। উত্তর: ১৭,৮০০/s (সীমা ছাড়ায়); ১১,৮০০/s; ১০,৬০০/s. ঝালাতে: পর্ব ২৩ আর ৩০।

৫.৫(মাঝারি) সেকেন্ডে ১,০০,০০০ read; cache-এ ১ ms, database-এ ২০ ms. (ক) hit ratio ৯০%, ৯৫% আর ৯৯%-এ database-এর চাপ আর গড় latency কত? (খ) h = ৯৮%, cache ৮টি shard-এ ভাগ — একটি shard বিকল হলে database-এর চাপ কত গুণ? (গ) পুরো cache খালি (cold) হলে?
(a) DB = 100,000 x (1 - h);  avg = 1 + (1 - h) x 20 ms
    h 90%: 10,000 /s, 3.0 ms   h 95%: 5,000 /s, 2.0 ms   h 99%: 1,000 /s, 1.2 ms
(b) before: 100,000 x 0.02 = 2,000 /s
    after : 2,000 x 7/8 + 100,000 / 8 = 1,750 + 12,500 = 14,250 /s
    x 7.125  (= 1 + h / (N (1 - h)) = 1 + 0.98 / 0.16)
(c) cold: 100,000 /s = 50 x the normal 2,000

Hit ratio ৯৫ থেকে ৯৯ — চার শতাংশ বিন্দু — অথচ database-এর চাপ পাঁচ ভাগের এক ভাগ, কারণ চাপ ঠিক করে miss. উল্টো দিকে, cache যত ভালো, তার একটি shard হারানো তত বিপজ্জনক: h বেশি হলে database ছোট করে কেনা হয়, অথচ একটি shard পড়লেই চাপ সাত গুণ। তাই cache-কেও capacity plan-এ রাখতে হয় — replica, ধীরে traffic ফেরানো, coalescing (পর্ব ২৮ আর ৩০)। যাচাই: (খ)-তে বিকল shard-এর ভাগ ১২,৫০০/s পুরোটাই database-এ, বাকি ৭ ভাগে আগের মতো ২% miss — যোগ ১৪,২৫০. উত্তর: (১০,০০০/s, ৩ ms), (৫,০০০, ২ ms), (১,০০০, ১.২ ms); ≈ ৭.১২৫ গুণ; ৫০ গুণ। ঝালাতে: পর্ব ২৮, ২৯ আর ৩০ (hit ratio).

৫.৬(কঠিন) Asynchronous replication: ১০ মিনিটের একটি ঢেউয়ে leader সেকেন্ডে ৫,০০০টি পরিবর্তন লেখে, কিন্তু follower সর্বোচ্চ ৪,০০০টি গ্রহণ ও প্রয়োগ করতে পারে (network আর disk মিলিয়ে)। ঢেউয়ের পরে লেখা নামে সেকেন্ডে ২,০০০-এ। (ক) ঢেউয়ের শেষে backlog কত, আর follower কত সেকেন্ড পেছনে? (খ) কত সময়ে ধরে ফেলবে? (গ) ঠিক তখন leader মরলে আর follower-কে promote করলে কী হারাতে পারে?
(a) backlog = (5,000 - 4,000) x 600 s = 600,000 changes
    after t s the follower has applied 4,000 t = what the leader wrote by 4,000 t / 5,000 = 0.8 t
    lag = t - 0.8 t = 0.2 x 600 = 120 s behind
(b) catch-up = 600,000 / (4,000 - 2,000) = 300 s
(c) up to the last ~120 s of writes (600,000 changes) not yet on the follower

Lag সময়ের মাপে বলা ভালো — “follower ১২০ সেকেন্ড পেছনে” — কারণ সেটিই সরাসরি বলে, read replica থেকে কত পুরোনো ডেটা আসবে আর failover-এ কত সময়ের লেখা হারাতে পারে (RPO, পর্ব ৫১)। ধরে ফেলার সময় ঠিক করে বাড়তি ক্ষমতা (৪,০০০ − ২,০০০), পুরো ক্ষমতা নয় — ব্যাংকের কাউন্টারে ভিড় সরে শুধু ক্যাশিয়ারের অলস সময় দিয়ে। যাচাই: ৩০০ সেকেন্ডে follower ১২ লাখ প্রয়োগ করে, ওই সময়ে নতুন লেখা ৬ লাখ, backlog ৬ লাখ — শূন্যে নামে। উত্তর: ৬,০০,০০০টি, ১২০ সেকেন্ড পেছনে; ৩০০ সেকেন্ড; শেষ প্রায় ১২০ সেকেন্ডের লেখা। ঝালাতে: পর্ব ২২ আর ৫১।

// Cache hit ratio -> database load and latency; a cache shard failure; replication lag.
const reads = 100000, tCache = 1, tDb = 20;                    // reads/s; ms (assumed)
console.log("hit    DB reads/s   avg latency");
for (const h of [0.90, 0.95, 0.98, 0.99]) {
  const db = reads * (1 - h);
  const avg = tCache + (1 - h) * tDb;                           // a miss also pays the cache lookup
  console.log((h * 100).toFixed(0).padStart(3) + "%" + Math.round(db).toString().padStart(12) +
    (avg.toFixed(2) + " ms").padStart(14));
}
// one of N cache shards dies: its share of reads all go to the database
const h = 0.98, N = 8;
const before = reads * (1 - h);
const after = reads * (1 - h) * (N - 1) / N + reads / N;
console.log("1 of " + N + " shards down: DB " + Math.round(before) + " -> " + Math.round(after) +
  "/s (x" + (after / before).toFixed(3) + ", formula 1 + h/(N(1-h)) = " + (1 + h / (N * (1 - h))).toFixed(3) + ")");
console.log("whole cache cold: DB gets " + reads + "/s, x" + (reads / before).toFixed(0));

// leader 5000 writes/s for 600 s; follower can take at most 4000/s; then leader drops to 2000/s
const spike = 600, wLead = 5000, wFol = 4000, after2 = 2000;
const backlog = (wLead - wFol) * spike;
const lagSec = spike - (wFol * spike) / wLead;                  // follower is at the leader's time wFol*t/wLead
console.log("backlog " + backlog + " changes, follower " + lagSec.toFixed(0) + " s behind");
console.log("catch-up after the spike: " + (backlog / (wFol - after2)).toFixed(0) + " s");

আউটপুট:

hit    DB reads/s   avg latency
 90%       10000       3.00 ms
 95%        5000       2.00 ms
 98%        2000       1.40 ms
 99%        1000       1.20 ms
1 of 8 shards down: DB 2000 -> 14250/s (x7.125, formula 1 + h/(N(1-h)) = 7.125)
whole cache cold: DB gets 100000/s, x50
backlog 600000 changes, follower 120 s behind
catch-up after the spike: 300 s

টেবিল ৫.৫(ক)-এর সাথে মেলে; shard বিকলে গণনা আর সূত্র দুটিই ৭.১২৫, cold cache-এ ৫০ গুণ; শেষ দুই লাইন ৫.৬ (৬ লাখ, ১২০ s, ৩০০ s). N ৩২ করলে একটি shard হারানোর ধাক্কা ≈ ২.৫৩ গুণে নামে।

(সহজ) Key রাখা হয় hash(key) mod N নিয়মে। Cluster ৪ থেকে ৫ node করলে প্রায় কত শতাংশ key-এর জায়গা বদলায়?

  • ৮০%
  • ২০%
  • ২৫%
  • ১০০%

(সহজ) সেকেন্ডে ৪০,০০০ read আসে, cache-এর hit ratio ৯৫%. Database প্রতি সেকেন্ডে কতটি read পায়?

  • ৩৮,০০০
  • ২,০০০
  • ৪০০
  • ৪,০০০

(মাঝারি) Consistent hashing ring-এ প্রতিটি সার্ভারের ভাগের sd গড়ের প্রায় ১০%-এর মধ্যে রাখতে প্রতি সার্ভারে মোটামুটি কয়টি virtual node লাগে (sd ÷ গড় ≈ 1 ÷ √V ধরুন)?

  • ১০
  • ১,০০০
  • ১০০
  • ১০,০০০

(মাঝারি) একটি কপিতে ৩০ TB ডেটা; প্রতিটি node-এ ৪ TB disk, ৭৫%-এর বেশি ভরানো হবে না; replication factor ৩. লেখার চাপ সমস্যা নয়। মোট কয়টি node?

  • ৮
  • ১০
  • ২৪
  • ৩০

৬ · Distributed systems-এর সংখ্যা — quorum, Raft, gossip, sketch আর ID-space

সূত্রের কার্ড

Quorum: R + W > N হলে যেকোনো লেখা আর পড়ার দল অন্তত W + R − N টি replica-তে মেলে; লেখা চলে N − W টি বন্ধ থাকলেও, পড়া N − R টি বন্ধ থাকলেও। Raft: majority ⌊n/2⌋ + 1, সহ্য করে ⌊(n − 1)/2⌋ টি crash.

Gossip: push gossip-এ খবর সবার কাছে প্রায় log2 n + ln n রাউন্ডে; all-to-all heartbeat-এ বার্তা n(n − 1), SWIM-এ প্রায় 2n প্রতি period.

Sketch: Bloom m = −n ln p ÷ (ln 2)², k = (m/n) ln 2; count-min w = ⌈e/ε⌉, d = ⌈ln(1/δ)⌉, বাড়তি ≤ εN; HyperLogLog-এর ভুল ≈ 1.04 ÷ √m, m = 2p টি register.

ID: M টি সম্ভাব্য মান থেকে n টি এলোমেলো — প্রত্যাশিত সংঘর্ষ-জোড়া ≈ n² ÷ 2M, ৫০% সম্ভাবনা n ≈ 1.177√M (birthday). Snowflake: ৪১ bit সময় (ms), ১০ bit worker, ১২ bit sequence.

৬.১(সহজ) Leaderless store-এ প্রতিটি key-এর N টি replica. (ক) N = ৩-এ (W, R) = (২, ২), (৩, ১) আর (১, ৩)-এ overlap কত, আর লেখা ও পড়া কয়টি replica বন্ধ থাকলেও চলে? (খ) N = ৫-এ (৩, ৩) হলে? (গ) (W, R) = (১, ১) কেন ঝুঁকিপূর্ণ?
overlap = W + R - N;  write survives N - W down;  read survives N - R down
(a) N=3 (2,2): overlap 1, write ok with 1 down, read ok with 1 down
        (3,1): overlap 1, write ok with 0 down, read ok with 2 down
        (1,3): overlap 1, write ok with 2 down, read ok with 0 down
(b) N=5 (3,3): overlap 1, both ok with 2 down
(c) (1,1): 1 + 1 = 2, not > 3 -> a read may miss the latest write entirely

(২, ২) জনপ্রিয় কারণ দুই দিকেই একটি করে ব্যর্থতা সহ্য হয়; (৩, ১) পড়াকে সস্তা করে কিন্তু একটি replica বন্ধ হলেই লেখা থামে। মনে রাখুন, overlap থাকলেই linearizable নয় — চলমান লেখা, আংশিক ব্যর্থ লেখা, sloppy quorum আর LWW-এ পুরোনো মান আসতে পারে (পর্ব ৪১)। যাচাই: প্রমাণের লাইন — দুটি দলের মিলন ≤ N, তাই ছেদ ≥ W + R − N ≥ ১. উত্তর: টেবিলের মতো; N = ৫, (৩, ৩)-এ দুই দিকেই ২টি; (১, ১)-এ overlap-এর নিশ্চয়তা নেই। ঝালাতে: পর্ব ৪১ (quorum intersection).

৬.২(মাঝারি) (ক) ৩, ৪, ৫ আর ৭ node-এর Raft cluster-এ majority কত আর কয়টি crash সহ্য হয়? ৪টি node কেন ৩-এর চেয়ে ভালো নয়? (খ) ৫টি node তিনটি region-এ: A-তে ২, B-তে ২, C-তে ১. Round trip A–B ৩০ ms, A–C ৮০ ms, B–C ৭০ ms, region-এর ভেতরে প্রায় ১ ms. Leader A-তে হলে একটি commit-এ নূন্যতম কত সময়? Leader C-তে হলে? একটি পুরো region হারালে cluster চলবে কি?
(a) n : majority  tolerated
    3 :    2         1
    4 :    3         1     (one more machine, no more safety)
    5 :    3         2
    7 :    4         3
(b) commit needs 3 of 5 (leader counts itself) = 2 more acks
    leader in A: A-peer ~1 ms, then nearest remote = B at 30 ms -> ~30 ms
    leader in C: acks from B at 70 ms, B at 70 ms              -> ~70 ms
    lose A (2) or B (2): 3 left = majority -> new leader, carries on
    lose C (1): 4 left -> carries on

জোড় সংখ্যার cluster-এ majority বাড়ে, কিন্তু সহ্যক্ষমতা বাড়ে না — দাম বাড়ে, নিরাপত্তা নয়। তাই ৩ বা ৫। (খ)-তে দেখুন, প্রতিটি commit majority-র সাথে একটি round trip, তাই leader কোথায় বসে তা লেখার latency ঠিক করে; leader A বা B-তে রাখা ভালো (পর্ব ৪২)। ২-২-১ বিন্যাস যেকোনো একটি region হারানো সহ্য করে — ৩-২ হলে বড় region-টি হারালে majority থাকত না। যাচাই: দুটি majority সবসময় অন্তত একজনে মেলে (৩ + ৩ > ৫), তাই এক term-এ দুজন leader হতে পারেন না, আর commit হওয়া entry পরের যেকোনো majority-তেও থাকে। উত্তর: (২, ১), (৩, ১), (৩, ২), (৪, ৩); leader A-তে ≈ ৩০ ms, C-তে ≈ ৭০ ms; যেকোনো একটি region হারালেও চলবে। ঝালাতে: পর্ব ৪২।

৬.৩(মাঝারি) একটি cluster-এ n = ১,০০০ আর ১০,০০০ node. (ক) push gossip-এ প্রতি রাউন্ড ১ সেকেন্ড হলে একটি খবর মোটামুটি কত সেকেন্ডে সবার কাছে পৌঁছায় (log2 n + ln n ধরে)? (খ) n = ১,০০০-এ সবাই সবাইকে প্রতি সেকেন্ডে heartbeat পাঠালে কত বার্তা, আর SWIM-এ প্রায় কত?
(a) n = 1,000 : log2 1000 + ln 1000 = 9.97 + 6.91 = 16.9 rounds ~ 17 s
    n = 10,000: 13.29 + 9.21 = 22.5 rounds ~ 23 s
(b) all-to-all: n (n - 1) = 1,000 x 999 = 999,000 messages per second
    SWIM      : ~ 2n = 2,000 (one ping + one ack per member per period)

Node দশ গুণ হলে রাউন্ড বাড়ে মাত্র ৫–৬টি — লগারিদমের জাদু। প্রথম log2 n রাউন্ডে জানা লোক মোটামুটি দ্বিগুণ হয়, তারপর অজানা অংশ প্রতি রাউন্ডে প্রায় e গুণ কমে — সেটিই ln n অংশ (পর্ব ৪৪)। All-to-all heartbeat বার্তায় n² বাড়ে, তাই বড় cluster-এ অচল। যাচাই: ২১০ = ১,০২৪ ≈ ১,০০০, তাই log2 ১,০০০ ≈ ১০ — মেলে। উত্তর: ≈ ১৭ আর ≈ ২৩ সেকেন্ড; ৯,৯৯,০০০ বনাম ≈ ২,০০০ বার্তা। ঝালাতে: পর্ব ৪৪।

// Quorum table for N replicas, write/read availability, and Raft majority sizes.
function table(N) {
  console.log("N=" + N + "   W R  overlap  write ok with  read ok with  R+W>N?");
  for (let W = 1; W <= N; W++) for (let R = 1; R <= N; R++) {
    if (W + R !== N + 1 && !(W === N && R === N)) continue;     // minimal overlaps + (N, N)
    console.log("      " + W + " " + R + String(Math.max(0, W + R - N)).padStart(8) +
      (N - W + " down").padStart(15) + (N - R + " down").padStart(14) + (W + R > N ? "  yes" : "  no"));
  }
}
table(3);
table(5);
// probability that at least W of N replicas (each up with prob a) answer
function atLeast(k, n, a) {
  let s = 0, c = 1;
  for (let i = 0; i <= n; i++) {
    if (i >= k) s += c * a ** i * (1 - a) ** (n - i);
    c = c * (n - i) / (i + 1);
  }
  return s;
}
for (const W of [1, 2, 3]) console.log("N=3, replica 99.9%: W=" + W + " write availability " +
  (100 * atLeast(W, 3, 0.999)).toFixed(7) + "%");
console.log("Raft size  majority  crashes tolerated");
for (const n of [3, 4, 5, 6, 7])
  console.log(String(n).padStart(9) + String(Math.floor(n / 2) + 1).padStart(10) + String(Math.floor((n - 1) / 2)).padStart(19));

আউটপুট:

N=3   W R  overlap  write ok with  read ok with  R+W>N?
      1 3       1         2 down        0 down  yes
      2 2       1         1 down        1 down  yes
      3 1       1         0 down        2 down  yes
      3 3       3         0 down        0 down  yes
N=5   W R  overlap  write ok with  read ok with  R+W>N?
      1 5       1         4 down        0 down  yes
      2 4       1         3 down        1 down  yes
      3 3       1         2 down        2 down  yes
      4 2       1         1 down        3 down  yes
      5 1       1         0 down        4 down  yes
      5 5       5         0 down        0 down  yes
N=3, replica 99.9%: W=1 write availability 99.9999999%
N=3, replica 99.9%: W=2 write availability 99.9997002%
N=3, replica 99.9%: W=3 write availability 99.7002999%
Raft size  majority  crashes tolerated
        3         2                  1
        4         3                  1
        5         3                  2
        6         4                  2
        7         4                  3

দুটি টেবিল ৬.১-এর উত্তর; মাঝের তিন লাইনে quorum-এর দাম — replica ৯৯.৯% হলে W = ৩-এ লেখার availability ৯৯.৭০%, W = ২-এ ৯৯.৯৯৯৭% (ভাগ ৮-এ লাগবে); শেষ টেবিল ৬.২(ক)।

৬.৪(মাঝারি) ১০ কোটি (১০৮) URL-এর একটি “আগে দেখা হয়েছে কি” Bloom filter. (ক) ১% আর ০.১% false positive-এ প্রতি key-এ কত bit, মোট কত MB, কয়টি hash? (খ) প্রতি key-এ ঠিক ১০ bit আর k = ৭ হলে false positive কত? (গ) URL গড়ে ২০০ byte — exact set-এ কত লাগত?
(a) bits/key = -ln p / (ln 2)^2;  k = bits/key x ln 2
    p = 1%  : 9.59 bit/key -> 9.59 x 10^8 bit = 119.8 MB, k = 6.64 -> 7
    p = 0.1%: 14.38 bit/key -> 179.7 MB, k = 9.97 -> 10
(b) p = (1 - e^(-7/10))^7 = (1 - 0.4966)^7 = 0.0082 -> 0.82%
(c) 10^8 x 200 B = 20 GB (before any hash-table overhead)

ভুল দশ গুণ কমাতে প্রতি key-এ মাত্র প্রায় ৪.৮ bit বেশি লাগে, আর key-এর আকার কোনো ভূমিকা রাখে না — ২০০ byte-এর URL আর ৮ byte-এর id দুটোরই ৯.৬ bit. দাম: “আছে” উত্তর মাঝে মাঝে মিথ্যা, তাই চূড়ান্ত সিদ্ধান্তের আগে আসল store-এ একবার মিলিয়ে নিতে হয় — false positive মানে সামান্য বাড়তি কাজ, false negative কখনো নয় (পর্ব ৪৫)। যাচাই: ১২০ MB বনাম ২০ GB — প্রায় ১৬৭ গুণ কম memory. উত্তর: ≈ ৯.৬ bit, ≈ ১২০ MB, ৭টি hash; ≈ ১৪.৪ bit, ≈ ১৮০ MB, ১০টি; ≈ ০.৮২%; ২০ GB. ঝালাতে: পর্ব ৪৫।

৬.৫(মাঝারি) (ক) দিনে ১০০ কোটি event-এ প্রতিটি key-এর গণনা চাই, বাড়তি ভুল ≤ εN, ε = ০.০০১, সম্ভাবনা ৯৯% (δ = ০.০১)। Count-min sketch-এর w, d আর memory (৪ byte counter)? (খ) আলাদা ব্যবহারকারী গুনতে HyperLogLog-এ p = ১৪ হলে ভুল আর memory (৬ bit register)? ভুল ২%-এর মধ্যে চাইলে সবচেয়ে ছোট p কত?
(a) w = ceil(e / 0.001) = 2,719;  d = ceil(ln 100) = ceil(4.61) = 5
    2,719 x 5 = 13,595 counters x 4 B = 54.4 KB
    overcount <= 0.001 x 10^9 = 10^6 with probability 0.99
(b) m = 2^14 = 16,384;  error = 1.04 / 128 = 0.81%;  16,384 x 6 bit = 12 KiB
    2%: m >= (1.04 / 0.02)^2 = 2,704 -> p = 12 (m = 4,096, error 1.625%)

Count-min কখনো কম দেখায় না, শুধু বেশি — তাই “সবচেয়ে বেশি চাওয়া জিনিস” খোঁজায় চলে, কিন্তু বিলের মতো নির্ভুল গণনায় নয়। লক্ষ করুন, ১০ লাখের বাড়তি ভুল মোট N-এর তুলনায়; একটি বিরল key-এর ১০০টি গণনার পাশে তা বিশাল, তাই CMS কাজে লাগে বড় গণনার key-এ (heavy hitters). HyperLogLog ১০০ কোটি আলাদা id-ও ১২ KiB-এ গোনে, যেখানে exact set-এ শুধু id-ই ৮ GB (পর্ব ৪৫)। যাচাই: √১৬,৩৮৪ = ১২৮, আর ১.০৪ ÷ ১২৮ = ০.০০৮১২৫. উত্তর: w = ২,৭১৯, d = ৫, ≈ ৫৪.৪ KB; ≈ ০.৮১%, ১২ KiB; p = ১২. ঝালাতে: পর্ব ৪৫।

// Sizing Bloom filter, count-min sketch and HyperLogLog. Edit n, p, eps, delta and Run.
const MB = 1e6, KB = 1e3;
function bloom(n, p) {
  const m = Math.ceil(-n * Math.log(p) / Math.LN2 ** 2);         // bits
  const k = Math.round((m / n) * Math.LN2);
  const real = (1 - Math.exp(-k * n / m)) ** k;                  // FP rate with integer k
  return { bitsPerKey: m / n, mb: m / 8 / MB, k, real };
}
for (const p of [0.01, 0.001]) {
  const b = bloom(1e8, p);
  console.log("Bloom n=1e8 p=" + p + ": " + b.bitsPerKey.toFixed(2) + " bit/key, " + b.mb.toFixed(1) +
    " MB, k=" + b.k + ", FP with that k " + (100 * b.real).toFixed(3) + "%");
}
const fp = (bitsPerKey, k) => (1 - Math.exp(-k / bitsPerKey)) ** k;
console.log("10 bit/key, k=7: FP " + (100 * fp(10, 7)).toFixed(2) + "%");

const eps = 0.001, delta = 0.01, N = 1e9;
const w = Math.ceil(Math.E / eps), d = Math.ceil(Math.log(1 / delta));
console.log("CMS eps=" + eps + " delta=" + delta + ": w=" + w + " d=" + d + ", " + w * d +
  " counters = " + (w * d * 4 / KB).toFixed(1) + " KB (4-byte), overcount <= " + eps * N + " w.p. " + (1 - delta));

console.log("HLL p   registers  std error  memory (6-bit)");
for (const p of [10, 12, 14, 16]) {
  const m = 2 ** p;
  console.log(String(p).padStart(5) + String(m).padStart(11) + ((104 / Math.sqrt(m)).toFixed(3) + "%").padStart(11) +
    ((m * 6 / 8 / 1024).toFixed(2) + " KiB").padStart(15));
}
console.log("exact set of 1e9 ids x 8 bytes = " + (1e9 * 8 / 1e9) + " GB before any overhead");

আউটপুট:

Bloom n=1e8 p=0.01: 9.59 bit/key, 119.8 MB, k=7, FP with that k 1.004%
Bloom n=1e8 p=0.001: 14.38 bit/key, 179.7 MB, k=10, FP with that k 0.100%
10 bit/key, k=7: FP 0.82%
CMS eps=0.001 delta=0.01: w=2719 d=5, 13595 counters = 54.4 KB (4-byte), overcount <= 1000000 w.p. 0.99
HLL p   registers  std error  memory (6-bit)
   10       1024     3.250%       0.75 KiB
   12       4096     1.625%       3.00 KiB
   14      16384     0.813%      12.00 KiB
   16      65536     0.406%      48.00 KiB
exact set of 1e9 ids x 8 bytes = 8 GB before any overhead

Bloom-এর লাইন ৬.৪-এর ৯.৫৯ আর ১৪.৩৮ bit, ১১৯.৮ আর ১৭৯.৭ MB; পূর্ণসংখ্যা k-তে আসল FP ১.০০৪% আর ০.১০০%; ১০ bit-এ ০.৮২%. CMS আর HLL ৬.৫-এর সাথে মেলে। একক লক্ষ করুন: MB আর KB দশমিকে, HLL-এর register KiB-এ।

৬.৬(কঠিন) একটি কাল্পনিক URL shortener এলোমেলো base62 code দেয়। (ক) ৭ অক্ষরে কয়টি সম্ভাব্য code? ১ কোটি link-এ প্রত্যাশিত কয়টি সংঘর্ষ, আর অন্তত একটির সম্ভাবনা কত? (খ) কতগুলো link-এ প্রথম সংঘর্ষের সম্ভাবনা ৫০%? (গ) এলোমেলো ৬৪-bit ID-তে ১০০ কোটি ID দিলে?
(a) M = 62^7 = 3,521,614,606,208 (~3.52 x 10^12)
    expected pairs = n^2 / 2M = 10^14 / 7.04 x 10^12 = 14.2
    P(at least one) = 1 - e^(-14.2) ~ 1  (practically certain)
(b) n50 = sqrt(2 ln 2 x M) = 1.177 x sqrt(M) = 2.21 x 10^6 links
(c) M = 2^64 = 1.84 x 10^19;  10^18 / 3.69 x 10^19 = 0.027 -> P ~ 2.7%

৩.৫ লাখ কোটি জায়গা শুনতে অফুরন্ত, অথচ মাত্র ২২ লাখ link-এই সংঘর্ষের সম্ভাবনা অর্ধেক — কারণ প্রতিটি নতুন code আগের সবগুলোর সাথে মেলার সুযোগ পায়, জোড়ার সংখ্যা n²-এর মতো বাড়ে। তাই এলোমেলো code-এ প্রতিটি লেখা শর্তসাপেক্ষ (“না থাকলে তবেই লেখা”) আর মিললে আবার চেষ্টা; অথবা counter + base62, যেখানে সংঘর্ষই নেই কিন্তু code অনুমেয় (পর্ব ৫৪)। যাচাই: √M ≈ ১.৮৮ × ১০৬; × ১.১৭৭ ≈ ২.২১ × ১০৬ — পর্ব ৫৪-এর ২২,০৯,৫২৪-এর সাথে মেলে। উত্তর: ≈ ৩.৫২ × ১০১২, প্রত্যাশিত ≈ ১৪টি, প্রায় নিশ্চিত; ≈ ২২ লাখ link; প্রায় ২.৭%. ঝালাতে: পর্ব ২৩ আর ৫৪।

৬.৭(মাঝারি) Snowflake-ধাঁচের ৬৪-bit ID: ১ bit চিহ্ন, ৪১ bit সময় (একটি নির্দিষ্ট epoch থেকে millisecond), ১০ bit worker, ১২ bit sequence. (ক) সময়ের ঘর কত বছর চলে? Epoch ২০২০ হলে কবে ফুরায়? (খ) একটি worker সেকেন্ডে কতটি ID দিতে পারে, পুরো cluster কত? (গ) একটি worker-এর ঘড়ি ৫ ms পেছালে কী করা উচিত?
(a) 2^41 ms = 2.199 x 10^12 ms = 2.199 x 10^9 s = 69.7 years
    epoch 2020 -> runs out around 2089
(b) per worker: 2^12 = 4,096 per ms = 4,096,000 per s
    workers: 2^10 = 1,024 -> cluster 4.19 x 10^9 per s
(c) refuse or wait 5 ms; never reuse an old timestamp (duplicates)

এক ms-এ ৪,০৯৬টির বেশি লাগলে worker পরের ms-এর অপেক্ষা করে। ঘড়ি পেছালে (NTP-এর সংশোধনে, পর্ব ৩৯) একই সময় আবার এলে একই ID বেরোনোর ঝুঁকি — তাই অপেক্ষা বা প্রত্যাখ্যান। ID সময়ক্রমে বাড়ে বলে index-এ ভালো, কিন্তু base62-এ ১১ অক্ষর — ছোট link-এর জন্য লম্বা (পর্ব ২৩ আর ৫৪)। যাচাই: ২৪১ ≈ ২.২ × ১০১২; ÷ (১,০০০ × ৮৬,৪০০ × ৩৬৫.২৫) ≈ ৬৯.৭. উত্তর: ≈ ৬৯.৭ বছর, ২০৮৯ সালের দিকে; ৪০,৯৬,০০০/s, cluster-এ ≈ ৪.১৯ × ১০৯/s; অপেক্ষা বা প্রত্যাখ্যান। ঝালাতে: পর্ব ২৩ আর ৩৯।

// ID space: birthday bound for random codes, and Snowflake-style 64-bit ID capacity.
const expected = (n, M) => n * n / (2 * M);                     // expected colliding pairs
const pAny = (n, M) => 1 - Math.exp(-expected(n, M));           // P(at least one)
const half = M => Math.sqrt(2 * Math.LN2 * M);                  // n for a 50% chance
const spaces = [["base62, 6 chars", 62 ** 6], ["base62, 7 chars", 62 ** 7], ["random 64-bit", 2 ** 64]];
for (const [name, M] of spaces) {
  console.log(name.padEnd(16) + "M=" + M.toExponential(3) + "  50% at n=" + Math.round(half(M)).toExponential(3));
  for (const n of [1e7, 1e9])
    console.log("".padEnd(16) + "n=" + n.toExponential(0) + ": expected pairs " + expected(n, M).toPrecision(3) +
      ", P(any) " + pAny(n, M).toFixed(4));
}
// Snowflake layout: 1 sign bit | 41 bits ms since epoch | 10 bits worker | 12 bits sequence
const msBits = 41, workerBits = 10, seqBits = 12;
const years = 2 ** msBits / 1000 / 86400 / 365.25;
console.log("time field lasts " + years.toFixed(1) + " years; epoch 2020 runs out in " + Math.floor(2020 + years));
console.log("workers " + 2 ** workerBits + ", per worker " + 2 ** seqBits + "/ms = " + 2 ** seqBits * 1000 + "/s");
console.log("whole cluster " + (2 ** seqBits * 1000 * 2 ** workerBits).toExponential(3) + " ids/s");
// shortest base62 code for C codes with at most 1% of the space used
const need = (C, fill) => Math.ceil(Math.log(C / fill) / Math.log(62));
console.log("1.825e10 links, keep fill <= 1%: " + need(1.825e10, 0.01) + " chars");

আউটপুট:

base62, 6 chars M=5.680e+10  50% at n=2.806e+5
                n=1e+7: expected pairs 880, P(any) 1.0000
                n=1e+9: expected pairs 8.80e+6, P(any) 1.0000
base62, 7 chars M=3.522e+12  50% at n=2.210e+6
                n=1e+7: expected pairs 14.2, P(any) 1.0000
                n=1e+9: expected pairs 1.42e+5, P(any) 1.0000
random 64-bit   M=1.845e+19  50% at n=5.057e+9
                n=1e+7: expected pairs 0.00000271, P(any) 0.0000
                n=1e+9: expected pairs 0.0271, P(any) 0.0267
time field lasts 69.7 years; epoch 2020 runs out in 2089
workers 1024, per worker 4096/ms = 4096000/s
whole cluster 4.194e+9 ids/s
1.825e10 links, keep fill <= 1%: 7 chars

৭ অক্ষরে ৫০% সংঘর্ষ ২.২১ × ১০৬-এ, ১ কোটিতে প্রত্যাশিত ১৪.২ (৬.৬); ৬ অক্ষরে ৮৮০টি। ৬৪-bit-এ ১০০ কোটিতে ২.৬৭%. Snowflake-এর লাইন ৬.৭-এর সাথে মেলে। P(any) ১.০০০০ মানে ১-এর খুব কাছে, ঠিক ১ নয়।

(সহজ) N = ৫টি replica, W = ৩, R = ৩. কয়টি replica বন্ধ থাকলেও লেখা আর পড়া দুটিই সফল হয়?

  • দুটিতেই ২টি
  • দুটিতেই ১টি
  • দুটিতেই ৩টি
  • শুধু পড়ায় ২টি, লেখায় ০

(সহজ) ৬টি node-এর একটি Raft cluster সর্বোচ্চ কয়টি node-এর crash সহ্য করে চলতে পারে?

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

(মাঝারি) ১% false positive-এর সেরা Bloom filter-এ প্রতি key-এ প্রায় কত bit লাগে (key-এর আকার যা-ই হোক)?

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

(মাঝারি) Snowflake-ধাঁচের ID-তে sequence-এর জন্য ১২ bit, আর সময় millisecond-এ। একটি worker সেকেন্ডে সর্বোচ্চ কতটি ID দিতে পারে?

  • ৪,০৯৬
  • ৪১,৯৪,৩০৪
  • ১,০০০
  • ৪০,৯৬,০০০

৭ · Operations-এর সংখ্যা — rate limit, retry, RPO-RTO, canary আর rolling update

সূত্রের কার্ড

Token bucket: হার r, ক্ষমতা b; যেকোনো T সেকেন্ডে ছাড়া ≤ b + rT; tokens = min(b, আগের + r × পেরোনো সময়)। Sliding window counter: আগের গণনা × (1 − f) + এখনকার গণনা।

Retry: L স্তরে প্রতিটিতে a বার চেষ্টা হলে সবচেয়ে নিচের অংশ পায় aL টি (retry amplification). Backoff-এর অপেক্ষা min(cap, base × 2i); full jitter-এ গড়ে অর্ধেক।

DR: RPO-র সবচেয়ে খারাপ = backup-এর ব্যবধান + নিরাপদ জায়গায় পৌঁছানোর সময়; RTO = টের পাওয়া + সিদ্ধান্ত + নতুন পরিবেশ + restore + log replay + যাচাই।

Release: canary-র blast radius = traffic × ভাগ × সময় × error rate; rolling-এ maxSurge ওপরে আর maxUnavailable নিচে গোল, ঢেউ = ⌈replica ÷ (surge + unavailable)⌉.

৭.১(সহজ) (ক) একটি API key-এর token bucket: হার ১০ token/s, ক্ষমতা ৫০, শুরুতে পূর্ণ। t = ০-এ ৮০টি অনুরোধ, t = ২-এ ৩০টি, t = ৩-এ ৫টি, t = ১০-এ ২০০টি। প্রতিবার কয়টি ঢোকে? প্রথম ১০ সেকেন্ডে সর্বোচ্চ কয়টি ঢুকতে পারে? (খ) মিনিটে ১০০-র sliding window counter: আগের মিনিটে ৮০, এই মিনিটে এখন পর্যন্ত ৩০, আর মিনিটের ২৫% পেরিয়েছে। আর কয়টি ঢোকানো যাবে?
(a) t=0 : tokens 50        ask 80  -> admit 50, left 0
    t=2 : 0 + 2 x 10 = 20  ask 30  -> admit 20, left 0
    t=3 : 0 + 10 = 10      ask 5   -> admit 5,  left 5
    t=10: min(50, 5 + 70)  ask 200 -> admit 50, left 0
    bound for any T seconds: b + r T = 50 + 10 x 10 = 150
(b) estimate = 80 x (1 - 0.25) + 30 = 60 + 30 = 90  -> 10 more

Bucket burst-কে অনুমতি দেয় (প্রথমেই ৫০টি), কিন্তু দীর্ঘ সময়ে গড় হার r-এ বাঁধে। t = ১০-এ ৭৫টি token জমার কথা ছিল, কিন্তু ক্ষমতা ৫০-এ আটকে গেল — অলস থেকে অসীম সঞ্চয় হয় না। (খ)-র অনুমান ধরে নেয় আগের মিনিটের ৮০টি সমানভাবে ছড়ানো ছিল; fixed window হলে মিনিটের সীমানায় দুই সেকেন্ডে ২০০টি ঢুকতে পারত (পর্ব ৪৯)। যাচাই: ০ থেকে ৩ সেকেন্ডে ঢুকেছে ৭৫টি ≤ ৫০ + ১০ × ৩ = ৮০ — সীমার ভেতরে। উত্তর: ৫০, ২০, ৫ আর ৫০টি; ১০ সেকেন্ডে সর্বোচ্চ ১৫০; আরও ১০টি। ঝালাতে: পর্ব ৪৯।

৭.২(মাঝারি) (ক) একটি অনুরোধ তিন স্তর পেরিয়ে database-এ যায় (gateway → service A → service B → DB); প্রতিটি স্তর ব্যর্থ হলে মোট ৩ বার চেষ্টা করে। DB পুরো বিকল — একটি ব্যবহারকারীর অনুরোধে DB কতবার ডাক পায়? সেকেন্ডে ১,০০০ অনুরোধে? (খ) Backoff: base ১০০ ms, প্রতিবার দ্বিগুণ, সর্বোচ্চ ১০ s, ৬ বার retry. মোট অপেক্ষা কত? Full jitter-এ গড়ে কত?
(a) 3 layers x 3 attempts each: 3^3 = 27 calls on the DB per user request
    1,000 req/s x 27 = 27,000 calls/s on a database that is already down
(b) waits = 100, 200, 400, 800, 1,600, 3,200 ms (cap 10 s not reached)
    total = 6,300 ms;  full jitter: uniform(0, w) -> average 3,150 ms

সুস্থ হয়ে ফেরার মুহূর্তে DB-কে ২৭ গুণ চাপ সামলাতে হয় — retry তখন সাহায্য নয়, আক্রমণ। প্রতিকার: শুধু একটি স্তরে retry (সাধারণত সবচেয়ে বাইরের বা সবচেয়ে ভেতরের, নকশা অনুযায়ী), retry budget (যেমন মোট অনুরোধের ১০%-এর বেশি retry নয়) আর circuit breaker (পর্ব ৪৮)। Jitter মোট অপেক্ষা কমানোর জন্য নয়, ক্লায়েন্টদের একসাথে ফেরা ভাঙার জন্য। যাচাই: জ্যামিতিক ধারা — ১০০ × (২৬ − ১) = ৬,৩০০ ms. উত্তর: ২৭ বার, সেকেন্ডে ২৭,০০০; ৬.৩ সেকেন্ড, jitter-এ গড়ে ≈ ৩.১৫ সেকেন্ড। ঝালাতে: পর্ব ১৮ আর ৪৮।

// Token bucket admits, sliding-window estimate, retry amplification and a backoff schedule.
function bucket(rate, burst, arrivals) {                        // arrivals: [time s, count]
  let tokens = burst, last = 0, ok = 0, no = 0;
  for (const [t, c] of arrivals) {
    tokens = Math.min(burst, tokens + (t - last) * rate); last = t;
    const take = Math.min(c, Math.floor(tokens));
    tokens -= take; ok += take; no += c - take;
    console.log("t=" + String(t).padEnd(3) + " ask " + String(c).padStart(3) + "  admit " +
      String(take).padStart(3) + "  tokens left " + tokens.toFixed(0));
  }
  return [ok, no];
}
const [ok, no] = bucket(10, 50, [[0, 80], [2, 30], [3, 5], [10, 200]]);
console.log("admitted " + ok + ", rejected " + no + "; bound in any T s: 50 + 10*T");

const prev = 80, cur = 30, f = 0.25;                            // 25% into the current minute
const est = prev * (1 - f) + cur;
console.log("sliding window estimate " + est + " of 100 -> " + (100 - est) + " more allowed");

for (const layers of [2, 3, 4])
  console.log(layers + " layers x 3 attempts: bottom sees " + 3 ** layers + " calls per user request");
let waits = [], sum = 0;
for (let i = 0; i < 6; i++) { const w = Math.min(100 * 2 ** i, 10000); waits.push(w); sum += w; }
console.log("backoff ms " + waits.join(", ") + " = " + sum + " ms; full jitter averages " + sum / 2);

আউটপুট:

t=0   ask  80  admit  50  tokens left 0
t=2   ask  30  admit  20  tokens left 0
t=3   ask   5  admit   5  tokens left 5
t=10  ask 200  admit  50  tokens left 0
admitted 125, rejected 190; bound in any T s: 50 + 10*T
sliding window estimate 90 of 100 -> 10 more allowed
2 layers x 3 attempts: bottom sees 9 calls per user request
3 layers x 3 attempts: bottom sees 27 calls per user request
4 layers x 3 attempts: bottom sees 81 calls per user request
backoff ms 100, 200, 400, 800, 1600, 3200 = 6300 ms; full jitter averages 3150

প্রথম চার লাইন ৭.১-এর token-এর হিসাব (মোট ১২৫টি ঢুকেছে); window-এর অনুমান ৯০; retry-র গুণফল ৯, ২৭, ৮১; backoff ৬,৩০০ ms (৭.২)। ভগ্নাংশ token দিয়ে অনুরোধ ঢোকে না, তাই Math.floor.

৭.৩(মাঝারি) একটি ২ TB database. (ক) শুধু রাত ২টার full backup, যা শেষ হয়ে নিরাপদ জায়গায় পৌঁছাতে ২ ঘণ্টা লাগে — সবচেয়ে খারাপ RPO কত? প্রতি ৫ মিনিটে WAL archive যোগ করলে? (খ) RTO-র ধাপ: টের পাওয়া ও সিদ্ধান্ত ৩০ মিনিট, নতুন instance ১৫ মিনিট, restore ৪০০ MB/s গতিতে, তারপর ৩০০ GB WAL replay ১০০ MB/s-এ। মোট RTO কত? লক্ষ্য ২ ঘণ্টা হলে কী বদলাবেন?
(a) daily full only : worst loss = 24 h + 2 h to be safe = 26 h
    + WAL every 5 min: worst loss ~ 5 min (plus shipping delay)
(b) detect + decide            30.0 min
    new instance               15.0 min
    restore 2 TB @ 400 MB/s    2 x 10^12 / 4 x 10^8 = 5,000 s = 83.3 min
    replay 300 GB @ 100 MB/s   3 x 10^11 / 10^8     = 3,000 s = 50.0 min
    RTO ~ 178.3 min = 2.97 h   (target 2 h missed by ~1 h)

সবচেয়ে খারাপ RPO ২৪ নয়, ২৬ ঘণ্টা: নতুন backup নিরাপদে পৌঁছানোর আগেই বিপর্যয় হলে আগের রাতেরটি থেকে ফিরতে হয়। RTO-র সবচেয়ে বড় দুটি অংশ ডেটা সরানো — ২ ঘণ্টায় নামাতে হলে আরও ঘন ঘন base backup (replay ছোট হয়), দ্রুত restore-এর storage snapshot, বা আগে থেকে চালু একটি warm standby — যেখানে restore-ই লাগে না, শুধু promote (পর্ব ৫১)। এই সংখ্যাগুলো কাগজের; আসল RTO মাপা যায় শুধু restore-মহড়ায়। যাচাই: ৪০০ MB/s = ১.৪৪ TB/ঘণ্টা, তাই ২ TB-তে প্রায় ১.৩৯ ঘণ্টা ≈ ৮৩ মিনিট — মেলে। উত্তর: ২৬ ঘণ্টা; প্রায় ৫ মিনিট; RTO ≈ ১৭৮ মিনিট (≈ ৩ ঘণ্টা)। ঝালাতে: পর্ব ৫১ (point-in-time recovery).

৭.৪(মাঝারি) সেকেন্ডে ১০,০০০ অনুরোধ, SLO ৯৯.৯% (৩০ দিন)। একটি নতুন build-এ এমন ত্রুটি আছে যে ২০% অনুরোধ ব্যর্থ হয়। (ক) ১% traffic-এ canary ৩০ মিনিট চললে কতটি অনুরোধ ব্যর্থ হয়, বাজেটের কত অংশ? (খ) একবারে সবাইকে দিলে একই ৩০ মিনিটে?
monthly requests = 10,000 x 30 x 86,400 = 2.592 x 10^10;  budget = 0.1% = 2.592 x 10^7
(a) canary: 10,000 x 0.01 x 1,800 s x 0.2 = 36,000 failed -> 0.14% of budget
(b) full  : 10,000 x 1,800 s x 0.2       = 3,600,000 failed -> 13.9% of budget

Canary ক্ষতিকে ১০০ ভাগের এক ভাগে নামায় — আর ৩০ মিনিট নয়, ভালো automated analysis-এ কয়েক মিনিটেই ধরা পড়ার কথা। তবে ছোট ভাগে নমুনা ছোট: ১% traffic-এ বিরল ত্রুটি (যেমন ০.১% বাড়তি) প্রমাণ হতে অনেক বেশি সময় লাগে, তাই canary ধাপে ধাপে বাড়ে (১% → ১০% → ৫০%) (পর্ব ৫৩)। যাচাই: অনুপাত ৩৬,০০,০০০ ÷ ৩৬,০০০ = ১০০ — ঠিক canary-র ভাগের উল্টো। উত্তর: ৩৬,০০০টি, বাজেটের ≈ ০.১৪%; ৩৬ লাখ, ≈ ১৩.৯%. ঝালাতে: পর্ব ৫০ আর ৫৩।

৭.৫(মাঝারি) (ক) ৪০টি replica-র rolling update, maxUnavailable ০, প্রতিটি ঢেউ (নতুন pod চালু, readiness, পুরোনোর drain) ৩ মিনিট। maxSurge ২৫% আর ১০%-এ কত সময়? (খ) ১০টি replica, maxSurge ২৫%, maxUnavailable ২৫% — একসাথে সর্বোচ্চ কয়টি pod, আর কমপক্ষে কয়টি প্রস্তুত থাকে?
(a) surge 25%: ceil(40 x 0.25) = 10 per wave -> 40 / 10 = 4 waves  x 3 = 12 min (max 50 pods)
    surge 10%: ceil(40 x 0.10) = 4 per wave  -> 40 / 4  = 10 waves x 3 = 30 min (max 44 pods)
(b) surge = ceil(2.5) = 3 -> at most 13 pods
    unavailable = floor(2.5) = 2 -> at least 8 ready

Surge হলো গতি আর বাড়তি ক্ষমতার trade-off: ২৫%-এ ১২ মিনিট কিন্তু মুহূর্তে ১০টি বাড়তি pod-এর জায়গা লাগে; ১০%-এ মাত্র ৪টি বাড়তি, কিন্তু ৩০ মিনিট — আর সেই পুরো সময় দুই সংস্করণ একসাথে চলে, তাই API আর database দুই সংস্করণের সাথেই মানানসই থাকতে হয় (expand/contract, পর্ব ৫৩)। গোল করার দিক ইচ্ছাকৃত: surge ওপরে, unavailable নিচে — দুটিই নিরাপদ দিকে। যাচাই: (খ) ১০ + ৩ = ১৩, ১০ − ২ = ৮ — পর্ব ৫৩-এর উদাহরণের সাথে মেলে। উত্তর: ১২ আর ৩০ মিনিট; সর্বোচ্চ ১৩টি pod, কমপক্ষে ৮টি প্রস্তুত। ঝালাতে: পর্ব ৫৩ (rolling deployment).

// RPO, RTO from restore steps, canary blast radius and rolling-update time.
const MB = 1e6, GB = 1e9, TB = 1e12;
const rpo = { "daily full (2 h to ship)": 24 * 60 + 120, "WAL archived every 5 min": 5, "sync replica": 0 };
for (const [k, v] of Object.entries(rpo)) console.log("RPO worst " + k.padEnd(26) + v + " min");

const steps = [["detect + decide", 30], ["new instance", 15],
  ["restore 2 TB @ 400 MB/s", 2 * TB / (400 * MB) / 60],
  ["replay 300 GB WAL @ 100 MB/s", 300 * GB / (100 * MB) / 60]];
let rto = 0;
for (const [name, min] of steps) { rto += min; console.log("  " + name.padEnd(30) + min.toFixed(1) + " min"); }
console.log("RTO ~ " + rto.toFixed(1) + " min = " + (rto / 60).toFixed(2) + " h");

const rps = 10000, canary = 0.01, mins = 30, errRate = 0.2;      // a bad build fails 20%
const canaryBad = rps * canary * mins * 60 * errRate;
const fullBad = rps * mins * 60 * errRate;
const budget = rps * 30 * 86400 * 0.001;                        // 30-day, 99.9% SLO
console.log("canary 1% for 30 min: " + canaryBad + " failed (" + (100 * canaryBad / budget).toFixed(2) +
  "% of budget); full rollout: " + fullBad + " (" + (100 * fullBad / budget).toFixed(1) + "%)");

function rolling(replicas, surgePct, unavailPct, batchMin) {
  const surge = Math.ceil(replicas * surgePct), unavail = Math.floor(replicas * unavailPct);
  const step = Math.max(1, surge + unavail);                     // pods replaced per wave
  console.log(replicas + " pods, surge " + surge + ", unavailable " + unavail + ": max " + (replicas + surge) +
    " pods, min " + (replicas - unavail) + " ready, " + Math.ceil(replicas / step) + " waves = " +
    Math.ceil(replicas / step) * batchMin + " min");
}
rolling(40, 0.25, 0, 3); rolling(40, 0.10, 0, 3); rolling(10, 0.25, 0.25, 3);

আউটপুট:

RPO worst daily full (2 h to ship)  1560 min
RPO worst WAL archived every 5 min  5 min
RPO worst sync replica              0 min
  detect + decide               30.0 min
  new instance                  15.0 min
  restore 2 TB @ 400 MB/s       83.3 min
  replay 300 GB WAL @ 100 MB/s  50.0 min
RTO ~ 178.3 min = 2.97 h
canary 1% for 30 min: 36000 failed (0.14% of budget); full rollout: 3600000 (13.9%)
40 pods, surge 10, unavailable 0: max 50 pods, min 40 ready, 4 waves = 12 min
40 pods, surge 4, unavailable 0: max 44 pods, min 40 ready, 10 waves = 30 min
10 pods, surge 3, unavailable 2: max 13 pods, min 8 ready, 2 waves = 6 min

RPO ১,৫৬০ মিনিট (২৬ ঘণ্টা), ৫ মিনিট আর ০ — তবে sync replica ভুল DELETE-ও কপি করে, backup-এর বিকল্প নয়। RTO ১৭৮.৩ মিনিট (৭.৩), canary ৩৬,০০০ বনাম ৩৬ লাখ (৭.৪), rolling-এর তিন লাইন ৭.৫. rolling() সব ঢেউ সমান ধরে — বাস্তবে readiness আর drain তা ঠিক করে।

(সহজ) Token bucket: হার ৫ token/s, ক্ষমতা ২০, শুরুতে পূর্ণ। প্রথম ১০ সেকেন্ডে সর্বোচ্চ কয়টি অনুরোধ ঢুকতে পারে?

  • ৭০
  • ৫০
  • ২০
  • ১০০

(মাঝারি) একটি অনুরোধ তিনটি স্তর পেরিয়ে একটি বিকল database-এ যায়; প্রতিটি স্তর মোট ৪ বার চেষ্টা করে (প্রথম চেষ্টা + ৩টি retry). Database একটি অনুরোধে কতবার ডাক পায়?

  • ১২
  • ৬৪
  • ৮১
  • ৪

(মাঝারি) শুধু প্রতি রাত ১টার full backup, যা শেষ হয়ে আলাদা নিরাপদ জায়গায় পৌঁছাতে ১ ঘণ্টা লাগে। সবচেয়ে খারাপ ক্ষেত্রে কত সময়ের ডেটা হারাতে পারে (RPO)?

  • ১ ঘণ্টা
  • ২৪ ঘণ্টা
  • ২৫ ঘণ্টা
  • ০

(মাঝারি) ২০টি replica-র rolling update: maxSurge ২৫%, maxUnavailable ০, প্রতিটি ঢেউ ৪ মিনিট। মোট কত সময়?

  • ৮০ মিনিট
  • ৪ মিনিট
  • ২০ মিনিট
  • ১৬ মিনিট

(মাঝারি) Load balancer প্রতি ৫ সেকেন্ডে health check পাঠায়, timeout ২ সেকেন্ড, পরপর ৩টি ব্যর্থ হলে সার্ভার বাদ। সবচেয়ে খারাপ ক্ষেত্রে মৃত সার্ভার কত সেকেন্ডে বাদ পড়ে?

  • ৭ সেকেন্ড
  • ১৫ সেকেন্ড
  • ১৭ সেকেন্ড
  • ৬ সেকেন্ড

৮ · Trade-off ড্রিল — “এই দুটি নকশার মধ্যে কোনটি, আর কেন”

লিখিত পরীক্ষায় “তুলনা করুন” আর ইন্টারভিউর “why not X?” — দুই প্রশ্নেরই সবচেয়ে শক্ত উত্তর হলো সংখ্যা দিয়ে দাম দেখানো, তারপর requirement দিয়ে সিদ্ধান্ত। প্রতিটি ড্রিলে তিনটি অংশ: সংখ্যা, কোথায় ভাঙে, আর কখন উল্টো সিদ্ধান্ত। মনে রাখুন, প্রশ্নের সব সংখ্যা ধরে নেওয়া; সংখ্যা বদলালে উত্তরও বদলাতে পারে — আর সেটি বলতে পারাই trade-off বোঝার প্রমাণ।

৮.১(মাঝারি) একটি কাল্পনিক সামাজিক অ্যাপে দিনে ১ কোটি পোস্ট, গড়ে ৫০০ জন follower; দিনে ৪০ কোটি বার feed খোলা হয়, প্রত্যেকে গড়ে ২০০ জনকে follow করেন। Fan-out on write (push) না fan-out on read (pull)? একজন তারকার ৫ কোটি follower থাকলে কী হয়? (ধরুন timeline-এ সেকেন্ডে ১ লাখ insert করা যায়।)
push: 10^7 posts x 500 = 5 x 10^9 inserts/day = 57,870 /s
pull: 4 x 10^8 reads x 200 followees = 8 x 10^10 fetches/day = 925,926 /s
celebrity: 5 x 10^7 inserts / 10^5 per s = 500 s = 8.3 min for ONE post

সংখ্যা: push-এ কাজ প্রায় ১৬ গুণ কম, আর feed খোলা মানে শুধু একটি তৈরি তালিকা পড়া — read-ভারী সেবায় push জেতে। কোথায় ভাঙে: লম্বা লেজ — একজন তারকার একটি পোস্টেই ৮ মিনিট insert, আর সেই সময়ে বাকিদের কাজ পিছিয়ে যায়। সিদ্ধান্ত: hybrid — সাধারণ ব্যবহারকারীর জন্য push, সীমার (যেমন কয়েক লাখ follower) ওপরের অ্যাকাউন্টের পোস্ট পড়ার সময় pull করে মিশিয়ে দেওয়া; অনুপস্থিত ব্যবহারকারীর timeline না বানানো (পর্ব ৫৬)। কখন উল্টো: লেখা পড়ার চেয়ে বেশি, বা follower-সংখ্যা সবার প্রায় সমান ও ছোট হলে pull সরল আর সস্তা। উত্তর: সাধারণভাবে push (≈ ৫৭,৮৭০ বনাম ≈ ৯,২৫,৯২৬ কাজ/s), তারকাদের জন্য pull — hybrid. ঝালাতে: পর্ব ৩২ আর ৫৬ (fan-out on write, fan-out on read).

৮.২(মাঝারি) Primary একটি region-এ, replica ৭০ ms round trip দূরের আরেকটি region-এ; সেকেন্ডে ২,০০০টি লেখা, region-এর ভেতরে একটি commit প্রায় ৫ ms. Asynchronous-এ lag সাধারণত ২০০ ms, কিন্তু ঢেউয়ে ৩০ s পর্যন্ত। Synchronous না asynchronous? একটি কাল্পনিক payment ledger আর একটি “like” গণনার জন্য আলাদা করে বলুন।
sync : commit latency ~ 5 + 70 = 75 ms (15x slower writes); RPO = 0
async: commit ~ 5 ms; on region loss lose ~ lag x write rate
       typical: 0.2 s x 2,000 = 400 writes;  during a spike: 30 s x 2,000 = 60,000

সংখ্যা: sync প্রতিটি লেখায় ৭০ ms যোগ করে, আর দূরের region বিকল বা ধীর হলে লেখাই আটকে যায় (availability-র দাম, PACELC-এর “E”-তে latency বনাম consistency, পর্ব ৪০)। Async দ্রুত, কিন্তু region হারালে শত থেকে হাজার হাজার লেখা হারাতে পারে। সিদ্ধান্ত: payment ledger-এ টাকা হারানো চলে না — region-এর ভেতরে তিনটি zone-এ quorum বা sync commit (RPO শূন্য, latency মাত্র কয়েক ms), আর দূরের region-এ async কপি DR-এর জন্য। “Like”-এ কয়েক সেকেন্ডের ক্ষতি সহনীয় — async. কখন উল্টো: নিয়ম বা চুক্তিতে region-বিপর্যয়েও শূন্য ক্ষতি চাইলে দূরের sync-এর ৭০ ms মেনে নিতে হয়, আর লেখার থ্রুপুট রাখতে batching. উত্তর: ledger — কাছের sync বা quorum + দূরে async; like — async. ঝালাতে: পর্ব ২২, ৪০ আর ৫১।

৮.৩(কঠিন) একটি কাল্পনিক sensor-ডেটা সেবায় সেকেন্ডে ৫০,০০০টি ১০০-byte সারি লেখা হয়; পড়া কম, মূলত সাম্প্রতিক সময়ের পরিসর। ধরা যাক B-tree-তে প্রতিটি ছোট লেখা গড়ে একটি ৪ KB page নতুন করে লেখায় (write amplification ≈ ৪০), আর LSM-tree-তে compaction মিলিয়ে ≈ ১০. LSM-এ ৬টি স্তর, প্রতিটিতে Bloom filter ১% false positive. B-tree না LSM-tree?
logical writes = 50,000 x 100 B = 5 MB/s
B-tree  : 5 MB/s x 40 = 200 MB/s of disk writes
LSM-tree: 5 MB/s x 10 =  50 MB/s of disk writes (mostly sequential)
LSM point read: extra SSTable probes ~ 6 levels x 1% = 0.06 per lookup

সংখ্যা: (ধরে নেওয়া amplification-এ) LSM disk-এ চার গুণ কম লেখে, আর লেখে ক্রমিকভাবে — SSD-এর আয়ু আর throughput দুটিতেই লাভ। Bloom filter থাকায় একটি key খুঁজতে বাড়তি ফাইল-খোঁজা গড়ে মাত্র ০.০৬টি। কোথায় ভাঙে: compaction পেছনে disk আর CPU খায়, আর লেখার ঢেউয়ে পিছিয়ে পড়লে পড়া ধীর হয় আর জায়গা ফুলে ওঠে (space amplification); range scan-এ Bloom filter সাহায্য করে না। সিদ্ধান্ত: লেখা-ভারী, সময়-ক্রমিক ডেটায় LSM. কখন উল্টো: পড়া-ভারী, অনুমেয় latency আর জায়গায় বদলানো (update-in-place) লাগলে B-tree (পর্ব ১৯)। আসল amplification workload আর setting-ভেদে অনেক আলাদা — নিজের ডেটায় মাপুন। উত্তর: LSM-tree (≈ ৫০ বনাম ≈ ২০০ MB/s disk-লেখা)। ঝালাতে: পর্ব ১৯ (LSM-tree, write amplification).

৮.৪(কঠিন) একটি database এখন সেকেন্ডে ৮,০০০টি লেখা নেয় আর ৮ TB ডেটা রাখে; দুটিই প্রতি বছর ৩০% বাড়ে। সবচেয়ে বড় যে মেশিন কেনা যায় সেটি ১৫,০০০ লেখা/s আর ২০ TB পারে, আর আপনি ৭০%-এর বেশি ভরাতে চান না। এখনই sharding, না আপাতত একটি বড় মেশিন? কত দিন চলবে?
limits at 70%: writes 10,500 /s, data 14 TB
years until writes hit it: log(10,500 / 8,000) / log(1.3) = 1.04 years
years until data hits it : log(14 / 8) / log(1.3)         = 2.13 years
-> the write rate runs out first, in about a year

সংখ্যা: বড় মেশিন (vertical scaling) প্রায় এক বছর সময় কেনে — লেখার হারই আগে ফুরায়, storage নয়। Read replica এখানে কিছুই করে না, কারণ লেখা শুধু primary-তে। সিদ্ধান্ত: আপাতত বড় মেশিনে যান — সরল, ঝুঁকি কম — কিন্তু আজই shard key বেছে sharding-এর কাজ শুরু করুন, কারণ data migration আর application বদলাতে মাস লাগে; ৯–১০ মাসে প্রস্তুত থাকা চাই (পর্ব ১৩ আর ২৩)। কখন উল্টো: বৃদ্ধি ১০০%/বছর হলে runway মাত্র log(১.৩১২৫) ÷ log ২ ≈ ০.৪ বছর — তখন সরাসরি sharding. যাচাই: ৮,০০০ × ১.৩ = ১০,৪০০ (এক বছরে), সীমা ১০,৫০০-এর প্রায় গায়ে — মেলে। উত্তর: আপাতত বড় মেশিন, প্রায় ১ বছরের runway (storage-এ ≈ ২.১ বছর); sharding-এর প্রস্তুতি এখনই। ঝালাতে: পর্ব ১৩ আর ২৩ (capacity planning).

৮.৫(মাঝারি) Peak সামলাতে ৩০টি সার্ভার লাগে, আর একটি পুরো zone হারালেও সেবা পূর্ণ চলতে হবে। ২, ৩ না ৪টি zone? প্রতিটিতে কত সার্ভার, মোট কত, আর বাড়তি খরচ কত শতাংশ?
z zones, survive 1: each of the remaining (z - 1) carries 30 / (z - 1)
z = 2: 30 per zone, total 60, extra 100%
z = 3: 15 per zone, total 45, extra  50%
z = 4: 10 per zone, total 40, extra  33%
general: total = N x z / (z - 1)

সংখ্যা: zone বাড়লে বাড়তি খরচ ১০০% থেকে ৩৩%-এ নামে। দাম: প্রতিটি zone-এ load balancer, database replica আর monitoring লাগে; zone-এর মধ্যে ডেটা পাঠানোয় latency আর (অনেক cloud-এ) খরচ যোগ হয়; quorum-ভিত্তিক database-এ ৩টি zone স্বাভাবিক মিল (৩-এর মধ্যে ২-এর majority). সিদ্ধান্ত: সাধারণত ৩টি — ৫০% বাড়তি, আর quorum-এর সাথে মানানসই। কখন উল্টো: ছোট সেবায় (৩–৪টি সার্ভার) ৪টি zone-এ ভাগ করলে প্রতিটিতে ১টি — একটি deploy-ও তখন zone হারানোর মতো; ২টি zone আর autoscaling সরল হতে পারে। উত্তর: ২ zone-এ ৬০টি (১০০%), ৩-এ ৪৫টি (৫০%), ৪-এ ৪০টি (≈ ৩৩%); সাধারণত ৩টি zone. ঝালাতে: পর্ব ০৫ আর ৫১ (overprovisioning).

৮.৬(মাঝারি) ১০ লাখ অনলাইন ক্লায়েন্ট নতুন খবর পেতে প্রতি ১০ সেকেন্ডে poll করে; প্রতিটি অনুরোধ-উত্তরে header মিলিয়ে ৮০০ byte. সারা সিস্টেমে সেকেন্ডে আসল নতুন খবর ৫,০০০টি। WebSocket-এ প্রতিটি খোলা সংযোগ সার্ভারে প্রায় ২০ KB memory নেয় (ধরে নেওয়া)। Polling না WebSocket? (ক) দুই পথের চাপ কত? (খ) কখন polling-ই ভালো?
(a) polling  : 10^6 / 10 s = 100,000 req/s x 800 B x 8 = 640 Mbit/s
               useful: 5,000 / 100,000 = 5% of polls carry news
    WebSocket: 10^6 open connections x 20 KB = 20 GB RAM; 5,000 msg/s pushed
               news arrives at once (not up to 10 s late)

সংখ্যা: polling-এ ৯৫% অনুরোধ খালি হাতে ফেরে, আর খবর গড়ে ৫ সেকেন্ড দেরিতে পৌঁছায়; WebSocket-এ অনুরোধ প্রায় ২০ গুণ কম, খবর সঙ্গে সঙ্গে — দাম ২০ GB RAM জুড়ে দীর্ঘজীবী সংযোগ, সেগুলো load balancer-এ ভাগ করা, deploy-এর সময় ১০ লাখ সংযোগের ধীরে পুনঃসংযোগ (না হলে thundering herd). সিদ্ধান্ত: chat বা live score-এর মতো ঘন ঘন, তাৎক্ষণিক খবরে WebSocket (বা এক দিকের হলে SSE). কখন উল্টো: খবর বিরল আর কয়েক মিনিট দেরি চলে (যেমন দিনে দুবার বদলানো তালিকা) — তখন সাধারণ HTTP polling, cache আর CDN সরল, সস্তা আর ভরসাযোগ্য (পর্ব ১০)। উত্তর: এখানে WebSocket (১,০০,০০০ req/s আর ৬৪০ Mbit/s-এর বদলে ৫,০০০ বার্তা/s আর ≈ ২০ GB RAM). ঝালাতে: পর্ব ১০ আর ৫৫।

// Trade-off numbers: feed fan-out, zones, single DB runway, polling vs WebSocket.
const DAY = 86400;
const posts = 1e7, feedReads = 4e8, avgFollowers = 500, followees = 200;
console.log("push: " + (posts * avgFollowers / DAY).toFixed(0) + " timeline inserts/s");
console.log("pull: " + (feedReads * followees / DAY).toFixed(0) + " followee fetches/s");
console.log("one celebrity post, 5e7 followers at 1e5 inserts/s: " + (5e7 / 1e5 / 60).toFixed(1) + " min");

const needPeak = 30;                                            // servers that carry the peak
for (const z of [1, 2, 3, 4]) {
  const perZone = z === 1 ? needPeak : Math.ceil(needPeak / (z - 1));
  console.log(z + " zone(s): " + perZone + " per zone, total " + perZone * z +
    (z === 1 ? " (a zone outage = full outage)" : ", extra " + (100 * (perZone * z / needPeak - 1)).toFixed(0) + "%"));
}
// how long until one database box is too small? growth 30%/yr, keep 70% headroom
const years = (now, limit) => Math.log(limit / now) / Math.log(1.3);
console.log("writes 8000/s -> 70% of 15000: " + years(8000, 0.7 * 15000).toFixed(2) + " years");
console.log("data 8 TB -> 70% of 20 TB:     " + years(8, 0.7 * 20).toFixed(2) + " years");

const clients = 1e6, every = 10, header = 800, events = 5000, wsMem = 20e3;
const pollRps = clients / every;
console.log("polling: " + pollRps + " req/s, " + (pollRps * header * 8 / 1e6) + " Mbit/s of headers, " +
  (100 * events / pollRps) + "% carry news");
console.log("WebSocket: " + clients + " open connections ~ " + clients * wsMem / 1e9 + " GB RAM, " + events + " msg/s");

আউটপুট:

push: 57870 timeline inserts/s
pull: 925926 followee fetches/s
one celebrity post, 5e7 followers at 1e5 inserts/s: 8.3 min
1 zone(s): 30 per zone, total 30 (a zone outage = full outage)
2 zone(s): 30 per zone, total 60, extra 100%
3 zone(s): 15 per zone, total 45, extra 50%
4 zone(s): 10 per zone, total 40, extra 33%
writes 8000/s -> 70% of 15000: 1.04 years
data 8 TB -> 70% of 20 TB:     2.13 years
polling: 100000 req/s, 640 Mbit/s of headers, 5% carry news
WebSocket: 1000000 open connections ~ 20 GB RAM, 5000 msg/s

প্রথম তিন লাইন ৮.১, zone-এর টেবিল ৮.৫ (১টি zone সস্তা, কিন্তু zone-বিভ্রাট মানে পুরো বিভ্রাট), runway ৮.৪-এর ১.০৪ আর ২.১৩ বছর, শেষ দুই লাইন ৮.৬. avgFollowers ৫০ করলে push-এর চাপ দশ ভাগের এক ভাগ।

(মাঝারি) Peak-এ ২৪টি সার্ভার লাগে। সেবাটি ৩টি zone-এ, আর একটি পুরো zone হারালেও পূর্ণ peak সামলাতে হবে। মোট কয়টি সার্ভার লাগবে?

  • ৩৬টি
  • ২৪টি
  • ৪৮টি
  • ৩২টি

(মাঝারি) দিনে ২ লাখ নতুন পোস্ট, প্রতিটির লেখকের গড়ে ৩০০ জন follower. Fan-out on write-এ timeline-এ সেকেন্ডে গড়ে কয়টি insert?

  • ≈ ২.৩
  • ≈ ৬৯৪
  • ≈ ১৬,৬৬৭
  • ৬ কোটি

(মাঝারি) Primary আর তার synchronous replica-র মধ্যে round trip ৬০ ms. প্রতিটি commit-এর latency ন্যূনতম প্রায় কত বাড়ে?

  • প্রায় ০
  • ৩০ ms
  • ৬০ ms
  • ১২০ ms

(কঠিন) N = ৩টি replica, প্রতিটি স্বাধীনভাবে ৯৯% সময় চালু। লেখায় W = ৩ (সবার ack) চাইলে লেখার availability প্রায় কত?

  • ৯৯%
  • ≈ ৯৯.৯৭%
  • ≈ ৯৯.৯৯৯৯%
  • ≈ ৯৭.০৩%

৯ · শেষ মুহূর্তের সূত্র-তালিকা — এক পাতায়

পরীক্ষার আগের রাতে বা ইন্টারভিউর ঘরে ঢোকার আগে এই টেবিলটি একবার চোখ বুলিয়ে নিন। প্রতিটি সারির শেষ কলামে যে পর্বে পূর্ণ যুক্তি আছে, তার নম্বর। সূত্র মুখস্থের চেয়ে জরুরি তার শর্ত — কোথায় স্বাধীনতা, স্থিতিশীলতা বা সমান ছড়ানো ধরে নেওয়া হয়েছে।

বিষয়সূত্র বা সংখ্যাশর্ত বা ফাঁদপর্ব
সময়দিন ৮৬,৪০০ s ≈ ১০৫; মাস (৩০ দিন) ২.৫৯ × ১০৬ s = ৪৩,২০০ মিনিট; বছর ৩.১৫ × ১০৭ s = ৫,২৫,৬০০ মিনিট১০৫-এ উত্তর ≈ ১৪% কম০৩
Latency-র মাত্রাRAM ~১০০ ns · SSD ~১০০ µs · data center RTT ~০.৫ ms · disk seek ~১০ ms · মহাদেশ RTT ~১৫০ ms; ফাইবারে ~৫ ms প্রতি ১,০০০ km এক দিকেমাত্রা মনে রাখুন, সংখ্যা নয়০৩
QPS আর peakDAU × অনুরোধ ÷ ৮৬,৪০০; peak = গড় × factorread আর write আলাদা০৩
Storagerecord/দিন × আকার × দিন × কপি × overhead; বৃদ্ধি g: প্রথম বছর × ((1 + g)n − 1) ÷ gকপি আর index ভুলবেন না০৩
BandwidthQPS × payload × ৮ bit/sMB/s বনাম Mbit/s — ৮ গুণ০৩
সার্ভার⌈peak ÷ (ক্ষমতা × ০.৬)⌉ + ১–২; z zone, একটি হারালে মোট = N × z ÷ (z − 1)ক্ষমতা load test থেকে০৩, ০৫
LittleL = λWস্থিতিশীল সিস্টেম, দীর্ঘ গড়০৪
M/M/1ρ = λS; W = S ÷ (1 − ρ); L = ρ ÷ (1 − ρ); p99 ≈ ৪.৬Wρ → ১-এ বিস্ফোরণ০৪
Percentilenearest-rank: ⌈p × n⌉-তম মানpercentile-এর গড় হয় না০৪, ৫০
Fan-out tail1 − (1 − p)N; প্রতিটিকে 0.991/Nব্যর্থতা স্বাধীন ধরা০৪
Overloadλ > μ, অসীম queue: সব timeout D ছাড়ায় T* = Dμ ÷ (λ − μ) পরেসীমিত queue আর shedding১৮
Availabilityseries ΠA; parallel 1 − Π(1 − A); k-of-n যোগফল; downtime = (1 − A) × সময়ভাগ করা zone series-এ০৫
MTBF/MTTRA = MTBF ÷ (MTBF + MTTR); U ≈ MTTR ÷ MTBFMTTR অর্ধেক = MTBF দ্বিগুণ০৫
Error budget(1 − SLO) × জানালা; burn = error ÷ (1 − SLO); ফুরায় জানালা ÷ burn; ১ ঘণ্টায় ২% → burn ১৪.৪অনুরোধ-ভিত্তিক হলে গণনায়৫০
Shardmax(ডেটা ÷ (disk × fill), লেখা ÷ (primary × util)); node = shard × RFবড়টি জেতে২৩
Key সরানোmod N: N ÷ (N + 1); ring: ১ ÷ (N + 1); নির্দিষ্ট partition: নতুনের ন্যায্য ভাগ“প্রত্যাশিত”, প্রতিবার নয়১৬, ২৩
Virtual nodesd ÷ গড় ≈ √((N − 1) ÷ (NV + 1)) ≈ 1 ÷ √V; V ≈ 1 ÷ c²hot key সারায় না১৬
CacheDB = read × (1 − h); latency = tc + (1 − h)tdb; একটি shard হারালে × (1 + h ÷ (N(1 − h)))miss-ই চাপ ঠিক করে২৮, ৩০
Replication lagbacklog = (লেখা − প্রয়োগ) × সময়; ধরে ফেলা = backlog ÷ (প্রয়োগ − নতুন লেখা)async-এ RPO ≈ lag২২
QuorumR + W > N; overlap ≥ W + R − N; লেখা N − W, পড়া N − R বন্ধেওlinearizable-এর নিশ্চয়তা নয়৪১
Raftmajority ⌊n/2⌋ + 1; সহ্য ⌊(n − 1)/2⌋; commit = majority-র এক round tripজোড় সংখ্যায় লাভ নেই৪২
Gossip≈ log2 n + ln n রাউন্ড; all-to-all n(n − 1), SWIM ≈ 2n বার্তাmembership সিদ্ধান্ত নয়৪৪
Bloomm/n = −ln p ÷ (ln 2)² (১% → ৯.৬ bit, ০.১% → ১৪.৪); k = (m/n) ln 2শুধু false positive৪৫
Count-min, HLLw = ⌈e/ε⌉, d = ⌈ln(1/δ)⌉; HLL ভুল 1.04 ÷ √m (p = ১৪ → ০.৮১%, ১২ KiB)CMS কখনো কম বলে না৪৫
Birthdayপ্রত্যাশিত জোড়া ≈ n² ÷ 2M; ৫০% at n ≈ 1.177√M; ৬২৭ ≈ ৩.৫২ × ১০১২জোড়া বাড়ে n²-এ২৩, ৫৪
Snowflake২৪১ ms ≈ ৬৯.৭ বছর; ১,০২৪ worker; ৪,০৯৬/ms/workerঘড়ি পেছালে অপেক্ষা২৩
Token bucketT সেকেন্ডে ≤ b + rT; window counter = আগের × (1 − f) + এখনকারfixed window-এর সীমানায় ২ গুণ৪৯
RetryaL গুণ চাপ; backoff min(cap, base × 2i), full jitter-এ গড় অর্ধেকএকটি স্তরে retry, budget৪৮
RPO-RTORPO = ব্যবধান + পৌঁছানোর সময়; RTO = টের পাওয়া + সিদ্ধান্ত + পরিবেশ + restore + replay + যাচাইমহড়ায় মাপুন৫১
Releasecanary ক্ষতি = traffic × ভাগ × সময় × error; ঢেউ = ⌈replica ÷ (surge + unavailable)⌉; health check: fall × interval + timeoutsurge ওপরে, unavailable নিচে গোল১৪, ৫৩

১০ · AI-এর যুগে — estimation আর trade-off-এর উত্তর যাচাই

AI-কে একটি capacity plan করতে বললে কয়েক সেকেন্ডে সুন্দর টেবিল আসে — আর বেশ প্রায়ই তার কোথাও একটি ×১,০০০ হারানো, ৮৬,৪০০-এর জায়গায় ৩,৬০০, বা MB আর Mbit মেশানো থাকে। ভুল সংখ্যার চেয়েও বড় সমস্যা হলো সংখ্যা ছাড়া সিদ্ধান্ত: “Kafka, Redis আর microservices যোগ করুন” — যেখানে এই পাতার হিসাব হয়তো বলছে একটি ভালো database আর একটি cache-ই যথেষ্ট। এই পাতার সব সংখ্যা স্ক্রিপ্ট চালিয়ে মেলানো; AI-এর সংখ্যাও সেভাবেই মেলাতে হবে।

AI সাধারণত যেখানে ভুল করে

AI-এর ভুলপরিণামকীভাবে ধরবেন
গুণ-ভাগে ভুল: ৩,৬০০ দিয়ে ভাগ, ×৮ বাদ, একটি prefix হারানো২৪, ৮ বা ১,০০০ গুণ ভুল সার্ভার বা লিংকপ্রতিটি ধাপ এই পাতার ক্যালকুলেটরে আবার চালান; একক মিলিয়ে দেখুন
Peak, replication আর overhead বাদসন্ধ্যার ভিড়ে বা প্রথম disk-ভরাটে বিপর্যয়“peak factor কত? কয়টি কপি? index?” — তিনটি প্রশ্ন সবসময়
Availability যোগ করা, বা স্বাধীনতা চুপচাপ ধরে নেওয়া“দুটি replica = পাঁচ nine”-এর মতো কাগুজে সংখ্যাভাগ করা zone, config আর deploy series-এ বসিয়ে আবার হিসাব
গড় দিয়ে latency, বা percentile-এর গড়p99-এর প্রতিশ্রুতি ভাঙেM/M/1 বা fan-out-এর সূত্রে tail হিসাব; histogram থেকে percentile
ACID-এর consistency আর CAP-এর consistency মেশানোquorum বা replication নিয়ে ভুল দাবিসংজ্ঞা মিলিয়ে নিন (পর্ব ২৪ আর ৪০)
বানানো product limit আর দাম“একটি Redis node ১০ লাখ QPS” বা মনগড়া GB-প্রতি দামঅফিসিয়াল documentation, বর্তমান মূল্যতালিকা আর নিজের load test
ব্যর্থতা উপেক্ষা আর অতিরিক্ত নকশাদিনে কয়েক হাজার অনুরোধে বহু-region cluster; অথচ cache shard পড়লে কী হবে বলা নেইFailure-mode review: প্রতিটি বাক্স নষ্ট হলে সংখ্যা কী দাঁড়ায় (যেমন ৫.৫-এর ৭ গুণ)

AI-কে উত্তরদাতা নয়, যাচাইকারী আর প্রশ্ন-বানানোর সহকারী হিসেবে ব্যবহার করুন — যাতে আপনার খাতার প্রতিটি ধাপ সে খুঁটিয়ে দেখে:

আমি system design-এর estimation অনুশীলন করছি। নিচে প্রশ্ন, আমার ধরে নেওয়া মান আর আমার হাতে করা সমাধান দিলাম। প্রশ্ন: [যেমন: একটি chat অ্যাপের peak delivery/s আর ৫ বছরের storage] নিয়ম: ১ দিন = ৮৬,৪০০ সেকেন্ড; KB = ১,০০০ byte; network bit-এ; peak-এ সার্ভারের লক্ষ্য ৬০%; ব্যর্থতা স্বাধীন ধরা হবে না যদি zone ভাগ করা থাকে। আমার সমাধান: [ধাপগুলো পেস্ট করুন] ১. পুরো উত্তর আগে দিও না। আমার সমাধানের প্রথম যে ধাপে ভুল আছে, শুধু সেটি বলো, আর কেন। ২. তুমি নিজে হিসাব করলে প্রতিটি ধাপে সূত্র, একক আর ১০-এর ঘাত আলাদা লাইনে দেখাও। ৩. কোনো product-এর limit বা দাম বানিয়ে বলবে না; জানা না থাকলে "যাচাই করতে হবে" লেখো। ৪. শেষে দুটি sanity check দাও: একটি প্রতি ব্যবহারকারীর হিসাবে, একটি কোনো পরিচিত সীমার (disk, লিংক, সার্ভার) সাথে তুলনায়। ৫. একই নিয়মে একটি নতুন trade-off প্রশ্ন দাও ("দুটির মধ্যে কোনটি, আর কেন"), উত্তর লুকিয়ে রাখো।

AI-এর estimation হাতে পেলে — যাচাইয়ের চেকলিস্ট

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

ওপরের প্রতিটি ভাগের প্রশ্নের সাথে এখানে শেষ কয়েকটি। খাতায় হিসাব করে তবে উত্তর বাছুন; ভুল হলে কারণসহ ব্যাখ্যা পাবেন।

ক্রমএকটি back-of-the-envelope estimation-এর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. ধরে নেওয়া মান (DAU, প্রতি জনের ব্যবহার, আকার, peak factor) আলাদা করে লেখা
  2. গড় আর peak QPS — read আর write আলাদা
  3. Storage — দিন, কপি আর overhead-সহ
  4. Bandwidth — ingress আর egress, bit/s-এ
  5. সার্ভার, cache আর shard-এর সংখ্যা — utilization আর বাড়তি-সহ
  6. Sanity check — প্রতি ব্যবহারকারীর হিসাবে আর পরিচিত সীমার সাথে

(মাঝারি) HyperLogLog-এ p = ১৪ (২১৪ = ১৬,৩৮৪টি register). আলাদা ব্যবহারকারীর অনুমানের আদর্শ ভুল (standard error) প্রায় কত?

  • ≈ ০.৮১%
  • ≈ ১.৬৩%
  • ≈ ০.০০৬%
  • ≈ ৮.১%

(কঠিন) ৬ অক্ষরের এলোমেলো base62 code (৬২৬ ≈ ৫.৬৮ × ১০১০টি সম্ভাব্য) দিয়ে ১০ লাখ link বানানো হলো। প্রত্যাশিত কয়টি সংঘর্ষ-জোড়া?

  • প্রায় ০
  • ≈ ৮.৮
  • ≈ ০.০০০০১৮
  • ১০ লাখ

শব্দকোষ

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

মনে রাখুন

  1. নিয়ম আর একক আগে: ৮৬,৪০০ (মাথায় ১০৫), ৩৬৫ দিনের বছর, ৩০ দিনের মাস, KB = ১,০০০, network bit-এ — উত্তরের প্রথম লাইনে লিখুন; ধরে নেওয়া মান আলাদা বাক্সে।
  2. Traffic থেকে যন্ত্র: peak দিয়ে নকশা, গড় দিয়ে নয়; storage-এ কপি আর overhead; bandwidth-এ ×৮; সার্ভার ৬০%-এ আর N+1/N+2; zone হারালে N × z ÷ (z − 1).
  3. Latency আর availability: L = λW; W = S ÷ (1 − ρ); fan-out-এ 1 − (1 − p)N; series-এ গুণ, parallel-এ ব্যর্থতার গুণ, ভাগ করা অংশ series-এ; burn = error ÷ (1 − SLO).
  4. ডেটা আর distributed: miss-ই database-এর চাপ; mod N সরায় N ÷ (N + 1), ring ১ ÷ (N + 1); R + W > N; majority ⌊n/2⌋ + 1; Bloom ১%-এ ৯.৬ bit; সংঘর্ষ n² ÷ 2M.
  5. Trade-off মানে সংখ্যা + ভাঙন + উল্টো শর্ত: প্রতিটি “কোনটি” প্রশ্নে দাম গুনে দেখান, কোথায় ভাঙে বলুন, আর কোন requirement-এ উত্তর উল্টে যায় — তারপর ক্যালকুলেটরে মিলিয়ে নিন।

পরের পর্বে: পুরো কোর্সের MCQ প্রশ্নব্যাংক — মডিউল ধরে সাজানো, প্রতিটি অপশনের ব্যাখ্যাসহ। এই পাতার সূত্রগুলো সেখানে কয়েক সেকেন্ডের সিদ্ধান্তে কাজে লাগবে।

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

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