এই পর্বে যা শিখবেন
- Data center-এর গঠন (rack, server, ToR switch, বিদ্যুৎ আর ঠান্ডা রাখার সীমা) আর north-south বনাম east-west ট্রাফিক
- তিন-স্তরের পুরোনো নকশার সমস্যা আর Clos/leaf-spine fabric কীভাবে সেগুলো মেটায় — একটি packet-এর যাত্রা ধাপে ধাপে
- Oversubscription, bisection bandwidth, fat-tree-র k³/৪ সূত্র আর spine হারানোর প্রভাব — হাতে কষে আর simulator চালিয়ে
- BGP underlay, VXLAN-EVPN overlay, incast, elephant ও mice flow, ECMP hash collision, RDMA আর AI cluster-এর নেটওয়ার্ক
- L4 ও L7 load balancer, round robin থেকে consistent hashing, health check, draining, GSLB আর availability-র series/parallel হিসাব
১ · Data center কী — rack, server, ToR switch আর বিদ্যুৎ-ঠান্ডার সীমা
আপনি bKash-এ টাকা পাঠালেন, YouTube-এ ভিডিও দেখলেন, বা কোনো AI সহকারীকে প্রশ্ন করলেন — প্রতিটির পেছনে আছে একটি data center: একটি ভবন বা হলঘর, যেখানে সারি সারি লোহার আলমারিতে হাজার হাজার সার্ভার বসানো। আলমারিগুলোকে বলে rack. একটি সাধারণ rack-এ কয়েক ডজন সার্ভার থাকে, আর rack-এর ওপরের দিকে বসে একটি switch — ToR switch (top-of-rack) — rack-এর সব সার্ভার যার সাথে ছোট তারে যুক্ত।
একটি বড় গার্মেন্টস কারখানার কথা ভাবুন। প্রতিটি ফ্লোরে সারি সারি সেলাই মেশিন (সার্ভার), প্রতিটি সারির মাথায় একজন সুপারভাইজার (ToR switch), যিনি সারির কাপড় নিয়ে লিফটে পাঠান। কারখানার উৎপাদন শুধু মেশিনের সংখ্যার ওপর নির্ভর করে না — লিফট আর করিডোর কতটা মাল বইতে পারে, তার ওপরও নির্ভর করে। Data center-এর নেটওয়ার্ক সেই লিফট আর করিডোর।
নেটওয়ার্ক প্রকৌশলীর কাছে data center-এর তিনটি বাস্তব সীমা আছে:
- বিদ্যুৎ: প্রতিটি rack কত kilowatt নিতে পারবে, তা ভবনের নকশায় ঠিক করা। GPU-ভরা rack বহুগুণ বিদ্যুৎ টানে। বিদ্যুৎ গেলে UPS আর জেনারেটর — load-shedding-এর দেশে এর গুরুত্ব আমরা ভালোই বুঝি।
- ঠান্ডা রাখা: খরচ হওয়া প্রায় সব বিদ্যুৎ তাপ হয়ে বেরোয়; rack-গুলো এমনভাবে সাজানো হয় যে সামনে ঠান্ডা বাতাস ঢোকে, পেছনে গরম বাতাস বেরোয়। মোট বিদ্যুৎ ÷ IT যন্ত্রের বিদ্যুৎ — এই অনুপাতকে বলে PUE; ১.০ আদর্শ।
- জায়গা আর তার: নেটওয়ার্কের নকশা যত নিয়মিত, হাজারো তার লাগানো আর ভুল খোঁজা তত সহজ।
Data center মোটামুটি তিন ধরনের:
| ধরন | কে চালায় | আকার ও বৈশিষ্ট্য |
|---|---|---|
| Hyperscale | বড় cloud আর ইন্টারনেট কোম্পানি | একটি ক্যাম্পাসেই লাখো সার্ভার; নিজেদের নকশার switch আর software; সব কিছু স্বয়ংক্রিয় |
| Enterprise (প্রতিষ্ঠানের নিজস্ব) | ব্যাংক, টেলিকম, সরকারি প্রতিষ্ঠান | কয়েকশো থেকে কয়েক হাজার সার্ভার; প্রায়ই সাথে একটি দূরের disaster recovery (DR) site |
| Colocation | ভবন, বিদ্যুৎ আর ঠান্ডা ভাড়া দেয় এমন প্রতিষ্ঠান | গ্রাহক নিজের যন্ত্র এনে ভাড়া করা rack-এ বসান; অনেক ISP আর গ্রাহক একই ভবনে থাকায় সরাসরি যুক্ত হওয়া সহজ |
বাংলাদেশেও সরকারি জাতীয় data center আর বেসরকারি বাণিজ্যিক data center আছে; ব্যাংক আর মোবাইল অপারেটরদের নিজস্ব data center ও DR site থাকে। এদের কেউ কেউ নিজেদের নকশাকে বিদ্যুৎ ও ঠান্ডার বিকল্প ব্যবস্থার মানদণ্ডে “Tier III” বা সমমানের বলে উল্লেখ করে — কোন ভবনের সনদ কী, তা হালনাগাদ অফিসিয়াল তথ্যে দেখে নেওয়াই নিরাপদ। নেটওয়ার্কের নীতিগুলো ছোট সার্ভার-ঘর থেকে বিশাল ক্যাম্পাস পর্যন্ত একই।
২ · ট্রাফিকের দিক — north-south বনাম east-west
Data center-এর ছবি আঁকলে বাইরের ইন্টারনেট সাধারণত ওপরে, সার্ভার নিচে। তাই বাইরে থেকে ভেতরে আসা-যাওয়া ট্রাফিককে বলে north-south, আর ভেতরের সার্ভারে-সার্ভারে ট্রাফিককে east-west.
ধরুন আপনি একটি অনলাইন শপে “অর্ডার দিন” চাপলেন। সামনের সেবা কথা বলে login, cart, দাম, স্টক, পেমেন্ট আর সুপারিশের আলাদা আলাদা ছোট সেবার সাথে — এই নকশাকে বলে microservices. প্রতিটি সেবা আবার ডেটাবেস আর cache-এর কাছে যায়, ডেটাবেস তিনটি কপিতে লেখে। বাইরের একটি ছোট অনুরোধ ভেতরে কয়েক ডজন বা শত শত বার্তা জন্ম দিতে পারে।
এর সাথে আছে নেটওয়ার্কের ওপারের storage, ব্যাকআপ, বড় ডেটা বিশ্লেষণ, আর মেশিন লার্নিং training, যেখানে হাজার হাজার GPU প্রতি ধাপে বিপুল ডেটা বিনিময় করে। শিল্প-প্রতিবেদন আর বড় কোম্পানির প্রকাশিত অভিজ্ঞতা অনুযায়ী আধুনিক data center-এ east-west ট্রাফিকই বাইরের ট্রাফিকের চেয়ে অনেক বেশি — সঠিক অনুপাত কাজের ধরন ভেদে আলাদা।
যে নেটওয়ার্ক বাইরের দরজার দিকে চওড়া আর ভেতরে সরু, সে east-west যুগে জট বাঁধায়। আধুনিক data center-এর লক্ষ্য তাই: যেকোনো সার্ভার যেকোনো সার্ভারের সাথে প্রায় সমান গতিতে, সমান দূরত্বে কথা বলতে পারবে — কোন rack-এ কে বসল, তাতে যেন বেশি কিছু না আসে যায়।
৩ · পুরোনো তিন-স্তরের নকশা — আর কেন সেটি ভেঙে পড়ল
বহু বছর enterprise data center-এর প্রচলিত নকশা ছিল তিন-স্তরের (three-tier): নিচে access switch (প্রতিটি rack-এ), মাঝে aggregation (বা distribution) switch-এর জোড়া, ওপরে কয়েকটি বড় core switch বা router. Access আর aggregation-এর মাঝে সাধারণত layer 2 (VLAN), ওপরে layer 3.
[ Core 1 ]════════[ Core 2 ] ← বড়, দামি chassis
║ ╲ ╱ ║
[ Agg 1 ]═════[ Agg 2 ] ... ← aggregation জোড়া
║ ║ ╲ ╱ ║ ║
[Acc1][Acc2] .... [Acc3][Acc4] ← প্রতিটি rack-এ access
│││ │││ │││ │││
সার্ভার (একটি করে link STP-তে বন্ধ)
উত্তর-দক্ষিণ ট্রাফিকের জন্য নকশাটি যুক্তিসংগত ছিল, কিন্তু তিনটি সমস্যা ক্রমশ বড় হলো:
- STP অর্ধেক link বন্ধ রাখে। প্রতিটি access switch দুটি aggregation switch-এ যুক্ত, যাতে একটি গেলে অন্যটি থাকে। কিন্তু layer 2-তে এতে loop তৈরি হয়, আর STP (পর্ব ১২, Ethernet আর switch) loop ভাঙতে একটি link-কে blocked রাখে। কেনা তারের অর্ধেক বসে থাকে, আর link নষ্ট হলে নতুন গাছ বানানো পর্যন্ত ট্রাফিক থামতে পারে। (MLAG বা vPC-র মতো vendor-কৌশলে দুটি switch-কে একটি LACP bundle-এর দুই প্রান্ত বানিয়ে এটি কিছুটা মেটানো হতো।)
- Oversubscription প্রতিটি স্তরে গুণ হয়। নিচের মোট bandwidth আর ওপরের মোট bandwidth-এর অনুপাতই oversubscription. ধরুন access-এ ৪৮টি সার্ভার ×১০G = ৪৮০G, ওপরে STP-র পরে কার্যত ১০G — অনুপাত ৪৮:১; aggregation থেকে core-এ আবার কয়েক গুণ। দূরের rack-এর সাথে কথা বললে প্রতিটি সার্ভার পায় সামান্য অংশ।
- Chokepoint আর বড় ব্যর্থতার এলাকা। দুই pod-এর মাঝের সব ট্রাফিক কয়েকটি core যন্ত্র দিয়ে যায়; একটি aggregation switch গেলে pod-এর অর্ধেক ক্ষমতা যায়; বড় layer-2 এলাকায় একটি broadcast storm সব অচল করতে পারে। বাড়াতে হলে আরও বড়, আরও দামি chassis — এটি scale-up, যার সীমা আছে।
ঢাকার পুরোনো রাস্তার ছবিটা মিলিয়ে দেখুন: গলি থেকে বড় রাস্তা, বড় রাস্তা থেকে একটি প্রধান মোড়। সবাই একই দিকে (মতিঝিলের অফিসে) গেলে চলে। কিন্তু যখন সবাই সব দিকে যেতে চায়, প্রধান মোড়ে জট লাগে — আর সেই মোড়ে একটি গাড়ি বিকল হলে পুরো এলাকা থেমে যায়।
৪ · Clos আর leaf-spine — প্রতিটি leaf প্রতিটি spine-এ
সমাধান এল একটি পুরোনো ধারণা থেকে। ১৯৫৩ সালে Bell Labs-এর প্রকৌশলী Charles Clos টেলিফোন এক্সচেঞ্জের জন্য দেখান যে অনেকগুলো ছোট switch কয়েকটি স্তরে সাজিয়ে একটি বিশাল, প্রায় বাধাহীন switch বানানো যায় — এই নকশাকে এখন বলে Clos network. অর্ধ শতাব্দীরও বেশি পরে data center একই চিন্তা নিল: একটি বিশাল দামি switch নয়, অনেকগুলো একই রকম সস্তা switch.
দুই স্তরের রূপকে বলে leaf-spine:
- Leaf = প্রতিটি rack-এর ToR switch; নিচে সার্ভার, ওপরে প্রতিটি spine-এ একটি করে uplink.
- Spine = শুধু leaf-দের মাঝে ট্রাফিক বহন করে; spine-এ কোনো সার্ভার নেই, spine-এ spine-এ সরাসরি যোগও নেই।
- নিয়ম একটাই: প্রতিটি leaf প্রতিটি spine-এ যুক্ত।
[Spine1] [Spine2] [Spine3] [Spine4]
║║║║ ║║║║ ║║║║ ║║║║ ← প্রতিটি spine থেকে প্রতিটি leaf-এ ১টি link
╔══╩╩╩╩═══════╩╩╩╩═══════╩╩╩╩═══════╩╩╩╩══╗ (পূর্ণ জাল: ৮ leaf × ৪ spine = ৩২টি link)
[Leaf1] [Leaf2] .... [Leaf7] [Leaf8] ← প্রতিটি leaf-এর ৪টি uplink
│││││ │││││ │││││ │││││
rack 1 rack 2 rack 7 rack 8
এই একটি নিয়ম থেকে চারটি সুবিধা আসে:
- যেকোনো দুই rack-এর দূরত্ব সমান: leaf → spine → leaf, মাঝে মাত্র দুটি link — সবার জন্য প্রায় একই latency.
- সব link একসাথে কাজ করে: Leaf ১ থেকে leaf ৭-এ ৪টি সমান পথ; layer 3 routing এগুলোকে ECMP (পর্ব ২২, Routing-এর ভিত্তি) হিসেবে flow hashing দিয়ে ভাগ করে — কিছুই বসে থাকে না।
- বাড়ানো সহজ (scale-out): আরও সার্ভার? Leaf যোগ করুন। আরও ভেতরের bandwidth? Spine যোগ করুন — যতক্ষণ port আছে।
- ব্যর্থতা ছোট: একটি spine গেলে প্রতিটি leaf তার ক্ষমতার ১/N হারায়।
এবার দেখি rack ১-এর একটি সার্ভার থেকে rack ৭-এর একটি সার্ভারে একটি packet কীভাবে যায়। এখানে fabric পুরোটাই layer 3 — প্রতিটি leaf নিজেই তার rack-এর default gateway (অংশ ৬-এ বিস্তারিত)।
- Server A
10.1.1.10rack ১ - Leaf 1
ECMP ×4ToR - Spine 3
১টি পথhash-এর বাছাই - Leaf 7
connectedToR - Server B
10.1.7.20rack ৭
| কোথায় | |
| IP header | |
| সিদ্ধান্ত |
- Server A packet বানায়। গন্তব্য 10.1.7.20 অন্য subnet-এ, তাই A frame পাঠায় নিজের default gateway 10.1.1.1-এর MAC-এ — এটি Leaf 1 নিজেই। IP header-এ TTL 64.
- Leaf 1 routing table দেখে। 10.1.7.0/24-এর জন্য ৪টি সমান খরচের next hop — চারটি spine, প্রতিটি BGP-তে এই prefix ঘোষণা করেছে। এটিই ECMP-র মুহূর্ত।
- Hash দিয়ে বাছাই। Leaf 1 packet-এর 5-tuple (TCP, উৎস ও গন্তব্য IP আর port) থেকে hash হিসাব করে; ধরা যাক hash mod 4 = 2 — তৃতীয় পথ, Spine 3. TTL এক কমে 63. একই সংযোগের সব packet-এর hash একই, তাই সবাই Spine 3 দিয়েই যাবে — ক্রম ভাঙবে না।
- Spine 3-এর কাজ সহজ। প্রতিটি spine প্রতিটি leaf-এ ঠিক একটি link রাখে, তাই 10.1.7.0/24-এর পথ একটিই: Leaf 7. TTL 62.
- Leaf 7 পৌঁছে দেয়। 10.1.7.0/24 তার নিজের rack-এর subnet; ARP table থেকে Server B-র MAC নিয়ে frame পাঠায়। পৌঁছানোর সময় TTL 61 — পথে তিনটি routing hop, আর দুই rack-এর মাঝে মাত্র দুটি fabric link.
- উত্তর অন্য spine দিয়ে আসতে পারে। B-র উত্তরের 5-tuple উল্টো, তাই Leaf 7-এর hash হয়তো Spine 1 বাছবে। দুই দিকের পথ আলাদা হওয়া (asymmetric routing) এখানে সমস্যা নয় — প্রতিটি দিকের flow নিজের পথে স্থির থাকে।
৫ · Fabric-এর হিসাব — oversubscription, bisection bandwidth, fat-tree আর ব্যর্থতা
Oversubscription — হাতে কষা
একটি leaf-এ ৪৮টি ২৫G port সার্ভারের দিকে আর ৮টি ১০০G port ৮টি spine-এর দিকে:
oversubscription = ১,২০০ ÷ ৮০০ = ১.৫:১ — সব সার্ভার একসাথে rack-এর বাইরে পাঠালে প্রত্যেকে সর্বোচ্চ ২৫ ÷ ১.৫ ≈ ১৬.৭ Gbps পায়
১:১ মানে “non-blocking” — rack-এর বাইরেও পূর্ণ গতি। কেন সবাই ১:১ রাখে না? দাম। Uplink port, optics আর spine সবচেয়ে দামি অংশ, আর বাস্তবে সব সার্ভার একসাথে পূর্ণ গতিতে বাইরে পাঠায় না। সাধারণ ওয়েব সেবায় ৩:১ চলতে পারে; storage বা AI training-এর fabric প্রায়ই ১:১-এর কাছাকাছি রাখা হয়।
Bisection bandwidth
নেটওয়ার্ককে ঠিক মাঝখান দিয়ে দুই সমান ভাগে কাটলে দুই ভাগের মাঝে সবচেয়ে খারাপ ক্ষেত্রে যত bandwidth পাওয়া যায়, সেটাই bisection bandwidth. বাঁ অর্ধেকের সব সার্ভার একসাথে ডান অর্ধেকে পাঠালে নেটওয়ার্ক মোট কত বইতে পারবে — এটি তার মাপ। Leaf-spine-এ অর্ধেক leaf-এর মোট uplink-ই সেই সীমা: ১৬টি leaf, প্রতিটির uplink ৮০০G হলে ৮ × ৮০০G = ৬.৪ Tbps.
Switch-এর port সংখ্যা থেকে সর্বোচ্চ আকার
একটি switch-এ কয়টি port আছে, তাকে বলে তার radix; ধরা যাক k. দুই স্তরের leaf-spine-এ প্রতিটি spine-এর প্রতিটি port একটি leaf-এ যায়, তাই সর্বোচ্চ k-টি leaf. ১:১ রাখতে প্রতিটি leaf-এর অর্ধেক port নিচে, অর্ধেক ওপরে — তাই সর্বোচ্চ সার্ভার k × k/২ = k²/২. ৬৪-port switch দিয়ে ২,০৪৮টি — একটি বড় অফিসের জন্য যথেষ্ট, hyperscale-এর জন্য নয়। তখন যোগ হয় তৃতীয় স্তর।
২০০৮ সালে Al-Fares ও সহকর্মীদের একটি পরিচিত গবেষণাপত্র দেখায় যে শুধু একই রকম সস্তা k-port switch দিয়ে তিন স্তরের একটি fat-tree বানানো যায়, যার সব স্তরে ১:১ ক্ষমতা। গঠনটি এরকম:
- মোট k-টি pod. প্রতিটি pod-এ k/২টি edge (leaf) আর k/২টি aggregation switch.
- প্রতিটি edge switch-এর k/২ port সার্ভারে, k/২ port pod-এর প্রতিটি aggregation switch-এ।
- প্রতিটি aggregation switch-এর k/২ port নিচে, k/২ port ওপরে core-এ। Core switch (k/২)² = k²/৪টি, প্রতিটির k-টি port প্রতিটি pod-এ একটি করে।
switch = k² (pod-এর ভেতরে) + k²/৪ (core) = ৫k²/৪; k = ৪৮ হলে ২৭,৬৪৮টি host, ২,৮৮০টি switch
এবার এসব হিসাব একসাথে একটি simulator-এ। প্রথম fabric ওপরের উদাহরণ; দ্বিতীয়টি একটু পুরোনো ধাঁচের — ১০G সার্ভার, ৪টি ৪০G uplink. শেষে k-এর কয়েকটি মানে দুই স্তর আর fat-tree-র তুলনা।
// Leaf-spine fabric calculator: every leaf has one uplink to every spine.
function fabric(name, leaves, spines, down, downG, upG, spinePorts) {
const serverBw = down * downG, upBw = spines * upG; // per leaf, Gbps
const ratio = serverBw / upBw; // oversubscription
const bisect = Math.min(leaves / 2 * upBw, leaves / 2 * serverBw);
const left = (spines - 1) * upG; // uplink after 1 spine dies
console.log(name);
console.log(" servers now " + leaves * down + ", max with " + spinePorts +
"-port spines " + spinePorts * down + " (" + spinePorts + " leaves)");
console.log(" per leaf: down " + serverBw + "G, up " + upBw + "G -> oversubscription " +
ratio.toFixed(2) + ":1");
console.log(" bisection bandwidth " + (bisect / 1000).toFixed(1) + " Tbps");
console.log(" one spine down: uplink " + left + "G (" + (100 * left / upBw).toFixed(1) +
"% left), ratio " + (serverBw / left).toFixed(2) + ":1");
}
fabric("A) 16 leaves, 8 spines, 48x25G down, 8x100G up", 16, 8, 48, 25, 100, 64);
fabric("B) 20 leaves, 4 spines, 48x10G down, 4x40G up", 20, 4, 48, 10, 40, 32);
console.log("k-port switches: 2-tier leaf-spine (k/2 down per leaf) vs 3-tier fat tree");
console.log(" k 2-tier hosts fat-tree hosts fat-tree switches");
for (const k of [4, 8, 16, 48, 64]) {
const two = k * k / 2, fat = k ** 3 / 4, sw = 5 * k * k / 4;
console.log(String(k).padStart(5) + String(two).padStart(15) + String(fat).padStart(17) +
String(sw).padStart(20));
}আউটপুট:
A) 16 leaves, 8 spines, 48x25G down, 8x100G up
servers now 768, max with 64-port spines 3072 (64 leaves)
per leaf: down 1200G, up 800G -> oversubscription 1.50:1
bisection bandwidth 6.4 Tbps
one spine down: uplink 700G (87.5% left), ratio 1.71:1
B) 20 leaves, 4 spines, 48x10G down, 4x40G up
servers now 960, max with 32-port spines 1536 (32 leaves)
per leaf: down 480G, up 160G -> oversubscription 3.00:1
bisection bandwidth 1.6 Tbps
one spine down: uplink 120G (75.0% left), ratio 4.00:1
k-port switches: 2-tier leaf-spine (k/2 down per leaf) vs 3-tier fat tree
k 2-tier hosts fat-tree hosts fat-tree switches
4 8 16 20
8 32 128 80
16 128 1024 320
48 1152 27648 2880
64 2048 65536 5120
(A) হাতে কষা হিসাবের সাথে মিলছে: ১,২০০G নিচে, ৮০০G ওপরে, ১.৫০:১. ১৬টি leaf-এ ৭৬৮টি সার্ভার; ৬৪-port spine থাকায় leaf বাড়ানো যায় ৬৪টি পর্যন্ত, তখন ৩,০৭২টি সার্ভার। Bisection ৬.৪ Tbps. একটি spine গেলে uplink ৭০০G — ৮৭.৫% রইল (১/৮ গেল), অনুপাত ১.৭১:১। (B) মাত্র ৪টি spine থাকায় একটি হারালেই ২৫% যায় আর অনুপাত ৩:১ থেকে ৪:১ — spine যত বেশি, প্রতিটির ব্যর্থতা তত ছোট। শেষ টেবিলে দুই স্তরের k²/২ আর fat-tree-র k³/৪-এর ফারাক দেখুন: k = ৬৪-তে ২,০৪৮ বনাম ৬৫,৫৩৬ — তৃতীয় স্তর আকার k/২ গুণ বাড়ায়। নিজে চেষ্টা করুন: (A)-তে spine ৮ থেকে ১২ করুন (uplink ১২টি ধরে) — অনুপাত কত হলো?
ব্যর্থতায় তিন-স্তর বনাম leaf-spine
একই ব্যর্থতায় দুই নকশা কী করে, পাশাপাশি দেখি। বাঁ দিকে একটি access switch (A1) দুটি aggregation switch-এ ১০G করে যুক্ত; ডান দিকে একটি leaf (L1) চারটি spine-এ ৪০G করে যুক্ত।
- স্বাভাবিক
সব linkশুরু - Link কাটা
uplinkব্যর্থতা - Convergence
সময়নতুন পথ - ক্ষমতা
Gbpsপরে - Switch নষ্ট
Agg / Spineবড় ব্যর্থতা
| তিন-স্তর (A1) | |
| Leaf-spine (L1) |
- স্বাভাবিক অবস্থা। তিন-স্তরে A1-এর দুটি uplink-এর একটি STP বন্ধ রেখেছে — কেনা ২০G-এর মধ্যে চলে ১০G. Leaf-spine-এ L1-এর চারটি uplink-ই ECMP-তে সক্রিয় — পুরো ১৬০G.
- সক্রিয় একটি uplink কেটে গেল। তিন-স্তরে কাটল ঠিক সেই forwarding link — A1-এর এখন কোনো চালু পথ নেই। Leaf-spine-এ L1–S2 কাটল; link down সংকেত বা BFD খুব দ্রুত টের পায়।
- নতুন পথ কত দ্রুত? তিন-স্তরে STP-কে blocked port খুলতে হয়: ক্লাসিক STP-র ডিফল্ট timer-এ ৩০–৫০ সেকেন্ড, RSTP-তে সাধারণত অনেক কম — তবু ততক্ষণ পুরো rack বিচ্ছিন্ন। Leaf-spine-এ routing শুধু ECMP group থেকে একটি next hop সরায়; যে flow-গুলো S2 দিয়ে যাচ্ছিল, শুধু সেগুলো অন্য পথে যায়।
- ব্যর্থতার পরের ক্ষমতা। তিন-স্তরে ১০G — আগের মতোই, কারণ বাড়তি link এতদিন বসে ছিল; কিন্তু মাঝে একটি বিভ্রাট গেছে। Leaf-spine-এ ১২০G, অর্থাৎ ৭৫% — সেবা এক মুহূর্তও থামেনি, শুধু একটু সরু হয়েছে।
- পুরো switch নষ্ট হলে। তিন-স্তরে Agg1 গেলে pod-এর সব ট্রাফিক Agg2-এর ঘাড়ে — aggregation-এর ক্ষমতা অর্ধেক, আর Agg2-ই এখন একমাত্র ভরসা। Leaf-spine-এ চারটি spine-এর একটি গেলে প্রতিটি leaf ১/৪ হারায়; সবাই ৭৫%-এ, কোনো একক যন্ত্রে চাপ জমে না। Spine ৮টি হলে ক্ষতি মাত্র ১২.৫%.
৬ · Fabric-এর routing — L3 পর্যন্ত ToR, BGP underlay আর VXLAN-EVPN overlay
Leaf-spine-এ প্রতিটি leaf সাধারণত একটি layer-3 switch: rack-এর সার্ভারদের subnet-এর gateway সে নিজেই, আর leaf-spine-এর প্রতিটি link একটি ছোট point-to-point IP link. ফলে layer 2-এর এলাকা একটি rack-এর ভেতরে সীমিত, STP-র দরকার প্রায় নেই, broadcast storm rack-এর বাইরে যায় না। একে বলে “L3 to the ToR”.
Leaf আর spine-এর মাঝে route কে জানায়? এই ভৌত IP নেটওয়ার্ককে বলে underlay, আর এর routing protocol দুই রকম হয়:
- OSPF বা IS-IS (পর্ব ২৪, Link state routing) — ছোট-মাঝারি fabric-এ প্রচলিত, পরিচিত আর সরল।
- BGP (পর্ব ২৫, BGP আর ইন্টারনেটের গঠন) — বড় fabric-এ জনপ্রিয়। RFC 7938 (২০১৬) এর নকশা বর্ণনা করে: প্রতিটি leaf আর spine-স্তর আলাদা private ASN পায়, প্রতিটি link-এ eBGP session. BGP বিপুল সংখ্যক route সামলাতে অভ্যস্ত, নীতি দিয়ে নিয়ন্ত্রণ সহজ, আর ব্যর্থতার প্রভাব কাছাকাছি থাকে। BGP-র multipath বিকল্প চালু থাকলে চারটি spine থেকে শেখা একই prefix ECMP হয়ে যায়।
তাহলে layer 2 লাগলে? — VXLAN-EVPN overlay
সব অ্যাপ layer 3-এ খুশি নয়। একটি virtual machine অন্য rack-এ সরালে তার IP বদলানো যায় না; কিছু পুরোনো cluster software একই subnet চায়; আর cloud-এ প্রতিটি গ্রাহক (tenant) নিজের আলাদা নেটওয়ার্ক চায়, যার ঠিকানা অন্যের সাথে মিলেও যেতে পারে। সমাধান overlay: IP underlay-এর ওপর tunnel দিয়ে virtual layer 2.
পর্ব ১৩-এ (VLAN আর trunking) দেখেছেন, VXLAN Ethernet frame-কে UDP-র ভেতরে মুড়ে পাঠায়, আর ২৪ bit-এর VNI দিয়ে প্রায় ১.৬৮ কোটি আলাদা segment দেয় — VLAN-এর ৪,০৯৪-এর সীমা আর থাকে না। Tunnel-এর দুই প্রান্ত সাধারণত leaf switch নিজেই (বা সার্ভারের ভেতরের virtual switch); এই প্রান্তকে বলে VTEP.
বাকি প্রশ্ন: কোন MAC বা IP কোন VTEP-এর পেছনে আছে, তা সবাই জানবে কীভাবে? পুরোনো উপায় ছিল flood করে শেখা। আধুনিক উপায় EVPN: BGP-কেই control plane বানিয়ে প্রতিটি leaf ঘোষণা করে “এই MAC আর IP আমার পেছনে, এই VNI-তে” (মূল মান RFC 7432, VXLAN-এর সাথে ব্যবহার RFC 8365). ফলে অচেনা ঠিকানার জন্য flooding কমে, আর প্রতিটি leaf একই anycast gateway ঠিকানা রাখতে পারে — VM যে rack-এই যাক, gateway একই।
কে কোন স্তরে? Underlay (OSPF বা eBGP) শুধু leaf আর spine-এর loopback ঠিকানা চেনে; overlay (EVPN) চেনে tenant-এর MAC আর IP. Spine overlay সম্পর্কে কিছুই জানে না — সে শুধু UDP packet ECMP দিয়ে এগিয়ে দেয়। Control plane পুরোটা কেন্দ্রীয় software থেকে চালানোর গল্প পর্ব ৫৩-এ (Software-defined networking আর NFV), আর cloud-এর VPC ও container নেটওয়ার্ক পর্ব ৫৪-এ (Cloud আর container নেটওয়ার্কিং)।
৭ · Data center-এর transport — incast, elephant ও mice, ECMP collision আর RDMA
Data center-এর ভেতরে RTT মাইক্রোসেকেন্ডের ঘরে, link খুব দ্রুত, আর অনেক switch-এর buffer তুলনামূলক ছোট। ইন্টারনেটের জন্য বানানো TCP এখানে কিছু অদ্ভুত সমস্যায় পড়ে।
Incast — সবাই একসাথে উত্তর দিলে
একটি search বা ডেটাবেস প্রশ্ন প্রায়ই এভাবে চলে: একটি aggregator সার্ভার একসাথে ৪০টি worker-কে প্রশ্ন পাঠায়, সবাই প্রায় একই মুহূর্তে উত্তর দেয় — সব উত্তর গিয়ে পড়ে aggregator-এর ToR port-এ। এই many-to-one ধাঁচকে বলে incast.
buffer উপচে পড়ে → কয়েকটি worker-এর পুরো window হারায় → duplicate ACK আসে না → RTO-র অপেক্ষা। Linux-এ ন্যূনতম RTO সাধারণত ২০০ ms, অথচ RTT ধরা যাক ১০০ µs — অপেক্ষা RTT-র প্রায় ২,০০০ গুণ
একটি worker দেরি করলে পুরো উত্তর দেরি করে, কারণ aggregator সবার উত্তরের অপেক্ষায় থাকে — তাই data center-এ গড় নয়, tail latency (সবচেয়ে ধীর ১% বা ০.১%) আসল মাপ। প্রতিকার কয়েক রকম: ছোট ন্যূনতম RTO, অনুরোধ ধাপে ধাপে পাঠানো বা উত্তরের আকার সীমিত রাখা, আর DCTCP (পর্ব ৩২, TCP congestion control) — যেখানে switch queue একটু বাড়লেই ECN দাগ দেয় আর প্রেরক দাগের অনুপাতে অল্প অল্প গতি কমায়, ফলে queue ছোট থাকে আর হঠাৎ ঢেউয়ের জন্য জায়গা থাকে।
Elephant আর mice — আর ECMP-র hash collision
প্রকাশিত বিভিন্ন পরিমাপে data center-এ একটি ধাঁচ বারবার দেখা গেছে: বেশিরভাগ flow ছোট (mice — কয়েক KB-র RPC), কিন্তু বেশিরভাগ বাইট বহন করে অল্প কয়েকটি বড় flow (elephant — ব্যাকআপ, VM সরানো, বড় ফাইল)। ECMP-র per-flow hash দুই ধরনের flow-কে আলাদা চেনে না — hash শুধু ঠিক করে কে কোন পথে। দুটি elephant এক link-এ পড়লে সেই link ভরে যায়, পাশের link ফাঁকা থাকে, আর একই link-এর mice-গুলো queue-তে আটকে tail latency বাড়ায়।
নিচের simulator-এ ৪টি spine uplink, প্রতিটি ৪০G. চারটি elephant (প্রতিটি ২০G) আর ২৪টি mice (প্রতিটি ০.৫G) — মোট ৯২G, যা ১৬০G-এর মধ্যে সহজেই ধরে। প্রথমে সাধারণ per-flow ECMP; তারপর flowlet switching — elephant-এর ভেতরের ছোট বিরতিগুলোতে (যখন পথ বদলালেও ক্রম ভাঙার ভয় নেই) প্রতিটি “ঝলক” নতুন করে hash করা; শেষে আদর্শ packet spraying, যেখানে প্রতিটি packet আলাদা পথে যায়।
// ECMP over 4 spine uplinks (40 Gbps each): per-flow hash vs flowlets.
function fnv(s) { // FNV-1a 32-bit hash of a string
let h = 0x811c9dc5;
for (const c of s) h = Math.imul(h ^ c.charCodeAt(0), 0x01000193) >>> 0;
return h;
}
const LINKS = 4, CAP = 40, flows = [];
for (let i = 0; i < 4; i++) flows.push({ id: "10.0.1." + (10 + i) + ":" + (40000 + 7 * i), gbps: 20 });
for (let i = 0; i < 24; i++) flows.push({ id: "10.0.1." + (20 + i) + ":" + (50000 + 13 * i), gbps: 0.5 });
function show(title, load) {
const max = Math.max(...load), min = Math.min(...load);
console.log(title);
console.log(" per-link Gbps: " + load.map(x => x.toFixed(1).padStart(5)).join(" ") +
" | max/min " + (max / min).toFixed(2) + (max > CAP ? " | OVERLOAD on a 40G link" : " | fits"));
}
let load = Array(LINKS).fill(0); // 1) classic: whole flow hashed once
for (const f of flows) load[fnv(f.id + "->10.0.7.5:443/6") % LINKS] += f.gbps;
show("Per-flow ECMP (5-tuple hash):", load);
console.log(" elephants on links: " + flows.slice(0, 4).map(f => fnv(f.id + "->10.0.7.5:443/6") % LINKS).join(", "));
load = Array(LINKS).fill(0); // 2) flowlets: each burst re-hashed
for (const f of flows) {
const bursts = f.gbps >= 10 ? 8 : 1; // elephants pause often -> 8 flowlets
for (let b = 0; b < bursts; b++) load[fnv(f.id + "#" + b) % LINKS] += f.gbps / bursts;
}
show("Flowlet switching (re-hash each burst):", load);
const total = flows.reduce((a, f) => a + f.gbps, 0);
show("Packet spraying (ideal round robin):", Array(LINKS).fill(total / LINKS));আউটপুট:
Per-flow ECMP (5-tuple hash):
per-link Gbps: 43.0 3.0 22.0 24.0 | max/min 14.33 | OVERLOAD on a 40G link
elephants on links: 0, 2, 3, 0
Flowlet switching (re-hash each burst):
per-link Gbps: 24.0 22.0 23.0 23.0 | max/min 1.09 | fits
Packet spraying (ideal round robin):
per-link Gbps: 23.0 23.0 23.0 23.0 | max/min 1.00 | fits
Per-flow ECMP-তে দুটি elephant একই link 0-তে পড়েছে: ২০ + ২০ + কয়েকটি mice-এর ৩G = ৪৩G — ৪০G link-এ জায়গা নেই, অথচ link 1-এ মাত্র ৩G. মোট চাহিদা ক্ষমতার মাত্র ৫৭.৫% (৯২ ÷ ১৬০), তবু একটি link উপচে পড়ছে, max/min ১৪.৩৩। ৪টি elephant ৪টি link-এ এলোমেলোভাবে পড়লে সবাই আলাদা link পাওয়ার সম্ভাবনা মাত্র ৪!/৪⁴ ≈ ৯.৪% — তাই collision ব্যতিক্রম নয়, স্বাভাবিক। Flowlet-এ প্রতিটি elephant ৮টি ঝলকে ভাগ হয়ে চার link-এ ছড়িয়েছে: ২২–২৪G, max/min ১.০৯. Packet spraying নিখুঁত ২৩G করে দেয়, কিন্তু বাস্তবে packet-এর ক্রম ভাঙে, তাই প্রাপকের দিকে পুনর্বিন্যাস সহ্য করার ব্যবস্থা লাগে। (Hash ফাংশনটি FNV-1a; বাস্তব switch ASIC-এর hash আলাদা, ধাঁচ একই।)
বাস্তবে switch নিজে link-এর ভিড় দেখেও flowlet-এর পথ বাছতে পারে (CONGA-র মতো গবেষণা)। মূল আপস একই: যত সূক্ষ্মভাবে ভাগ, ভার তত সমান, কিন্তু ক্রম ভাঙার ঝুঁকি তত বেশি।
RDMA, RoCE আর lossless Ethernet
Storage আর AI-এর মতো কাজে TCP/IP stack-এর CPU খরচ আর দেরিও বোঝা। RDMA (remote direct memory access)-এ এক সার্ভারের network card সরাসরি অন্য সার্ভারের মেমরিতে লেখে বা পড়ে — দুই দিকের OS kernel প্রায় বাইরে থাকে। এর নিজস্ব নেটওয়ার্ক InfiniBand; Ethernet-এর ওপর রূপটিকে বলে RoCE (RDMA over Converged Ethernet; সংস্করণ ২ চলে UDP/IP-এর ওপর, তাই route করা যায়)।
সমস্যা: প্রচলিত RoCE-র transport loss খুব খারাপ সহ্য করে — packet হারালে বড় অংশ আবার পাঠাতে হয়। তাই নেটওয়ার্ককে প্রায় “lossless” বানানো হয় PFC (priority flow control, IEEE 802.1Qbb) দিয়ে: switch-এর buffer ভরার আগেই আগের যন্ত্রকে নির্দিষ্ট অগ্রাধিকার-শ্রেণির জন্য থামতে বলে — Ethernet-এর PAUSE frame-এর (IEEE 802.3x, পর্ব ৩১-এ উল্লেখ আছে) অগ্রাধিকার-ভিত্তিক রূপ। দাম আছে: একটি জট থেকে “থামুন” বার্তা পেছনে ছড়িয়ে নির্দোষ flow-কেও থামাতে পারে (pause storm), বিরল ক্ষেত্রে deadlock-ও সম্ভব। তাই PFC-র সাথে সাধারণত ECN-ভিত্তিক congestion control চালানো হয়, যাতে pause কদাচিৎ লাগে।
AI training cluster-এর নেটওয়ার্ক
বড় মডেল training-এ হাজার হাজার GPU প্রতিটি ধাপের শেষে নিজেদের হিসাব (gradient) মিলিয়ে নেয় — এই সম্মিলিত কাজকে বলে all-reduce. সবচেয়ে ধীর GPU-র ডেটা না পৌঁছালে কেউ এগোতে পারে না, তাই এখানেও tail-ই নির্ধারক। প্রকাশিত নকশাগুলোতে প্রতিটি GPU-র জন্য কয়েকশো Gbps-এর link, ১:১-এর কাছাকাছি fabric আর RDMA সাধারণ; ট্রাফিক অল্প কয়েকটি বিশাল, একসাথে শুরু হওয়া flow — ECMP collision-এর সবচেয়ে খারাপ ধাঁচ। এই ক্ষেত্রের গবেষণা আর মান খুব দ্রুত বদলাচ্ছে।
৮ · Load balancer — L4 আর L7, algorithm, health check আর draining
একটি সার্ভার যত শক্তিশালীই হোক, লাখো ব্যবহারকারী সামলাতে পারে না, আর সেটি নষ্ট হলে সেবা বন্ধ। সমাধান: একই সেবার অনেকগুলো কপি (backend), আর সামনে একটি load balancer (LB), যে প্রতিটি সংযোগ বা অনুরোধ কোনো একটি সুস্থ backend-এ পাঠায়। ক্লায়েন্ট দেখে একটিমাত্র ঠিকানা — VIP (virtual IP).
ব্যাংকের শাখায় টোকেন মেশিনের কথা ভাবুন। গ্রাহক জানেন না কোন কাউন্টার খালি; টোকেন ব্যবস্থা ঠিক করে কে কোন কাউন্টারে যাবেন। কোনো কাউন্টারের কর্মকর্তা দুপুরের খাবারে গেলে সেই কাউন্টারে নতুন টোকেন যায় না, কিন্তু যিনি আগে থেকেই সেখানে আছেন, তাঁর কাজ শেষ করা হয় — এটিই health check আর draining.
L4 বনাম L7
| বিষয় | L4 load balancer | L7 load balancer |
|---|---|---|
| কী দেখে | IP আর TCP/UDP header — 5-tuple | পুরো HTTP অনুরোধ: path, Host, header, cookie |
| সিদ্ধান্তের একক | সংযোগ (একটি TCP সংযোগের সব packet একই backend-এ) | প্রতিটি অনুরোধ (একই সংযোগের দুটি অনুরোধ দুই backend-এ যেতে পারে) |
| TLS | খোলে না, এনক্রিপ্টেড বাইট সোজা পাঠায় | সাধারণত TLS termination করে (পর্ব ৪৮, TLS আর HTTPS) |
| সুবিধা | খুব দ্রুত, যেকোনো protocol, প্রতি সংযোগে কম খরচ | path ধরে routing (/api এক দলে, /static আরেক দলে), header যোগ, retry, cache, WAF |
| উদাহরণ | Linux IPVS, cloud-এর network LB, Maglev-ধাঁচের ব্যবস্থা | nginx, HAProxy, Envoy, cloud-এর application LB |
L7 LB আসলে একটি reverse proxy (পর্ব ৩৮, Web cache, proxy আর CDN): ক্লায়েন্টের সংযোগ সে নিজে শেষ করে, backend-এর সাথে আলাদা সংযোগ খোলে। ফলে backend ক্লায়েন্টের আসল IP দেখে না — তাই LB X-Forwarded-For header-এ সেটি যোগ করে।
L4-এ উত্তর ফেরার দুই পথ: NAT আর DSR
L4 LB সাধারণত দুইভাবে চলে। NAT মোডে LB গন্তব্য-ঠিকানা VIP থেকে backend-এর ঠিকানায় বদলায় (পর্ব ১৯-এর DNAT), আর উত্তরও LB দিয়েই ফেরে — সহজ, কিন্তু সব উত্তর-ট্রাফিক LB-র ঘাড়ে। DSR (direct server return)-এ backend-ও VIP ঠিকানাটি নিজের loopback-এ রাখে; LB শুধু অনুরোধ পৌঁছে দেয় (MAC বদলে বা tunnel করে), আর backend উত্তর সরাসরি ক্লায়েন্টকে পাঠায়। ওয়েবে উত্তর সাধারণত অনুরোধের চেয়ে অনেক বড় (ছোট GET, বড় ভিডিও), তাই DSR-এ LB-কে খুব কম ট্রাফিক বইতে হয়। আপস: LB উত্তর দেখে না, তাই L7-এর কাজ বা TLS termination সেখানে সম্ভব নয়।
কোন backend? — algorithm
- Round robin: পালা করে — ১, ২, ৩, ৪, ১, ২… সরল, কিন্তু কোন অনুরোধ কতটা ভারী তা জানে না।
- Weighted round robin: দ্বিগুণ শক্তিশালী সার্ভার দ্বিগুণ পালা পায়।
- Least connections: এই মুহূর্তে যার হাতে সবচেয়ে কম চলমান সংযোগ বা অনুরোধ, তাকে দেওয়া। ধীর অনুরোধে আটকে থাকা সার্ভার স্বাভাবিকভাবেই কম নতুন কাজ পায়।
- Hash-ভিত্তিক: ক্লায়েন্ট IP, user ID বা cache key থেকে hash — একই key সবসময় একই backend-এ। Cache-এর জন্য দারুণ, কিন্তু কিছু key বেশি জনপ্রিয় হলে ভার অসমান।
নিচের simulator-এ ৪টি backend, প্রতিটি একসাথে একটি অনুরোধ সামলায় (বাকিরা লাইনে)। প্রতি ৮ ms-এ একটি অনুরোধ আসে; প্রায় ১৫% ভারী (১২০ ms), বাকিরা হালকা (১০ ms); প্রতিটি অনুরোধ ৩০ জন ব্যবহারকারীর কোনো একজনের। তিনটি algorithm একই trace-এ:
// Load-balancer simulator: 4 backends, each serves one request at a time (FIFO).
let seed = 7;
const rnd = () => (seed = seed * 16807 % 2147483647) / 2147483647; // Park-Miller PRNG
function hash(s) { // FNV-1a + a final bit-mixing step
let h = 0x811c9dc5;
for (const c of s) h = Math.imul(h ^ c.charCodeAt(0), 16777619);
h = Math.imul(h ^ (h >>> 16), 0x85ebca6b); h = Math.imul(h ^ (h >>> 13), 0xc2b2ae35);
return (h ^ (h >>> 16)) >>> 0;
}
const ring = []; // consistent-hash ring: 50 virtual nodes per backend
for (let b = 0; b < 4; b++) for (let v = 0; v < 50; v++) ring.push([hash("be" + b + "-" + v), b]);
ring.sort((x, y) => x[0] - y[0]);
const owner = h => (ring.find(p => p[0] >= h) || ring[0])[1];
const trace = []; // one request every 8 ms; ~15% are heavy
for (let i = 0; i < 400; i++)
trace.push({ t: i * 8, cost: rnd() < 0.15 ? 120 : 10, user: "u" + Math.floor(rnd() * 30) });
function run(name, pick) {
const freeAt = [0, 0, 0, 0], ends = [[], [], [], []], work = [0, 0, 0, 0], lat = [];
trace.forEach((r, i) => {
const active = ends.map(e => e.filter(x => x > r.t).length); // in-flight now
const b = pick(i, r, active);
const start = Math.max(r.t, freeAt[b]);
freeAt[b] = start + r.cost; ends[b].push(freeAt[b]); work[b] += r.cost;
lat.push(freeAt[b] - r.t);
});
lat.sort((a, b) => a - b);
const avg = lat.reduce((a, b) => a + b) / lat.length;
console.log(name.padEnd(18) + "work ms" + work.map(w => String(w).padStart(6)).join("") +
" | avg " + avg.toFixed(0).padStart(4) + " ms | p99 " + String(lat[Math.floor(0.99 * lat.length)]).padStart(4) + " ms");
}
console.log("total work " + trace.reduce((a, r) => a + r.cost, 0) + " ms in " + 400 * 8 + " ms on 4 backends");
run("Round robin", i => i % 4);
run("Least connections", (i, r, act) => act.indexOf(Math.min(...act)));
run("Consistent hash", (i, r) => owner(hash(r.user)));আউটপুট:
total work 10380 ms in 3200 ms on 4 backends
Round robin work ms 2870 2650 2540 2320 | avg 102 ms | p99 450 ms
Least connections work ms 2910 2690 2620 2160 | avg 50 ms | p99 240 ms
Consistent hash work ms 2710 1840 3180 2650 | avg 111 ms | p99 568 ms
মোট কাজ ১০,৩৮০ ms, সময় ৩,২০০ ms, ৪টি backend — গড় ব্যবহার ১০,৩৮০ ÷ (৪ × ৩,২০০) ≈ ৮১%, অর্থাৎ বেশ ব্যস্ত সময়। Round robin-এ মোট কাজ মোটামুটি সমান ভাগ হয়েছে, তবু গড় অপেক্ষা ১০২ ms আর p99 ৪৫০ ms — কারণ পালা আসলে সে ভারী অনুরোধে ব্যস্ত সার্ভারেও কাজ পাঠায়, আর হালকা অনুরোধ ভারী অনুরোধের পেছনে আটকে যায়। Least connections একই trace-এ গড় অর্ধেকের কম (৫০ ms) আর p99 ২৪০ ms — সে দেখে কে এখন ফাঁকা। Consistent hash-এ একজন ব্যবহারকারীর সব অনুরোধ একই backend-এ যায়; কিছু ব্যবহারকারী বেশি সক্রিয় হওয়ায় তৃতীয় backend পেয়েছে ৩,১৮০ ms কাজ আর দ্বিতীয়টি মাত্র ১,৮৪০ — গড় ১১১ ms, p99 ৫৬৮ ms. তাহলে hash কেন? কারণ তার লক্ষ্য ভার সমান করা নয়, একই key-কে একই জায়গায় রাখা — cache বা session-এর জন্য, যা পরের simulator দেখাবে।
Consistent hashing — backend বদলালে কত key সরে?
সরল hash-ভিত্তিক LB লেখে backend = hash(key) mod N. সমস্যা: N বদলালেই প্রায় সব key-র ঘর বদলায়। প্রতিটি backend যদি নিজের key-গুলোর cache বা session রাখে, একটি সার্ভার যোগ করলেই প্রায় পুরো cache অকেজো — আর সব অনুরোধ একসাথে ডেটাবেসে ছুটে যায়।
Consistent hashing (Karger ও সহকর্মীরা, ১৯৯৭) একটি বৃত্ত কল্পনা করে: backend আর key দুটোকেই একই hash দিয়ে বৃত্তে বসানো হয়; প্রতিটি key ঘড়ির কাঁটার দিকে প্রথম যে backend পায়, সেটিই তার মালিক। নতুন backend E এলে সে বৃত্তের কিছু জায়গা নেয়, আর শুধু সেই জায়গার key-গুলো E-তে যায় — বাকিরা নড়ে না। N থেকে N+১ হলে আদর্শভাবে মাত্র ১/(N+১) অংশ সরে। একটি backend-কে বৃত্তে একবার নয়, অনেকগুলো virtual node হিসেবে বসালে ভাগও সমান হয়।
// How many keys move when a backend is added or removed? modulo vs consistent hashing
function hash(s) { // FNV-1a + a final bit-mixing step
let h = 0x811c9dc5;
for (const c of s) h = Math.imul(h ^ c.charCodeAt(0), 16777619);
h = Math.imul(h ^ (h >>> 16), 0x85ebca6b); h = Math.imul(h ^ (h >>> 13), 0xc2b2ae35);
return (h ^ (h >>> 16)) >>> 0;
}
const keys = Array.from({ length: 10000 }, (_, i) => hash("session-" + i));
function ring(backends, vnodes) { // sorted [point, backend] pairs
const r = [];
for (const b of backends) for (let v = 0; v < vnodes; v++) r.push([hash(b + "#" + v), b]);
return r.sort((x, y) => x[0] - y[0]);
}
function lookup(r, h) { // binary search: first point >= h, wrap around
let lo = 0, hi = r.length;
while (lo < hi) { const m = (lo + hi) >> 1; if (r[m][0] < h) lo = m + 1; else hi = m; }
return r[lo % r.length][1];
}
const moved = (f, g) => (100 * keys.filter(k => f(k) !== g(k)).length / keys.length).toFixed(1) + "%";
const four = ["A", "B", "C", "D"], five = [...four, "E"], three = ["A", "B", "C"];
console.log("change modulo consistent(100 vnodes)");
const R4 = ring(four, 100), R5 = ring(five, 100), R3 = ring(three, 100);
console.log("add E 4->5 " + moved(k => k % 4, k => k % 5).padStart(7) + moved(k => lookup(R4, k), k => lookup(R5, k)).padStart(12));
console.log("drop D 4->3" + moved(k => k % 4, k => k % 3).padStart(7) + moved(k => lookup(R4, k), k => lookup(R3, k)).padStart(12));
for (const vn of [1, 10, 100, 1000]) { // balance: how even is each backend's share?
const r = ring(four, vn), count = { A: 0, B: 0, C: 0, D: 0 };
for (const k of keys) count[lookup(r, k)]++;
const c = Object.values(count);
console.log("vnodes " + String(vn).padStart(4) + ": keys per backend " + c.join(" / ") +
" max/avg " + (Math.max(...c) / 2500).toFixed(2));
}আউটপুট:
change modulo consistent(100 vnodes)
add E 4->5 79.9% 25.5%
drop D 4->3 74.7% 25.0%
vnodes 1: keys per backend 2457 / 1510 / 5477 / 556 max/avg 2.19
vnodes 10: keys per backend 2419 / 2827 / 1948 / 2806 max/avg 1.13
vnodes 100: keys per backend 2701 / 2569 / 2228 / 2502 max/avg 1.08
vnodes 1000: keys per backend 2380 / 2628 / 2513 / 2479 max/avg 1.05
Modulo-তে ৪ থেকে ৫ করলে ৭৯.৯% key সরে — তত্ত্বের সাথে মিল: key x একই ঘরে থাকে শুধু যখন x mod ৪ = x mod ৫, যা প্রতি ২০টি সংখ্যায় ৪টিতে ঘটে (০, ১, ২, ৩), অর্থাৎ ৮০% সরে। ৪ থেকে ৩ করলে প্রতি ১২টিতে ৩টি থাকে — ৭৫% সরে (মাপা ৭৪.৭%). Consistent hashing-এ D বাদ দিলে ঠিক D-র ভাগ (২৫.০%) সরে — শুধু D-র key, আর কারও নয়। E যোগ করলে সরে ২৫.৫%; আদর্শ ২০% হতো, কিন্তু ১০০টি virtual node-এ E বৃত্তের একটু বেশি অংশ পেয়েছে — আর সরানো প্রতিটি key গেছে শুধু E-তে। শেষ চার লাইন virtual node-এর কারণ দেখায়: প্রতি backend-এ ১টি বিন্দু হলে একজন পায় ৫,৪৭৭টি key, আরেকজন ৫৫৬ (সবচেয়ে বেশি ভার গড়ের ২.১৯ গুণ); ১০০টিতে ১.০৮, ১,০০০টিতে ১.০৫.
Google ২০১৬ সালে তাদের software load balancer Maglev-এর নকশা প্রকাশ করে। সেখানে router ECMP দিয়ে VIP-এর ট্রাফিক অনেকগুলো সাধারণ সার্ভারে চলা LB-তে ভাগ করে, আর প্রতিটি LB একটি বিশেষ consistent-hash টেবিল (Maglev hashing) থেকে backend বাছে — প্রায় সমান ভাগ আর backend বদলালে কম পরিবর্তনের জন্য বানানো। প্রতিটি LB একই টেবিল ব্যবহার করায় একটি LB নষ্ট হয়ে ECMP সংযোগটি অন্য LB-তে পাঠালেও বেশিরভাগ ক্ষেত্রে সে একই backend বাছে, তাই চলমান সংযোগ টিকে যায়। অর্থাৎ LB নিজেরও load balancing আর redundancy লাগে।
Sticky session, health check আর connection draining
Sticky session (session affinity): একজন ব্যবহারকারীকে বারবার একই backend-এ পাঠানো — cookie দিয়ে বা IP-hash দিয়ে — যাতে সার্ভারের মেমরিতে রাখা session পাওয়া যায়। অসুবিধা অসমান ভার আর backend নষ্ট হলে session হারানো; তাই আধুনিক নকশা session সাধারণত বাইরের store-এ রাখে।
Health check দুই রকম: active — LB নিজে নির্দিষ্ট সময় পরপর প্রতিটি backend-কে পরীক্ষা করে (TCP সংযোগ, বা GET /healthz-এর উত্তর ২০০ কি না), পরপর কয়েকবার ব্যর্থ হলে DOWN, পরপর কয়েকবার সফল হলে আবার UP; passive — আসল ট্রাফিকের ত্রুটি (সংযোগ ব্যর্থ, ৫xx উত্তর) গুনে সাময়িক বাদ দেওয়া। ভালো health check শুধু “process বেঁচে আছে?” নয়, “অনুরোধ সামলাতে পারবে?” যাচাই করে — তবে এত গভীর নয় যে ডেটাবেস ধীর হলেই সব backend একসাথে DOWN হয়ে যায়।
Connection draining: নতুন সংস্করণ deploy বা রক্ষণাবেক্ষণের জন্য একটি backend সরানোর আগে LB তাতে নতুন অনুরোধ পাঠানো বন্ধ করে, কিন্তু চলমান অনুরোধ শেষ হতে দেয় (একটি সর্বোচ্চ সময়সীমা পর্যন্ত)। এটি LB-স্তরের graceful shutdown (পর্ব ৪৩-এর সার্ভারে দেখেছেন)।
- ক্লায়েন্ট
198.51.100.23HTTPS - L7 LB
VIP :443203.0.113.10 - api pool
api-1, 2, 3/api/* - api-3
10.0.2.13বাছাই
| অনুরোধ | |
| api pool | |
| LB-র সিদ্ধান্ত |
- TLS এখানেই শেষ। DNS ক্লায়েন্টকে VIP 203.0.113.10 দিয়েছে। ক্লায়েন্ট TCP আর TLS handshake করে LB-র সাথে; SNI-তে shop.example, আর LB সেই নামের certificate দেখায়। এনক্রিপশন খোলা হয় LB-তে — এটিই TLS termination.
- HTTP পড়া আর path ধরে routing. এখন LB অনুরোধটি পড়তে পারে:
GET /api/orders/42. নিয়ম অনুযায়ী/static/*যায় static pool-এ,/api/*যায় api pool-এ। L4 LB এই সিদ্ধান্ত নিতে পারত না — সে path দেখেই না। - Health check-এর ফল। LB প্রতি ৫ সেকেন্ডে প্রতিটি backend-এ
GET /healthzপাঠায়। api-2 পরপর ৩ বার ব্যর্থ — DOWN, বাছাইয়ের তালিকা থেকে বাদ। ক্লায়েন্ট কিছুই টের পান না। - Backend বাছাই আর পাঠানো। সুস্থ দুজনের মধ্যে least connections: api-1-এর হাতে ১২টি, api-3-এর ৯টি — api-3. LB নতুন (বা আগে থেকে খোলা) সংযোগে অনুরোধ পাঠায় আর
X-Forwarded-For: 198.51.100.23যোগ করে, যাতে backend আসল ক্লায়েন্ট চেনে। api-3-এর চলমান অনুরোধ এখন ১০। - উত্তর ফেরে LB দিয়ে। api-3 উত্তর দেয়
200 OK; LB সেটি TLS-এ এনক্রিপ্ট করে ক্লায়েন্টকে পাঠায় আর সময়টি log-এ লেখে। api-3-এর চলমান অনুরোধ আবার ৯। - Deploy-এর জন্য draining. নতুন সংস্করণ বসাতে api-1-কে DRAINING করা হলো: নতুন কোনো অনুরোধ যায় না, হাতের ১২টি শেষ হতে দেওয়া হয় (সর্বোচ্চ ৩০ সেকেন্ড), তারপর সরানো। এদিকে api-2 পরপর ২ বার health check পাস করে আবার UP — কোনো ব্যবহারকারী একটি ত্রুটিও দেখেননি।
Data center-এর বাইরে: GSLB আর anycast
একটি data center নিজেই নষ্ট হতে পারে — বিদ্যুৎ, বন্যা, fiber কাটা। তাই বড় সেবা কয়েকটি data center-এ চলে, আর ব্যবহারকারীকে কোনটিতে পাঠানো হবে তা ঠিক করে GSLB (global server load balancing). সাধারণ পদ্ধতি DNS (পর্ব ৩৫, DNS): authoritative সার্ভার প্রশ্নকারীর অবস্থান আর প্রতিটি সাইটের স্বাস্থ্য দেখে ভিন্ন ঠিকানা দেয়, ছোট TTL রেখে — তবে resolver-এর cache-এর কারণে বদল পুরোপুরি তাৎক্ষণিক নয়। আরেক পদ্ধতি anycast (পর্ব ২৫): একই VIP কয়েকটি সাইট থেকে BGP-তে ঘোষণা, routing নিজেই কাছের সাইটে পাঠায়; একটি সাইট ঘোষণা তুলে নিলে ট্রাফিক অন্যগুলোতে যায়।
Software বনাম hardware: আগে LB মানে ছিল দামি বিশেষ যন্ত্রের জোড়া; এখন বেশিরভাগ জায়গায় সাধারণ সার্ভারে চলা software (HAProxy, nginx, Envoy, IPVS), সামনে router-এর ECMP — সার্ভার যোগ করলেই ক্ষমতা বাড়ে। Hardware LB এখনো কিছু enterprise-এ দেখা যায়।
৯ · নির্ভরযোগ্যতা — redundancy, failure domain আর availability-র অঙ্ক
Data center-এর প্রতিটি নকশা-সিদ্ধান্তের পেছনে একটি প্রশ্ন: “এটা নষ্ট হলে কী হবে?” উত্তরের তিনটি হাতিয়ার:
- Redundancy আর N+1: দরকার N-টি হলে অন্তত একটি বাড়তি রাখা — ৩টি spine-এর ক্ষমতা লাগলে ৪টি। কিছু জায়গায় ২N: পুরো দ্বিগুণ (দুটি আলাদা বিদ্যুৎ লাইন, প্রতিটি সার্ভারে দুটি power supply).
- Failure domain: একটি ব্যর্থতা কতদূর ছড়ায় — একটি সার্ভার, একটি rack (ToR গেলে পুরো rack), একটি বিদ্যুৎ-সারি, একটি হল, পুরো data center. Redundant কপিগুলো আলাদা failure domain-এ রাখতে হয়: ডেটাবেসের তিনটি কপি একই rack-এ রাখলে একটি ToR-এই তিনটি যায়। এজন্য অনেক প্রতিষ্ঠান ToR-ও জোড়ায় রাখে আর সার্ভারকে দুটিতে যুক্ত করে।
- Single point of failure খোঁজা: প্রতিটি পথ ধরে জিজ্ঞেস করা, কোথায় একটিমাত্র কিছু আছে — একটি LB, একটি DNS সেবাদাতা, একটি fiber পথ, একটি configuration ফাইল।
Availability-র হিসাব
Availability সাধারণত সময়ের শতাংশে বলা হয়: বছরে ৮,৭৬০ ঘণ্টার কত অংশ সেবা চালু। ৯৯.৯% (“three nines”) মানে বছরে চালু নেই ০.১%:
৯৯% → ৮৭.৬ ঘণ্টা; ৯৯.৯৯% → প্রায় ৫২.৬ মিনিট; ৯৯.৯৯৯% (five nines) → প্রায় ৫.২৬ মিনিট
দুটি নিয়ম, অংশগুলো একে অপরের থেকে স্বাধীনভাবে নষ্ট হয় ধরে নিয়ে:
- Series (সবগুলো লাগবে): A = a₁ × a₂ × … — শিকল তার সবচেয়ে দুর্বল কড়ার চেয়েও দুর্বল। দুটি ৯৯.৯% অংশ পরপর: ০.৯৯৯ × ০.৯৯৯ = ৯৯.৮০০১% — বছরে প্রায় ১৭.৫ ঘণ্টা।
- Parallel (যেকোনো একটি চললেই হবে): সব একসাথে নষ্ট হওয়ার সম্ভাবনা গুণ হয়, তাই A = ১ − (১ − a₁)(১ − a₂)…; দুটি একই রকম হলে ১ − (১ − a)². দুটি ৯৯% সার্ভার: ১ − ০.০১² = ৯৯.৯৯%; দুটি ৯৯.৯% LB: ৯৯.৯৯৯৯% — বছরে মাত্র প্রায় ৩১.৫ সেকেন্ড।
হাতে কষা উদাহরণ: একটি সেবার পথ — দুটি LB (প্রতিটি ৯৯.৯%, parallel) → তিনটি app সার্ভার (প্রতিটি ৯৯%, একটি চললেই হবে) → একটি ডেটাবেস (৯৯.৯৫%).
মোট = ০.৯৯৯৯৯৯ × ০.৯৯৯৯৯৯ × ০.৯৯৯৫ ≈ ০.৯৯৯৪৯৮ → বছরে প্রায় ৪.৪ ঘণ্টা বন্ধ — প্রায় সবটাই একমাত্র ডেটাবেসের জন্য
শিক্ষা: সবচেয়ে দুর্বল series অংশটিই পুরো সেবার availability ঠিক করে। ডেটাবেসেরও একটি স্বাধীন কপি (parallel) রাখলে হিসাবে বছরে প্রায় এক মিনিটে নামে। কিন্তু সাবধান — “স্বাধীন” ধারণাটিই সবচেয়ে বড় ফাঁকি: একই software bug, একই ভুল configuration বা একই বিদ্যুৎ লাইন দুটি কপিকে একসাথে ফেলে দেয়, আর failover নিজেও ব্যর্থ হতে পারে। বড় বিভ্রাটগুলো সাধারণত এই সম্পর্কযুক্ত (correlated) ব্যর্থতা থেকেই আসে।
আরও গভীরে: Linux-ও ECMP করে — একটি route-এ একাধিক nexthop দিলে kernel hash দিয়ে পথ বাছে, আর IPv4-এ net.ipv4.fib_multipath_hash_policy sysctl ঠিক করে hash-এ শুধু L3 ঠিকানা (০) না পুরো L4 5-tuple (১) যাবে। Data center switch-এর ASIC-গুলোতে buffer সাধারণত সব port-এর মধ্যে ভাগ করা (shared) কয়েক থেকে কয়েক ডজন MB-র on-chip মেমরি — port-প্রতি হিসাবে খুব ছোট, তাই incast এত সহজে হয়। Maglev-এর প্রবন্ধে lookup টেবিলের আকার একটি মৌলিক সংখ্যা (যেমন ৬৫,৫৩৭) রাখার কথা আছে, যাতে প্রতিটি backend-এর পছন্দের ক্রম টেবিলের সব ঘর ছুঁয়ে যায়।
পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:
- Leaf-spine কেন তিন-স্তরের চেয়ে ভালো? — সব link সক্রিয় (ECMP, STP নয়), যেকোনো দুই rack-এর দূরত্ব সমান, spine/leaf যোগ করে বাড়ানো যায়, একটি spine গেলে মাত্র ১/N ক্ষমতা যায়।
- Oversubscription কীভাবে হিসাব করবেন? — leaf-এর মোট নিচের bandwidth ÷ মোট ওপরের bandwidth; ৪৮×২৫G ÷ ৮×১০০G = ১.৫:১.
- k-port switch-এর fat-tree-তে কয়টি host? — k³/৪ (k pod × k/২ edge × k/২ port); switch ৫k²/৪.
- L4 আর L7 load balancer-এর পার্থক্য? — L4 5-tuple দেখে সংযোগ ভাগ করে; L7 HTTP পড়ে (path, header), TLS termination করে, প্রতিটি অনুরোধ আলাদা পাঠাতে পারে।
- Consistent hashing কেন? — N বদলালে modulo-তে প্রায় সব key সরে, consistent hashing-এ মাত্র প্রায় ১/N; virtual node ভার সমান করে।
১০ · AI-এর যুগে data center নেটওয়ার্ক — হিসাব নিজে যাচাই করুন
AI সহকারী fabric-এর খসড়া নকশা, LB-র configuration বা ক্ষমতার হিসাবে দ্রুত সাহায্য করে। কিন্তু এই বিষয়ে তার পরিচিত ভুলগুলো ব্যয়বহুল — ভুল হিসাবে কেনা switch ফেরত দেওয়া যায় না।
| AI-এর ভুল | কেন ভুল | কীভাবে ধরবেন |
|---|---|---|
| Oversubscription-এ port সংখ্যা ভাগ করা (৪৮ ÷ ৮ = ৬:১) | গতি বাদ পড়েছে; হিসাব হয় bandwidth-এ | নিচে ও ওপরে port × গতি আলাদা গুণ করে নিজে ভাগ করুন |
| “ECMP প্রতিটি packet সমানভাবে ভাগ করে” | সাধারণ ECMP per-flow hash; বড় flow collide করে | ছোট simulator বা আসল link counter দেখুন |
| Fat-tree-তে k³ বা k²/৪ host বলা | সঠিক k³/৪; ছোট k-তে হাতে গুনে মেলে (k = ৪ → ১৬) | k = ৪-এর ছবি এঁকে গুনুন |
| Availability যোগ বা গড় করা | series-এ গুণ, parallel-এ ১ − (১ − a)ⁿ; স্বাধীনতা ধরে নেওয়া স্পষ্ট বলতে হয় | নিজে হিসাব করে বছরে কত ঘণ্টা দেখুন |
| Vendor-নির্দিষ্ট কমান্ড বা feature সার্বজনীন বলা; বানানো RFC নম্বর | MLAG, vPC, EVPN-এর খুঁটিনাটি vendor ভেদে আলাদা | rfc-editor.org-এ মেলান (VXLAN = RFC 7348, EVPN = RFC 7432 ও 8365, DC-তে BGP = RFC 7938, DCTCP = RFC 8257); vendor-এর নিজের ডকুমেন্টেশন দেখুন; ল্যাবে পরীক্ষা করুন |
একটি leaf-spine নকশা যাচাইয়ে AI-কে এভাবে কাজে লাগাতে পারেন:
AI-এর data center পরামর্শ ব্যবহারের আগে — চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১১৯৫৩ সালের টেলিফোন এক্সচেঞ্জের একটি নকশা কীভাবে একবিংশ শতাব্দীর data center-এর মূল কাঠামো হয়ে উঠল? মাঝখানে কী বদলেছিল?
Charles Clos-এর ১৯৫৩ সালের প্রবন্ধের সমস্যা ছিল টেলিফোনের: একটি এক্সচেঞ্জে হাজার হাজার লাইনের যেকোনোটিকে যেকোনোটির সাথে জুড়তে হবে, অথচ একটি বিশাল crossbar switch বানাতে লাইনের সংখ্যার বর্গের সমান সংযোগ-বিন্দু লাগে — খরচ অসম্ভব। Clos দেখান যে ছোট switch-গুলো তিন স্তরে সাজালে, আর মাঝের স্তরে যথেষ্ট switch রাখলে, নতুন কল কখনো আটকায় না (non-blocking), অথচ মোট সংযোগ-বিন্দু অনেক কম। পরের কয়েক দশক এই ধারণা টেলিফোন এক্সচেঞ্জ আর বড় router-এর ভেতরের switching fabric-এ টিকে ছিল।
Data center-এ এটি ফিরে এল ২০০০-এর দশকের শেষে, তিনটি পরিবর্তনের মিলনে। এক, east-west ট্রাফিক বিস্ফোরিত হলো — MapReduce-ধাঁচের বড় ডেটা কাজ আর পরে microservice. দুই, “merchant silicon” এল: কয়েকটি chip নির্মাতা একটি chip-এই অনেকগুলো দ্রুত port-এর switch বানাতে লাগল, ফলে সস্তা, একই রকম switch সহজলভ্য হলো। তিন, বড় কোম্পানিগুলো সার্ভারের মতো নেটওয়ার্কেও “অনেক সস্তা জিনিস, software দিয়ে নিয়ন্ত্রণ” পথ বেছে নিল। ২০০৮ সালের Al-Fares-দের fat-tree প্রবন্ধ দেখাল যে শুধু সাধারণ switch দিয়েই পূর্ণ bisection bandwidth সম্ভব। ২০১৫ সালে Google তাদের কয়েক প্রজন্মের Clos fabric-এর অভিজ্ঞতা (Jupiter) প্রকাশ করে, আর Facebook ২০১৪ সালে নিজেদের data center fabric-এর নকশা প্রকাশ্যে বর্ণনা করে — দুটিই একই মূল ধারণার ওপর দাঁড়ানো।
মজার ব্যাপার, এক অর্থে চক্র পূর্ণ হয়েছে: বড় chassis router-এর ভেতরের line card আর fabric card নিজেই একটি Clos; leaf-spine সেই ভেতরের নকশাকে বাইরে, তার দিয়ে, আলাদা বাক্সে ছড়িয়ে দিয়েছে।
মূল উপলব্ধি: ভালো ধারণা প্রায়ই হারায় না, অপেক্ষা করে — যখন খরচ আর চাহিদার হিসাব বদলায় (সস্তা chip, east-west ট্রাফিক), পুরোনো তত্ত্ব হঠাৎ সবচেয়ে বাস্তব সমাধান হয়ে ওঠে।
প্র ০২বড় data center-গুলো layer 2 থেকে সরে “L3 to the ToR” আর BGP-তে গেল, অথচ আবার VXLAN-EVPN দিয়ে layer 2 ফিরিয়ে আনল। এটা কি স্ববিরোধ?
পুরোনো data center-এ বড় layer 2 এলাকা জনপ্রিয় ছিল সুবিধার জন্য: যেকোনো সার্ভার যেকোনো rack-এ বসুক, একই VLAN আর একই subnet; virtual machine চালু অবস্থায় অন্য সার্ভারে সরালেও IP একই থাকে। কিন্তু দাম ছিল ভয়ংকর: STP অর্ধেক link বন্ধ রাখে, MAC table বিশাল, broadcast আর অচেনা গন্তব্যের flooding পুরো এলাকায় ছড়ায়, আর একটি loop বা broadcast storm একসাথে হাজারো সার্ভার অচল করতে পারে। Failure domain পুরো layer 2 এলাকার সমান।
তাই fabric হলো layer 3: প্রতিটি rack নিজের subnet, প্রতিটি link একটি route, ব্যর্থতা ছোট গণ্ডিতে। RFC 7938 বর্ণনা করে কেন অনেক বড় operator এখানে IGP-র বদলে eBGP বেছে নিয়েছে: একটিই protocol সব জায়গায়, নীতি দিয়ে সূক্ষ্ম নিয়ন্ত্রণ, আর পরিচিত, পরিপক্ক software.
কিন্তু অ্যাপের চাহিদা মুছে যায়নি — VM সরানো, পুরোনো software যা একই subnet চায়, আর cloud-এ হাজারো tenant-এর আলাদা নেটওয়ার্ক। সমাধান হলো স্তর আলাদা করা: ভৌত নেটওয়ার্ক (underlay) পুরোপুরি layer 3, সরল আর স্থিতিশীল; layer 2-এর অনুভূতি দেওয়া হয় software-এর overlay দিয়ে, VXLAN-এর tunnel-এ। আর পুরোনো flood-and-learn-এর বদলে EVPN BGP দিয়েই জানিয়ে দেয় কোন MAC কোথায় — অর্থাৎ overlay-এর layer 2-ও আসলে একটি routing protocol দিয়ে চলে। Broadcast-এর ক্ষতি ছোট থাকে, অথচ অ্যাপ দেখে বড় একটি LAN. দাম হলো জটিলতা: সমস্যা খুঁজতে গেলে প্রথম প্রশ্নই হয় — গোলমাল underlay-এ, না overlay-এ? দুই স্তরের আলাদা table আর আলাদা দৃশ্য বুঝতে হয়।
একই নীতি cloud-এর VPC-তে দেখবেন (পর্ব ৫৪): গ্রাহক নিজের subnet আর ঠিকানা বানান, কিন্তু নিচের ভৌত নেটওয়ার্ক পুরোপুরি আলাদা, আর দুটির মাঝে encapsulation.
মূল উপলব্ধি: স্ববিরোধ নয়, স্তর ভাগ করা — ভৌত নেটওয়ার্ক যতটা সম্ভব সরল layer 3, আর অ্যাপের যে সুবিধা দরকার তা overlay-এ, যেখানে নিয়ন্ত্রণ software-এর হাতে।
প্র ০৩Incast সমস্যার সহজ সমাধান মনে হয় switch-এ বড় buffer দেওয়া। তাহলে data center-এর অনেক switch-এ buffer এত ছোট কেন, আর গবেষকেরা কী পথ নিয়েছেন?
Data center switch-এর chip-এর buffer সাধারণত chip-এর ভেতরের দ্রুত মেমরি (SRAM). এটি জায়গা নেয়, বিদ্যুৎ খায়, আর port-এর গতি যত বাড়ে, প্রতি port-এ ততটুকু বাইট ধরে রাখতে তত বেশি মেমরি লাগে — তাই অনেক জনপ্রিয় chip-এ buffer সব port মিলিয়ে কয়েক থেকে কয়েক ডজন MB. বড় buffer-এর switch আছে (বাইরের DRAM-সহ), কিন্তু দামি; আর বড় buffer নিজেও সমস্যা আনে — queue বড় হলে delay বাড়ে, যাকে পর্ব ৫-এ bufferbloat হিসেবে দেখেছেন।
২০০৯ সালের একটি পরিচিত গবেষণা incast-কে বিস্তারিত মাপে আর দেখায় যে মূল ক্ষতি আসে timeout থেকে: মিলিসেকেন্ডের RTO, অথচ মাইক্রোসেকেন্ডের RTT. তাদের প্রস্তাব ছিল ন্যূনতম RTO-কে মাইক্রোসেকেন্ডের ঘরে নামানো। ২০১০ সালে DCTCP উল্টো দিক থেকে আসে: buffer বাড়ানোর বদলে queue-কে সবসময় ছোট রাখা। Switch queue একটি নির্দিষ্ট সীমা পেরোলেই ECN দাগ দেয়, প্রেরক দাগের অনুপাত অনুযায়ী অল্প করে window কমায় — ফলে buffer-এর বেশিরভাগ ফাঁকা থাকে হঠাৎ ঢেউয়ের জন্য। পরে এটি RFC 8257-এ বর্ণিত হয়, আর বিভিন্ন OS-এ বাস্তবায়ন আছে।
অ্যাপ্লিকেশনের দিক থেকেও সমাধান আছে: একসাথে সবাইকে প্রশ্ন না পাঠিয়ে ধাপে ধাপে পাঠানো, উত্তরের আকার ছোট রাখা, বা একই প্রশ্ন দুই জায়গায় পাঠিয়ে যে আগে উত্তর দেয় সেটি নেওয়া (hedged request) — যদিও শেষেরটি ভার বাড়ায়। গবেষণায় receiver-চালিত transport-ও প্রস্তাব হয়েছে, যেখানে প্রাপক নিজেই ঠিক করে কে কখন পাঠাবে।
মূল উপলব্ধি: জটের উত্তর সবসময় বড় গুদাম নয়; অনেক সময় ভালো উত্তর হলো আগেভাগে সংকেত দিয়ে লাইন ছোট রাখা, আর অ্যাপ্লিকেশনকে নেটওয়ার্কের সীমা মাথায় রেখে বানানো।
প্র ০৪Consistent hashing প্রথম এসেছিল web cache-এর জন্য, ১৯৯৭ সালে। আজ এটি load balancer, distributed ডেটাবেস আর CDN-এ সর্বত্র। এর জনপ্রিয়তার রহস্য কী, আর এর সীমাবদ্ধতা কোথায়?
১৯৯৭ সালে MIT-র Karger ও সহকর্মীরা একটি সমস্যা নিয়ে কাজ করছিলেন: জনপ্রিয় ওয়েবসাইটে হঠাৎ ভিড় হলে (তখনকার ভাষায় “hot spot”) অনেকগুলো cache সার্ভারে কনটেন্ট কীভাবে ভাগ করা যায়, যখন cache সার্ভার যোগ-বিয়োগ হতেই থাকে। Modulo hashing-এ একটি সার্ভার যোগ করলেই প্রায় সব কনটেন্ট নতুন ঘরে যায় — সব cache একসাথে ঠান্ডা। তাঁদের consistent hashing বৃত্তের ধারণা দিয়ে নিশ্চিত করে যে সার্ভার যোগ-বিয়োগে গড়ে শুধু প্রায় ১/N অংশ সরে। এই গবেষণার সাথে যুক্ত কয়েকজন পরে একটি বড় CDN কোম্পানি প্রতিষ্ঠা করেন বলে পরিচিত।
এর জনপ্রিয়তার কারণ: এটি একটি “চুক্তি” ছাড়াই সমন্বয় দেয়। সব LB বা সব ক্লায়েন্ট একই hash ফাংশন আর একই সার্ভার-তালিকা জানলে কারও সাথে কথা না বলেই সবাই একই উত্তর পায়। পরিবর্তন স্থানীয় থাকে। তাই ২০০০-এর দশকের distributed key-value store (যেমন Amazon-এর Dynamo-র প্রকাশিত নকশা), পরের অনেক NoSQL ডেটাবেস (দেখুন distributed ডেটাবেস), আর Maglev-এর মতো LB সবাই এই পরিবারের সদস্য।
সীমাবদ্ধতাও আছে। ভার সমান রাখতে virtual node লাগে (simulator-এ ১টি বিন্দুতে সবচেয়ে বেশি ভার গড়ের ২.১৯ গুণ)। একটি key খুব জনপ্রিয় হলে (একটি ভাইরাল ভিডিও) hash তাকে একটি সার্ভারেই রাখে — তখন কপি বাড়ানো বা “bounded load” ধরনের রূপ লাগে। আর ভার সমান রাখার চেয়ে স্থিতিশীলতা এখানে বেশি গুরুত্ব পায়; যে কাজে key-র স্মৃতি দরকার নেই, সেখানে least connections-ই ভালো।
মূল উপলব্ধি: Consistent hashing-এর আসল শক্তি সমান ভাগ নয়, ন্যূনতম পরিবর্তন আর সমন্বয় ছাড়া একমত হওয়া — বিতরণ-ব্যবস্থায় এ দুটিই সবচেয়ে দামি।
প্র ০৫কাগজে-কলমে redundancy-র হিসাব “বছরে কয়েক সেকেন্ড বিভ্রাট” দেখায়, অথচ বড় বড় সেবা কয়েক ঘণ্টার জন্য অচল হয়। বাস্তবের বড় বিভ্রাটগুলো কী শেখায়?
Parallel-এর সূত্র ১ − (১ − a)² একটি অনুমানের ওপর দাঁড়ানো: দুটি অংশ স্বাধীনভাবে নষ্ট হয়। বাস্তবের বড় বিভ্রাটগুলো প্রায় সবসময় এই অনুমান ভাঙে। ২০১৭ সালের ফেব্রুয়ারিতে একটি বড় cloud সেবাদাতার storage সেবার একটি অঞ্চলে বিভ্রাটের প্রকাশিত ব্যাখ্যা অনুযায়ী, রক্ষণাবেক্ষণের সময় একটি কমান্ডে ভুল মান দেওয়ায় পরিকল্পনার চেয়ে অনেক বেশি সার্ভার সরানো হয়, আর তার ওপর নির্ভরশীল বহু সেবা কয়েক ঘণ্টা ব্যাহত হয়। ২০২১ সালের অক্টোবরে Facebook-এর প্রকাশিত ব্যাখ্যা অনুযায়ী, backbone-এর রক্ষণাবেক্ষণে একটি কমান্ড সব data center-এর সংযোগ বিচ্ছিন্ন করে; এরপর তাদের DNS সার্ভার নিজেদের BGP ঘোষণা তুলে নেয়, আর কয়েক ঘণ্টা তাদের সেবাগুলো ইন্টারনেট থেকে প্রায় অদৃশ্য ছিল — এমনকি মেরামতের জন্য ভেতরের যন্ত্রেও পৌঁছানো কঠিন হয়েছিল।
দুটি ঘটনাতেই যন্ত্র ছিল বহুগুণ redundant; কিন্তু একটি মানুষের কমান্ড, একটি configuration বা একটি software সব কপিকে একসাথে ছুঁয়েছে — সম্পর্কযুক্ত ব্যর্থতা। আরও সাধারণ উদাহরণ: একই software bug সব সার্ভারে একই সময়ে, একই certificate-এর মেয়াদ সব জায়গায় একসাথে শেষ, ব্যাকআপ জেনারেটর সত্যিই চালু হয় কি না কখনো পরীক্ষা না করা।
প্রতিকার তাই প্রকৌশলের পাশাপাশি প্রক্রিয়ার: পরিবর্তন ধাপে ধাপে ছড়ানো (প্রথমে একটি rack, একটি অঞ্চল), প্রতিটি কমান্ডে সীমা আর যাচাই, ব্যর্থতার এলাকা (failure domain বা “cell”) ছোট রাখা যাতে একটি ভুল সবাইকে না ছোঁয়, নিয়ন্ত্রণের জন্য আলাদা out-of-band নেটওয়ার্ক, আর নিয়মিত ব্যর্থতার মহড়া। বাংলাদেশের ব্যাংক বা মোবাইল আর্থিক সেবার DR site-এর বেলায়ও প্রশ্ন একই: শেষ কবে সত্যিই সেখানে সেবা সরিয়ে দেখা হয়েছে?
মূল উপলব্ধি: Availability-র সূত্র যন্ত্রের স্বাধীন ব্যর্থতা মাপে; বড় বিভ্রাট আসে সম্পর্কযুক্ত ব্যর্থতা থেকে — configuration, software আর মানুষ। তাই redundancy-র সাথে ছোট failure domain, ধাপে ধাপে পরিবর্তন আর নিয়মিত মহড়া লাগে।
অনুশীলন
খাতা-কলম নিন — port, Gbps আর শতাংশ ধরে ধরে হিসাব করুন।
-
হিসাব (fabric নকশা): একটি প্রতিষ্ঠানের ৪০টি rack, প্রতিটিতে ৪০টি সার্ভার, প্রতিটি সার্ভার ২৫G. প্রতিটি leaf-এ ৪৮×২৫G আর ৮×১০০G port; spine ৬৪-port ১০০G, সংখ্যায় ৮টি। (ক) প্রতিটি leaf-এর oversubscription কত? (খ) Bisection bandwidth কত? (গ) এই spine দিয়ে সর্বোচ্চ কতটি rack পর্যন্ত বাড়ানো যাবে, আর তখন কতটি সার্ভার? (ঘ) একটি spine নষ্ট হলে প্রতিটি leaf-এর uplink আর অনুপাত কত?
(ক) নিচে ৪০ × ২৫ = ১,০০০G; ওপরে ৮ × ১০০ = ৮০০G; অনুপাত ১,০০০ ÷ ৮০০ = ১.২৫:১ (leaf-এর ৮টি ২৫G port খালি থাকে)। (খ) ৪০টি leaf-এর অর্ধেক ২০টি, প্রতিটির uplink ৮০০G: ২০ × ৮০০ = ১৬,০০০G = ১৬ Tbps.
(গ) প্রতিটি spine-এর প্রতিটি port একটি leaf-এ যায়, তাই সর্বোচ্চ ৬৪টি rack; ৬৪ × ৪০ = ২,৫৬০টি সার্ভার (প্রতিটি leaf-এ ৪৮টি সার্ভার বসালে ৩,০৭২টি, তখন অনুপাত ১.৫:১)। (ঘ) Uplink ৭ × ১০০ = ৭০০G, অনুপাত ১,০০০ ÷ ৭০০ ≈ ১.৪৩:১; ক্ষমতা কমল ১/৮ = ১২.৫%.
-
হিসাব (availability, series ও parallel): একটি অনলাইন সেবার পথে আছে দুটি LB (প্রতিটি ৯৯.৯৫%, যেকোনো একটি চললেই হবে), চারটি app সার্ভার (প্রতিটি ৯৯.৫%, একটি চললেই হবে) আর একটি ডেটাবেস (৯৯.৯%). ব্যর্থতাগুলো স্বাধীন ধরে নিন। (ক) পুরো সেবার availability আর বছরে মোটামুটি কত ঘণ্টা বিভ্রাট? (খ) ডেটাবেসের একটি স্বাধীন কপি (দুটি ৯৯.৯%, parallel) যোগ করলে কী হয়? (গ) বাস্তবে সংখ্যাটি কেন এর চেয়ে খারাপ হতে পারে?
(ক) LB = ১ − ০.০০০৫² = ০.৯৯৯৯৯৯৭৫; app = ১ − ০.০০৫⁴ ≈ ০.৯৯৯৯৯৯৯৯৯৪ (প্রায় ১); DB = ০.৯৯৯. মোট ≈ ০.৯৯৯৯৯৯৭৫ × ১ × ০.৯৯৯ ≈ ০.৯৯৮৯৯৯৭৫ ≈ ৯৯.৯%; বিভ্রাট ≈ ০.০০১ × ৮,৭৬০ ≈ ৮.৭৬ ঘণ্টা/বছর — প্রায় পুরোটাই ডেটাবেস থেকে।
(খ) DB = ১ − ০.০০১² = ০.৯৯৯৯৯৯; মোট ≈ ০.৯৯৯৯৯৮৭৫, অর্থাৎ বছরে প্রায় ০.৬৬ মিনিট — ৪০ সেকেন্ডের মতো। (গ) স্বাধীনতার অনুমান ভাঙে: দুই ডেটাবেস কপি একই ভুল configuration, একই software bug বা একই বিদ্যুৎ লাইনে একসাথে পড়তে পারে; failover নিজে ব্যর্থ হতে পারে বা কয়েক মিনিট নেয়; আর রক্ষণাবেক্ষণের পরিকল্পিত বিরতিও হিসাবে নেই।
-
আউটপুট অনুমান করুন: অংশ ৮-এর consistent hashing simulator-এ শুধু প্রথম তুলনার লাইনে
k => k % 5বদলেk => k % 8করা হলো (অর্থাৎ modulo-তে ৪ থেকে ৮টি backend). “add E” সারির modulo কলামে কত শতাংশ দেখাবে? কেন এটি ৪ থেকে ৫-এর চেয়ে কম? Consistent hashing-এ ৪ থেকে ৮ হলে আদর্শভাবে কত শতাংশ সরত?change modulo consistent(100 vnodes) add E 4->5 50.0% 25.5% drop D 4->3 74.7% 25.0%Modulo কলামে ৫০.০% (লাইনের লেবেল “4->5” থেকে যায়, কারণ শুধু সূত্র বদলেছে)। Key x একই ঘরে থাকে যখন x mod ৪ = x mod ৮, অর্থাৎ যখন x mod ৮ < ৪ — ঠিক অর্ধেক সংখ্যা। N দ্বিগুণ করলে প্রতিটি পুরোনো ঘর দুই ভাগ হয়, অর্ধেক key থেকে যায়। Consistent hashing-এ ৪ থেকে ৮ হলে নতুন চারজন আদর্শভাবে বৃত্তের অর্ধেক নেবে — সেখানেও প্রায় ৫০% সরবে, তবে শুধু নতুনদের কাছে; আসল সুবিধা একটি একটি করে যোগ-বিয়োগে।
-
Configuration লিখুন: nginx দিয়ে একটি L7 load balancer লিখুন:
shop.example-এর HTTPS অনুরোধ নেবে;/api/যাবে তিনটি backend-এ (10.0.2.11–13, port 8080) least connections দিয়ে, যার দ্বিতীয়টি রক্ষণাবেক্ষণে আছে;/static/যাবে আলাদা একটি pool-এ; backend যেন আসল ক্লায়েন্ট IP জানে। তারপর বলুন open-source nginx-এর health check কোন ধরনের, আর active check লাগলে কী করবেন।# উদাহরণ — nginx (খুঁটিনাটি সংস্করণ ভেদে আলাদা হতে পারে; nginx -t দিয়ে যাচাই করুন) upstream api_pool { least_conn; server 10.0.2.11:8080 max_fails=3 fail_timeout=10s; server 10.0.2.12:8080 down; # রক্ষণাবেক্ষণে server 10.0.2.13:8080 max_fails=3 fail_timeout=10s; } upstream static_pool { server 10.0.3.21:8080; server 10.0.3.22:8080; } server { listen 443 ssl; server_name shop.example; ssl_certificate /etc/ssl/shop.example.crt; # TLS termination এখানে ssl_certificate_key /etc/ssl/shop.example.key; location /api/ { proxy_pass http://api_pool; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; } location /static/ { proxy_pass http://static_pool; } }least_connalgorithm বাছে;downbackend-টিকে বাছাই থেকে বাদ রাখে;X-Forwarded-Forআসল ক্লায়েন্ট IP পাঠায়।max_fails/fail_timeoutহলো passive health check — আসল অনুরোধ ব্যর্থ হলে গুনে সাময়িক বাদ দেয়। Open-source nginx-এ নির্দিষ্ট সময় পরপর/healthzপরীক্ষার মতো active check নিজে থেকে নেই (বাণিজ্যিক সংস্করণে আছে); তা লাগলে HAProxy বা Envoy-র মতো LB, বা আলাদা monitoring দিয়ে backend সরানো যায়। এটি আপনার নিজের ল্যাবে আগে চালিয়ে একটি backend থামিয়ে দেখুন কী হয়।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি L7 load balancer একটি HTTPS অনুরোধ সামলানোর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- ক্লায়েন্টের সাথে TCP আর TLS handshake — VIP-এ TLS termination
- HTTP অনুরোধ পড়া: method, path আর Host header
- Path-এর নিয়ম মিলিয়ে backend pool বাছা (যেমন /api/* → api pool)
- Pool-এর সুস্থ (health check-এ UP) backend থেকে algorithm দিয়ে একটি বাছা
- X-Forwarded-For যোগ করে backend-এ পাঠানো, উত্তর এনক্রিপ্ট করে ক্লায়েন্টকে ফেরত
একটি leaf switch-এ ৪৮টি ২৫ Gbps port সার্ভারের দিকে আর ৬টি ১০০ Gbps port spine-এর দিকে ব্যবহার হচ্ছে। Oversubscription ratio কত?
- ১:১
- ১.৫:১
- ২:১
- ৮:১
শুধু ৮-port switch দিয়ে বানানো একটি k-ary fat-tree (k = ৮)-এ সর্বোচ্চ কতটি host যুক্ত করা যায়?
- ৩২
- ১২৮
- ৫১২
- ৮০
একটি search সেবায় একটি aggregator একসাথে ৫০টি worker-কে প্রশ্ন পাঠায়, আর সবাই প্রায় একই মুহূর্তে উত্তর দেয়। Link-গুলোর গড় ব্যবহার কম হলেও কিছু অনুরোধ মাঝে মাঝে ২০০ ms-এর বেশি দেরি করে। সবচেয়ে সম্ভাব্য কারণ কী?
- Spine-এর মোট bandwidth যথেষ্ট নয়
- DNS resolution ধীর
- STP বারবার নতুন গাছ বানাচ্ছে
- Incast — একসাথে আসা উত্তরে buffer উপচে packet হারায়, তারপর retransmission timeout
একটি cache cluster-এ ৪টি সার্ভার; key-গুলো hash করে সার্ভারে ভাগ করা হয়। পঞ্চম সার্ভার যোগ করলে প্রায় কত অংশ key-র সার্ভার বদলাবে — modulo hashing (hash mod N) আর consistent hashing-এ?
- Modulo প্রায় ৮০%, consistent প্রায় ২০%
- দুটিতেই প্রায় ২০%
- Modulo প্রায় ৮০%, consistent ০%
- Modulo প্রায় ২০%, consistent প্রায় ৮০%
একটি load balancer-কে /api/ দিয়ে শুরু হওয়া অনুরোধ এক দল সার্ভারে আর /images/-এর অনুরোধ আরেক দলে পাঠাতে হবে, আর সংযোগ HTTPS. কোনটি দরকার?
- DSR মোডের একটি L4 load balancer
- TLS termination-সহ একটি L7 load balancer
- Router-এর ECMP
- DNS round robin
একটি সেবায় দুটি একই রকম সার্ভার parallel-এ আছে, যেকোনো একটি চললেই সেবা চলে। প্রতিটির availability ৯৯%, আর তারা স্বাধীনভাবে নষ্ট হয়। সেবার availability কত?
- ৯৮.০১%
- ৯৯%
- ৯৯.৯৯%
- ১৯৮%
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- East-west যুগ: microservice, storage আর ML-এর কারণে ভেতরের ট্রাফিক প্রধান; তিন-স্তরের নকশা STP-তে অর্ধেক link বন্ধ রাখে, oversubscription গুণ করে আর core-এ chokepoint বানায়।
- Leaf-spine: প্রতিটি leaf প্রতিটি spine-এ; যেকোনো দুই rack leaf → spine → leaf; ECMP সব spine ব্যবহার করে; spine বা leaf যোগ করে বাড়ে; একটি spine গেলে ১/N যায়। নিচে L3 underlay (eBGP বা OSPF), ওপরে প্রয়োজনে VXLAN-EVPN overlay.
- হিসাব: oversubscription = নিচের মোট bandwidth ÷ ওপরের মোট (৪৮×২৫G ÷ ৮×১০০G = ১.৫:১); দুই স্তরে সর্বোচ্চ k²/২ host, fat-tree-তে k³/৪, switch ৫k²/৪.
- Transport: incast-এ ছোট buffer আর বড় RTO মিলে tail latency; elephant flow ECMP-তে collide করে (flowlet, packet spraying); RoCE-র জন্য PFC দিয়ে lossless Ethernet, তার নিজস্ব ঝুঁকিসহ।
- Load balancer আর নির্ভরযোগ্যতা: L4 সংযোগ, L7 অনুরোধ (TLS termination, path routing); least connections ধীর অনুরোধ সামলায়, consistent hashing ~১/N key সরায়; health check, draining, GSLB. Series-এ a₁a₂, parallel-এ ১ − (১ − a)², তবে সম্পর্কযুক্ত ব্যর্থতাই বড় বিভ্রাটের উৎস।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৫৩ · Software-defined networking আর NFVপরবর্তী পর্বControl plane কেন্দ্রীয় software-এ, নেটওয়ার্কের যন্ত্র software হয়ে।
- পর্ব ৫৪ · Cloud আর container নেটওয়ার্কিং — VPC, Docker আর KubernetesসামনেOverlay, virtual নেটওয়ার্ক আর container-এর load balancing.
- পর্ব ৫১ · মোবাইল নেটওয়ার্ক — 2G থেকে 5G, cell আর handoverআগের পর্বমডিউল ৯-এর শুরু: আধুনিক নেটওয়ার্ক।
- পর্ব ৩২ · TCP congestion control — slow start, AIMD, CUBIC আর BBRভিত্তিDCTCP আর ECN-এর পটভূমি।
- কম্পিউটার নেটওয়ার্ক · কোর্স হোম৬২টি পর্বপুরো রোডম্যাপ, মডিউল ৯-এর আধুনিক নেটওয়ার্কসহ।
- DSA · Hash tableপাশের ট্র্যাকHash ফাংশন আর collision — ECMP আর consistent hashing-এর গাণিতিক ভিত্তি।
- DBMS ও SQL · Distributed ডেটাবেসপাশের ট্র্যাকReplication, partitioning আর consistent hashing ডেটাবেসের দিক থেকে।