সরাসরি পর্বে যান
পর্ব ১৭ · ৮১-এর মধ্যে · মডিউল ৩

Autoscaling — scaling policy, health check আর instance group

Autoscaling — Scaling Policies, Health Checks and Instance Groups

Taught in Bangla, this lesson configures an instance group with min, desired and max, compares four policy types and scaling signals, and works the target tracking formula, headroom and true max by hand. Simulators show boot delay, cooldown and flapping, including a festival sale. It also follows instance replacement, health checks, zone distribution, draining and lifecycle hooks, and the limits autoscaling cannot pass.

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

  • Min, desired, max দিয়ে একটি group সাজানো আর তিন provider-এ তার নাম চেনা
  • চার ধরনের policy আর CPU, requests per target ও queue depth থেকে সঠিক signal বাছাই
  • Target tracking-এর সূত্র, headroom আর সত্যিকার max হাতে হিসাব করা
  • Boot-এর দেরি, cooldown আর flapping simulator-এ মেপে দেখা
  • Instance বদল, zone বণ্টন, draining আর lifecycle hook-এর কাজ ধাপে ধাপে অনুসরণ করা

১ · Instance group — min, desired আর max

ঈদের আগের সন্ধ্যায় বাসের টিকিট কাউন্টারের কথা ভাবুন। সকালে দুটি কাউন্টার খোলা, সন্ধ্যায় ভিড় বাড়লে মালিক আরও চারটি খোলেন, রাতে আবার বন্ধ করেন। Autoscaling এই সিদ্ধান্তটিই যন্ত্রের হাতে দেয়: চাপ মেপে server-এর সংখ্যা নিজে থেকে বাড়ানো আর কমানো। এটি elasticity-র (পর্ব ০৪) ব্যবহারিক রূপ।

Horizontal scaling কেন কাজ করে, stateless হওয়া কেন শর্ত, এই তত্ত্ব আছে System Design-এর scaling পর্বে। এখানে আমাদের প্রশ্ন আলাদা: বাস্তবে এটি কীভাবে সাজাবেন, চালাবেন আর ঠিক করবেন?

Autoscaling একা একটি VM-এর ওপর চলে না। চলে একটি instance group-এর ওপর, অর্থাৎ একই ছাঁচের VM-এর দলের ওপর। ছাঁচটি হলো launch template: কোন image (পর্ব ১৬), কোন instance type (পর্ব ১৫), কোন network আর কোন cloud-init script. দলের সংখ্যা ঠিক হয় তিনটি মান দিয়ে:

  • Min: এর নিচে কখনো নামবে না। চাপ শূন্য হলেও এতগুলো চালু থাকবে।
  • Desired: এই মুহূর্তে কতটি থাকা উচিত। Autoscaler শুধু এই সংখ্যাটিই বদলায়।
  • Max: এর ওপরে কখনো উঠবে না। এটি আপনার খরচ আর পেছনের database-এর রক্ষাকবচ।

বিয়েবাড়ির ক্যাটারিং ভাবুন। কমপক্ষে ৪ জন পরিবেশক থাকবেনই (min), এখন আছেন ৬ জন (desired), আর রান্নাঘরের সামর্থ্য ৩০ জনের বেশি সামলাতে পারবে না (max). একজন অসুস্থ হলে ম্যানেজার আরেকজনকে ডেকে ৬ জন পূরণ করেন। Group-ও ঠিক এই কাজ করে।

তিন zone জুড়ে একটি instance group

One group across three AZs, with min 4, desired 6, max 30

Instance group: তিন zone-এ ৬টি instance, min ৪, desired ৬, max ৩০ Load balancer Instance group · একই launch template AZ-aAZ-bAZ-c web-1web-2 web-3web-4 web-5web-6 বাড়ার জায়গাবাড়ার জায়গাবাড়ার জায়গা Group-এর ক্ষমতার দণ্ড (প্রতি ঘর = ১টি instance) min 4 desired 6 max 30 Autoscaler শুধু desired সরায়
ছবি ১৭.১ — একটি group, তিনটি zone, আর একটিমাত্র সংখ্যা যা autoscaler বদলায়।

সব বড় provider-এ ধারণাটি একই, শুধু নাম আলাদা:

ধারণাAWSAzureGoogle Cloud
দলAuto Scaling GroupVirtual Machine Scale SetManaged Instance Group
ছাঁচLaunch templateScale set modelInstance template
Policy-র ধরনTarget tracking, step, simple, scheduled, predictiveMetric বা সময়ভিত্তিক rule, predictiveলক্ষ্য-ভিত্তিক autoscaler, schedule, predictive

নিচের উদাহরণগুলো দেখায় কী কী সিদ্ধান্ত নিতে হয়। সবগুলো নমুনা; পড়ার জন্য account লাগবে না। চালালে VM চালু হবে আর টাকা লাগতে পারে, তাই শেষে group মুছে ফেলতে হবে।

# Launch template version is pinned: never let a new version roll out by surprise
aws autoscaling create-auto-scaling-group \
  --auto-scaling-group-name web-asg \
  --launch-template LaunchTemplateName=web-lt,Version=7 \
  --min-size 4 --desired-capacity 6 --max-size 30 \
  --vpc-zone-identifier "subnet-0aaa,subnet-0bbb,subnet-0ccc" \
  --health-check-type ELB --health-check-grace-period 180

# cpu60.json: {"PredefinedMetricSpecification":
#   {"PredefinedMetricType":"ASGAverageCPUUtilization"},"TargetValue":60.0}
aws autoscaling put-scaling-policy \
  --auto-scaling-group-name web-asg --policy-name cpu-60 \
  --policy-type TargetTrackingScaling \
  --target-tracking-configuration file://cpu60.json

# Clean up afterwards (this terminates every instance in the group)
aws autoscaling delete-auto-scaling-group \
  --auto-scaling-group-name web-asg --force-delete
# Azure autoscale uses rules; here: above 70% for 5 minutes, add 2
az monitor autoscale create --resource-group demo-rg \
  --resource web-vmss \
  --resource-type Microsoft.Compute/virtualMachineScaleSets \
  --name web-autoscale --min-count 4 --max-count 30 --count 6

az monitor autoscale rule create --resource-group demo-rg \
  --autoscale-name web-autoscale \
  --condition "Percentage CPU > 70 avg 5m" --scale out 2
# Regional MIG: keep average CPU near 60%
gcloud compute instance-groups managed set-autoscaling web-mig \
  --region=asia-south1 \
  --min-num-replicas=4 --max-num-replicas=30 \
  --target-cpu-utilization=0.60 --cool-down-period=180

২০০৯ সালের মে মাসে AWS একসাথে CloudWatch, Elastic Load Balancing আর Auto Scaling ঘোষণা করে। তিনটি একসাথে আসা কাকতালীয় নয়: মাপ, ট্রাফিক ভাগ আর সংখ্যা বদল, এই তিনটি মিলেই autoscaling.

২ · চার ধরনের policy আর মূল সূত্র

Policy হলো সেই নিয়ম, যা ঠিক করে desired কখন কত হবে। চারটি ধরন চার রকম প্রশ্নের উত্তর দেয়:

🎯 Target tracking

Target tracking এসির thermostat-এর মতো: “২৫° রাখুন” বলে দেন, কতটা ঠান্ডা করতে হবে সে নিজে হিসাব করে। “Instance-প্রতি ৬০ অনুরোধ রাখুন।”

সাধারণ কাজের প্রথম পছন্দ

🪜 Step

Step scaling-এ আপনি নিজে ধাপ লেখেন: ৭০ ছাড়ালে ২টি যোগ, ৮৫ ছাড়ালে ৪টি, ১০০ ছাড়ালে ৮টি।

স্পষ্ট নিয়ম, হাতে সাজানো

🗓️ Scheduled

Scheduled scaling রেলের সময়সূচির মতো। “রাত ৮টার সেলের আগে ৭:৩০-এ min হবে ৩০।”

জানা সময়ের ভিড়

🔮 Predictive

Predictive scaling আগের দিন-সপ্তাহের ধাঁচ দেখে ভিড়ের আগে বাড়ায়। নিয়মিত দৈনিক ঢেউয়ে কাজে লাগে, নতুন ঘটনায় নয়।

নিয়মিত ধাঁচ

একাধিক policy একসাথে থাকতে পারে। সাধারণত যে policy সবচেয়ে বেশি ক্ষমতা চায়, তার কথাই থাকে (provider-এর নথিতে মিলিয়ে নিন)। তাই scheduled policy min তুলে দেয়, আর target tracking তার ওপরে কাজ করে।

Target tracking-এর হিসাব

desired = ⌈current × metric ÷ target⌉
তারপর min ≤ desired ≤ max

যুক্তিটি সহজ। ৬টি instance-এ প্রতিটিতে ১৫০ অনুরোধ মানে মোট ৯০০. প্রতিটিতে ৬০ রাখতে চাইলে লাগবে ৯০০ ÷ ৬০ = ১৫টি। ⌈ ⌉ মানে ওপরের দিকে গোল করা (ceil), কারণ ৬.৫টি VM হয় না, আর কম ধরলে লক্ষ্য ছাড়িয়ে যায়।

এই রূপটি Kubernetes-এর Horizontal Pod Autoscaler-এর নথিতে সরাসরি আছে (পর্ব ৪৮)। Cloud provider-এর target tracking-এর ভেতরের হিসাব হুবহু প্রকাশিত নাও হতে পারে, তবে হাতে অনুমানের জন্য এটি ভালো মডেল।

৩ · কোন signal দেখে সিদ্ধান্ত

ভুল signal মানে ভুল জ্বরের থার্মোমিটার। প্রশ্ন একটাই: কোন সংখ্যাটি সবচেয়ে আগে আর সবচেয়ে সৎভাবে বলে যে আরও instance লাগবে?

Signalকখন ভালোফাঁদ
CPUকাজ সত্যিই CPU-নির্ভর: ছবি বদল, হিসাব, encryption১০০%-এ আটকে যায়, তাই আসল চাপ দেখায় না। I/O-র অপেক্ষায় থাকা app-এ কম দেখায়।
Requests per targetWeb আর API, যেখানে এক instance কত পারে load test-এ জানাআটকায় না, কিন্তু ভারী আর হালকা অনুরোধকে সমান গোনে। নতুন release-এ ক্ষমতা বদলালে target-ও বদলাতে হয়।
Queue depthপেছনের worker, যারা queue থেকে কাজ নেয় (পর্ব ৭০)মোট সংখ্যা নয়, worker-প্রতি জমা কাজ ধরতে হয়। প্রতি কাজের সময় বদলালে হিসাবও বদলায়।

নিচের ক্যালকুলেটরে ছয়টি কাজের হিসাব একসাথে আছে। প্রতিটি সংখ্যা অনুমিত, বদলে “চালান” চাপুন। কোনো account লাগবে না।

// Worked autoscaling numbers. Every input is ASSUMED: change them and Run.
const ceil = Math.ceil, MIN = 4, MAX = 30;
const desired = (n, m, t) => Math.min(MAX, Math.max(MIN, ceil(n * m / t)));

console.log("A. desired = ceil(current x metric / target), then clamp to 4..30");
for (const [n, m, t] of [[6, 150, 60], [6, 65, 60], [20, 35, 60], [18, 320, 60], [5, 20, 60]])
  console.log(`  ${n} x ${m} / ${t} = ${(n * m / t).toFixed(2)} -> ${desired(n, m, t)}`);

console.log("B. CPU is stuck at 100%, true demand needs 30 instances");
let n = 6, demand = 1800, round = 0;              // 1800 req/s, 1 instance = 100 req/s
while (n * 100 / demand < 1) {                    // saturated: CPU reads 100
  const next = desired(n, 100, 60);
  console.log(`  round ${++round}: ${n} -> ${next}`); n = next;
}
const cpu = demand / n, last = desired(n, cpu, 60);
console.log(`  round ${++round}: ${n} at ${cpu.toFixed(1)}% -> ${last}`);

console.log("C. Queue depth: backlog per worker");
const backlog = 90000, rate = 20, maxWait = 300;  // jobs, jobs/s per worker, seconds
const perWorker = rate * maxWait;
console.log(`  target ${perWorker} jobs per worker -> ${ceil(backlog / perWorker)} workers`);

console.log("D. Target needed if load grows g per minute for T minutes");
for (const [g, T] of [[0.05, 4], [0.20, 4], [0.20, 2]])
  console.log(`  g=${g * 100}% T=${T}: target <= ${(100 / (1 + g) ** T).toFixed(1)}%`);

console.log("E. The real max is the smallest limit");
const lim = { configured: 30, quota: Math.floor(96 / 4), db: Math.floor(500 / 20) };
console.log(`  max ${lim.configured}, quota ${lim.quota}, db ${lim.db} -> usable ${Math.min(...Object.values(lim))}`);

console.log("F. One zone of Z lost: utilisation of the survivors");
for (const [u, z] of [[60, 3], [70, 3], [60, 2]])
  console.log(`  target ${u}%, ${z} zones -> ${(u * z / (z - 1)).toFixed(1)}%`);

আউটপুট:

A. desired = ceil(current x metric / target), then clamp to 4..30
  6 x 150 / 60 = 15.00 -> 15
  6 x 65 / 60 = 6.50 -> 7
  20 x 35 / 60 = 11.67 -> 12
  18 x 320 / 60 = 96.00 -> 30
  5 x 20 / 60 = 1.67 -> 4
B. CPU is stuck at 100%, true demand needs 30 instances
  round 1: 6 -> 10
  round 2: 10 -> 17
  round 3: 17 -> 29
  round 4: 29 at 62.1% -> 30
C. Queue depth: backlog per worker
  target 6000 jobs per worker -> 15 workers
D. Target needed if load grows g per minute for T minutes
  g=5% T=4: target <= 82.3%
  g=20% T=4: target <= 48.2%
  g=20% T=2: target <= 69.4%
E. The real max is the smallest limit
  max 30, quota 24, db 25 -> usable 24
F. One zone of Z lost: utilisation of the survivors
  target 60%, 3 zones -> 90.0%
  target 70%, 3 zones -> 105.0%
  target 60%, 2 zones -> 120.0%

A: 18 x 320 / 60 = 96.00 হলেও ফল 30, কারণ max আটকায়। 5 x 20 / 60-এ ফল 4, কারণ min ধরে রাখে। B: আসল চাহিদা ১,৮০০ অনুরোধ/সেকেন্ড, দরকার ৩০টি। কিন্তু CPU ১০০-এর ওপরে উঠতে পারে না, তাই সূত্র কম চায়: 6 -> 10 -> 17 -> 29 -> 30. চার দফা, আর প্রতি দফায় boot-এর অপেক্ষা। Request-ভিত্তিক metric-এ এক দফাই যথেষ্ট, কারণ ৬টিতে metric ৩০০ দেখায়।

C: প্রতি worker সেকেন্ডে ২০টি কাজ করে, আর ৩০০ সেকেন্ডের বেশি অপেক্ষা চাই না, তাই worker-প্রতি ৬,০০০টি কাজ জমতে পারে। ৯০,০০০ ÷ ৬,০০০ = ১৫ জন worker. D: Headroom-এর সূত্র: target ≤ ১ ÷ (১ + g)T. প্রতি মিনিটে চাপ ২০% বাড়লে আর সাড়া দিতে ৪ মিনিট লাগলে target ৪৮.২%-এর নিচে রাখতে হবে। সাড়ার সময় ২ মিনিটে নামালে ৬৯.৪% চলে। তাই দ্রুত boot মানে কম অলস ক্ষমতা, অর্থাৎ কম খরচ।

E: Max লেখা ৩০, কিন্তু vCPU quota ৯৬ ÷ ৪ = ২৪টি instance, আর database-এর ৫০০ connection ÷ ২০ = ২৫টি। আসল সীমা 24. F: তিন zone-এ target ৬০% হলে একটি zone হারিয়ে বাকিরা ৯০%-এ চলে। ৭০% হলে 105.0%, অর্থাৎ overload. দুই zone-এ ৬০%-ও টেকে না। তিন zone-এ নিরাপদ সীমা ২ ÷ ৩ ≈ ৬৬.৭%.

৪ · ঈদের সেল — boot-এর দেরির আসল দাম

একটি কাল্পনিক অনলাইন বাজার অ্যাপ ধরি। প্রতিটি instance সেকেন্ডে ১০০ অনুরোধ পারে, target ৬০, শুরুতে ৬টি, max ৩০. মিনিট ৫-এ ঈদের সেল শুরু, দুই মিনিটে চাপ ৩৬০ থেকে ১,৮০০ হলো। Metric পড়া হয় প্রতি মিনিটের শেষে, আর নতুন instance traffic নিতে পারে ৩ মিনিট পরে। ক্ষমতার বাইরের অনুরোধ এই মডেলে বাদ পড়ে।

নিচের ধাপগুলোতে যারা boot-এ আছে তাদের দিকে নজর রাখুন। “পরে” চাপুন।

মিনিটের শুরুর অবস্থা
মিনিট
চাপ (req/s)
Ready
Boot-এ
ক্ষমতা (req/s)
ব্যস্ততা
এই মিনিটে বাদ
মোট বাদ
  1. মিনিট ৪, শান্ত। ৩৬০ ÷ ৬ = ৬০, ঠিক লক্ষ্যে। প্রতিটি instance-এর হাতে ৪০ অনুরোধের headroom. ব্যস্ততা ৬০%.
  2. মিনিট ৫, সেল শুরু। চাপ ৯০০, ক্ষমতা ৬০০. প্রতি সেকেন্ডে ৩০০ অনুরোধ বাড়তি, তাই ৩০০ × ৬০ = ১৮,০০০ বাদ। মিনিটের শেষে metric ১৫০ দেখে desired হলো ১৫, ৯টি চালু হওয়া শুরু।
  3. মিনিট ৬. চাপ ১,৫০০. ৯টি boot-এ আছে, কিন্তু traffic নিতে পারে না। ৯০০ × ৬০ = ৫৪,০০০ বাদ। মিনিটের শেষে desired ২৫. আগের ৯টি গোনা হলো বলে যোগ হলো ১০টি, ১৯টি নয়।
  4. মিনিট ৭. চাপ চূড়ায়, ১,৮০০. ১,২০০ × ৬০ = ৭২,০০০ বাদ। Desired ৩০, যা max-ও। শেষ ৫টি চালু হলো। মোট ২৪টি এখন boot-এ।
  5. মিনিট ৮, সবচেয়ে কষ্টের মিনিট। Autoscaler-এর আর কিছু করার নেই, সব সিদ্ধান্ত হয়ে গেছে। তবু আরও ৭২,০০০ বাদ। মোট ২,১৬,০০০. এটিই boot-এর দেরির দাম।
  6. মিনিট ৯. প্রথম ৯টি এলো, ready ১৫. ক্ষমতা ১,৫০০, চাপ ১,৮০০. ৩০০ × ৬০ = ১৮,০০০ বাদ।
  7. মিনিট ১০. আরও ১০টি, ready ২৫. ক্ষমতা ২,৫০০, ব্যস্ততা ৭২%. এই প্রথম কোনো অনুরোধ বাদ পড়েনি।
  8. মিনিট ১১, শান্ত। ৩০টি ready, ১,৮০০ ÷ ৩০ = ৬০, আবার লক্ষ্যে। মোট ক্ষতি ২,৩৪,০০০ অনুরোধ, অথচ autoscaler কোনো ভুল করেনি।

এবার নিজে সংখ্যা বদলান। নিচের simulator-এ ms হলো latency-র একটি মোটা অনুমান: ৫০ ÷ (১ − ব্যস্ততা), ১,০০০ ms-এ আটকানো। এটি মাপা latency নয়, শুধু দিক বোঝায়।

// Eid sale: autoscaler against a sudden spike, minute by minute. Scale-in is left out.
// ASSUMED: 1 instance = 100 req/s; target 60 req/s per instance; max 30.
// The metric is read at the end of a minute; new instances serve BOOT minutes later.
const CAP = 100, TARGET = 60, MIN = 4, MAX = 30;
const load = [360, 360, 360, 360, 360, 900, 1500, 1800, 1800, 1800, 1800, 1800,
              1800, 1500, 1200, 900, 600, 480];

function run(BOOT, schedAt) {          // schedAt: minute when min is raised to MAX
  let ready = 6, boot = [], drop = 0, paid = 0, rows = [];
  for (let t = 0; t < load.length; t++) {
    ready += boot.filter(b => b === t).length;
    boot = boot.filter(b => b > t);
    const L = load[t], rho = L / (ready * CAP);
    const lost = Math.max(0, L - ready * CAP) * 60;
    const ms = Math.round(50 / (1 - Math.min(rho, 0.95)));   // latency proxy
    drop += lost; paid += ready + boot.length;
    rows.push({ t, L, ready, wait: boot.length, rho, ms, lost });
    const floor = t >= schedAt ? MAX : MIN;
    const want = Math.min(MAX, Math.max(floor, Math.ceil(ready * (L / ready) / TARGET)));
    for (let i = ready + boot.length; i < want; i++) boot.push(t + 1 + BOOT);
  }
  return { rows, drop, paid };
}
console.log("min  load ready+boot  rho    ms   dropped");
for (const r of run(3, 99).rows.slice(4, 13))
  console.log(String(r.t).padStart(3), String(r.L).padStart(5),
    `${r.ready}+${r.wait}`.padStart(10), `${Math.round(r.rho * 100)}%`.padStart(5),
    String(r.ms).padStart(5), String(r.lost).padStart(9));
console.log("--- BOOT minutes -> dropped requests, instance-minutes");
for (const b of [1, 3, 6, 10]) {
  const x = run(b, 99);
  console.log(`boot ${String(b).padStart(2)}: dropped ${String(x.drop).padStart(7)}, paid ${x.paid}`);
}
const s = run(3, 1);
console.log(`scheduled at minute 1 (boot 3): dropped ${s.drop}, paid ${s.paid}`);

আউটপুট:

min  load ready+boot  rho    ms   dropped
  4   360        6+0   60%   125         0
  5   900        6+0  150%  1000     18000
  6  1500        6+9  250%  1000     54000
  7  1800       6+19  300%  1000     72000
  8  1800       6+24  300%  1000     72000
  9  1800      15+15  120%  1000     18000
 10  1800       25+5   72%   179         0
 11  1800       30+0   60%   125         0
 12  1800       30+0   60%   125         0
--- BOOT minutes -> dropped requests, instance-minutes
boot  1: dropped   90000, paid 376
boot  3: dropped  234000, paid 376
boot  6: dropped  450000, paid 376
boot 10: dropped  612000, paid 376
scheduled at minute 1 (boot 3): dropped 0, paid 492

ওপরের সারিগুলো stepper-এর সাথে হুবহু মেলে। শেষের অংশটিই আসল শিক্ষা: boot ১ মিনিট হলে বাদ 90000, ৩ মিনিটে 234000, ১০ মিনিটে 612000. paid সব ক্ষেত্রে 376, কারণ instance চালু হওয়ার মুহূর্ত থেকেই ভাড়া লাগে; boot-এ থাকা instance ভাড়া খায়, কাজ করে না।

Scheduled সারিতে মিনিট ১-এ min ৩০ করা হয়েছে, তাই মিনিট ৫-এর আগেই সব তৈরি: বাদ 0, ভাড়া 492. বাড়তি ১১৬ instance-মিনিট, অর্থাৎ প্রায় ৩১% বেশি ভাড়ায় পুরো ক্ষতি মুছে গেল।

একটি ব্যর্থতার গল্প (কাল্পনিক)

দলটি পরীক্ষায় দেখেছিল boot ৩ মিনিট। তাই সেলের রাতে শুধু target tracking-এ ভরসা করল। কিন্তু সেই রাতে নতুন instance startup script-এ package নামাচ্ছিল, আর config আনছিল সেই database থেকে, যা নিজেই চাপে কাঁপছিল। Boot হয়ে গেল ১০ মিনিট।

Simulator-এর boot 10 সারিটি সেই রাতের গল্প: 612000 অনুরোধ বাদ। প্রথম ৯টি instance মিনিট ১৬-তে এলো, যখন চাপ নেমে ৬০০. ভিড় শেষ, ক্রেতা চলে গেছেন, ভাড়ার বিল শুরু। পরের দিনের postmortem-এ তিনটি শিক্ষা উঠে এলো:

  • জানা ভিড়ে আগেই বাড়ান। Scheduled min সেল শুরুর অন্তত boot-এর সময়ের চেয়ে বেশি আগে বসান, আর বাড়তি সময় রাখুন।
  • Boot ছোট রাখুন। সব package image-এ পুরে দিন (পর্ব ১৬), startup-এ শুধু config আনুন। প্রয়োজনে warm pool ব্যবহার করুন।
  • চাপের মধ্যেই boot মাপুন। শান্ত পরিবেশের ৩ মিনিট ভিড়ের রাতের ৩ মিনিট নয় (load test, পর্ব ৬৮)।

Target tracking বনাম step

একই instance আর একই boot, শুধু নিয়ম আলাদা। Step-এর ধাপ: metric ৭০-এ +২, ৮৫-এ +৪, ১০০-এ +৮, আর boot-এ থাকা সংখ্যা বাদ দিয়ে যোগ। দুই রকম চাপে চালিয়ে দেখি: হঠাৎ ধাক্কা আর ধীরে বাড়া।

// Target tracking vs step policy on two traffic shapes (scale-in is left out).
// ASSUMED: 1 instance = 100 req/s, target 60, boot 3 minutes, start 6, max 30.
const CAP = 100, TARGET = 60, BOOT = 3, MAX = 30;
const sudden = [360, 360, 360, 360, 360, 900, 1500, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800];
const ramp = Array.from({ length: 30 }, (_, i) => Math.min(1800, 360 + 60 * i));

function stepAdd(m) { return m >= 100 ? 8 : m >= 85 ? 4 : m >= 70 ? 2 : 0; }

function run(load, policy) {
  let ready = 6, boot = [], drop = 0, paid = 0, peak = 6;
  for (let t = 0; t < load.length; t++) {
    ready += boot.filter(b => b === t).length;
    boot = boot.filter(b => b > t);
    const L = load[t], metric = L / ready;
    drop += Math.max(0, L - ready * CAP) * 60;
    paid += ready + boot.length;
    let add;
    if (policy === "tracking") add = Math.ceil(ready * metric / TARGET) - ready - boot.length;
    else add = stepAdd(metric) - boot.length;       // in-flight capacity counts
    add = Math.min(add, MAX - ready - boot.length);
    for (let i = 0; i < add; i++) boot.push(t + 1 + BOOT);
    peak = Math.max(peak, ready + boot.length);
  }
  return { drop, paid, peak, ready };
}
const show = (name, x) => console.log(name.padEnd(16), "dropped", String(x.drop).padStart(7),
  " paid", String(x.paid).padStart(4), " peak", String(x.peak).padStart(2), " end", x.ready);
console.log("sudden spike");
show("target tracking", run(sudden, "tracking")); show("step", run(sudden, "step"));
console.log("slow ramp (+60 req/s each minute)");
show("target tracking", run(ramp, "tracking")); show("step", run(ramp, "step"));

আউটপুট:

sudden spike
target tracking  dropped  234000  paid  286  peak 30  end 30
step             dropped  312000  paid  204  peak 24  end 22
slow ramp (+60 req/s each minute)
target tracking  dropped       0  paid  577  peak 30  end 30
step             dropped       0  paid  512  peak 26  end 24

হঠাৎ ধাক্কায় step-এর সবচেয়ে বড় ধাপ +৮, তাই প্রথম দফায় ৬ থেকে মাত্র ১৪. দ্বিতীয় দফা শুরুই হয় ৪ মিনিট পরে। ফল 312000 বাদ, target tracking-এর 234000-এর চেয়ে ৭৮,০০০ বেশি। ধীরে বাড়ায় কেউই কিছু হারায় না, আর step-এর paid কম (512 বনাম 577). কারণ step-এর কোনো লক্ষ্য নেই, সে metric ৭০-এর নিচে এলেই থামে; এখানে 1800 / 26 ≈ 69-এ, ৬০-এ নয়।

এই ফল ধাপের ওপর নির্ভর করে। ধাপ ভালো সাজালে step-ও দ্রুত হতে পারে, কিন্তু সাজানো আর বজায় রাখার দায় আপনার। তাই সাধারণ পরামর্শ: আগে target tracking; নিখুঁত নিয়ন্ত্রণ দরকার হলে তবেই step.

৫ · Warm-up, cooldown আর flapping

নতুন instance “running” হলেই কাজের হয় না। তার cache ফাঁকা, connection pool খোলেনি, runtime গরম হয়নি। এই সময়টি warm-up. এই অবস্থায় তার metric গড়ে ঢুকলে autoscaler ভুল বোঝে। তাই AWS-এ instance warmup সেটিং আছে, আর Google Cloud-এ initialization period: এই সময়ে নতুন instance-এর মান গড়ে ধরা হয় না বা আলাদাভাবে দেখা হয় (provider-ভেদে আলাদা)।

Cooldown হলো দুটি সিদ্ধান্তের মাঝের বিরতি, যাতে আগের সিদ্ধান্তের ফল মাপে আসার সুযোগ পায়। Stabilization window একটু বুদ্ধিমান: গত কয়েক মিনিটের সুপারিশ মনে রেখে কমানোর সময় সবচেয়ে বড়টি মানে।

অফিসের এসি যদি ২৫°-র ওপরে চালু আর ২৫°-র নিচে বন্ধ হয়, তাহলে compressor সারাদিন চালু-বন্ধ করে নষ্ট হবে। তাই ২৬°-এ চালু আর ২৩°-এ বন্ধ করা হয়। মাঝের ফাঁকটুকুই hysteresis.

এই ফাঁক না থাকলে দেখা দেয় flapping: চাপ প্রায় এক, অথচ instance বারবার বাড়ে-কমে। প্রতিটি ঘূর্ণিতে boot-এর ভাড়া, ফাঁকা cache আর কাটা connection-এর দাম। নিচের চাপ ২৮৫ থেকে ৩০৫-এর মধ্যে থাকে, নিয়ম: ৭০-এর ওপরে +২, ৫০-এর নিচে −২. প্রতিটি অঙ্ক এক মিনিটের instance সংখ্যা।

// Flapping: load barely moves, yet a careless rule never settles. 60 simulated minutes.
// Rule: metric > 70 add 2; metric < 50 remove 2. New instances serve after 2 minutes.
let seed = 7;                                      // mulberry32: repeatable noise
const rand = () => { seed = (seed + 0x6D2B79F5) | 0; let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
  t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; };
const load = Array.from({ length: 60 }, () => Math.round(285 + 20 * rand()));  // 285..305 req/s
const BOOT = 2, MIN = 4;

function run(cooldown, safeIn) {
  let ready = 6, boot = [], last = -99, starts = 0, stops = 0, paid = 0, strip = "";
  for (let t = 0; t < load.length; t++) {
    ready += boot.filter(b => b === t).length; boot = boot.filter(b => b > t);
    const m = load[t] / ready; strip += ready.toString(16); paid += ready + boot.length;
    if (t - last < cooldown || boot.length) continue;
    if (m > 70) { boot.push(t + 1 + BOOT, t + 1 + BOOT); starts += 2; last = t; }
    else if (m < 50 && ready - 2 >= MIN) {
      if (safeIn && load[t] / (ready - 2) > 60) continue;  // would overshoot: hold
      ready -= 2; stops += 2; last = t;
    }
  }
  return { strip, starts, stops, paid };
}
for (const [name, c, s] of [["no cooldown", 0, false], ["cooldown 10", 10, false],
                            ["cooldown 10 + safe scale-in", 10, true]]) {
  const r = run(c, s);
  console.log(name); console.log(" ", r.strip);
  console.log(`  launches ${r.starts}, terminations ${r.stops}, paid ${r.paid} instance-minutes`);
}

আউটপুট:

no cooldown
  644464446444664446444664446444644464446444644464446444664446
  launches 28, terminations 30, paid 332 instance-minutes
cooldown 10
  644444444444466666666444444444444666666664444444444446666666
  launches 6, terminations 6, paid 300 instance-minutes
cooldown 10 + safe scale-in
  666666666666666666666666666666666666666666666666666666666666
  launches 0, terminations 0, paid 360 instance-minutes

ফাঁদটি পাটিগণিতের। ৬টিতে metric প্রায় ৪৯, তাই ২টি বাদ। ৪টিতে তা হয় ৪৯ × ৬ ÷ ৪ = ৭৩.৫, যা ৭০-এর ওপরে, তাই আবার ২টি যোগ। কমানোর সিদ্ধান্ত নিজেই বাড়ানোর শর্ত তৈরি করছে। no cooldown-এ ৬০ মিনিটে 28টি launch আর 30টি termination.

Cooldown ১০ মিনিট ঘূর্ণি থামায় না, শুধু ধীর করে: 6টি launch. তৃতীয় সারিতে কমানোর আগে একটি হিসাব আছে: বাদ দিলে metric ৬০ ছাড়াবে কি না। ছাড়ালে কমানো স্থগিত থাকে। ফল শূন্য ঘটনা, কিন্তু paid 360, যা 300-এর চেয়ে বেশি। স্থিরতারও একটি দাম আছে।

কমানোর নিরাপত্তা-শর্ত

N থেকে k টি বাদ দিলে নতুন metric = metric × N ÷ (N − k). এই মান বাড়ানোর সীমার নিচে থাকতে হবে। Target tracking এই ফাঁক নিজেই সামলানোর চেষ্টা করে; হাতে লেখা rule-এ দায়িত্ব আপনার।

তাই সাধারণ নীতি: বাড়ান দ্রুত, কমান ধীরে। কম instance-এ ব্যবহারকারী ফিরে যান, বেশি instance-এ কয়েক মিনিটের ভাড়া যায়। দুই ভুলের দাম সমান নয়।

৬ · Health check আর instance বদল

Group দুই রকম health check-এর খবর শুনতে পারে, আর পার্থক্যটি বড়:

🖥️ Instance check

Hypervisor দেখে VM চলছে কি না, hardware আর network ঠিক আছে কি না। হাজিরা খাতার মতো: মানুষটি অফিসে এসেছেন।

App-এর খবর জানে না

🌐 Load balancer check

নির্দিষ্ট path-এ, যেমন /healthz, HTTP অনুরোধ পাঠিয়ে উত্তর দেখে। মানুষটি সত্যিই কাজ করছেন কি না, সেই পরীক্ষা।

App-এর আসল অবস্থা

App deadlock-এ আটকালে VM দিব্যি “running”. Group যদি শুধু instance check শোনে, তাহলে load balancer সেটিকে বাদ দেবে, কিন্তু group ভাববে সব ঠিক। Desired ৬, কাজ করছে ৫, আর কেউ বদলাচ্ছে না। AWS-এ এই কারণেই --health-check-type ELB; অন্য provider-এ autohealing বা application health নামে একই ধারণা।

নতুন instance-কে শুরুতে কিছুটা সময় দিতে হয়, নইলে boot শেষের আগেই “অসুস্থ” বলে মেরে ফেলা হবে, আর ঘূর্ণি চলতেই থাকবে। সেই সময়টি grace period. Boot আর warm-up-এর চেয়ে সামান্য বড় রাখুন। ডিফল্ট মান provider আর তৈরির পথভেদে আলাদা, তাই ধরে না নিয়ে দেখে নিন।

চাপ ৩০০ req/s, check প্রতি ১০ সেকেন্ডে (অনুমিত)
সময় (সেকেন্ড)
Desired
LB-তে healthy
প্রতি healthy-তে চাপ
web-5
web-7 (AZ-c)
ব্যর্থ অনুরোধ (মোট)
  1. ০ সেকেন্ড. AZ-c-র web-5-এ app আটকে গেল। VM চলছে, instance check সবুজ। কিন্তু load balancer জানে না, এখনো ৬ ভাগের ১ ভাগ চাপ, অর্থাৎ সেকেন্ডে ৫০ অনুরোধ সেখানে পাঠাচ্ছে।
  2. ৩০ সেকেন্ড. পরপর ৩টি check ব্যর্থ, তাই load balancer web-5 বাদ দিল। এর মধ্যে ৫০ × ৩০ = ১,৫০০ অনুরোধ ব্যর্থ। বাকি ৫টি নিচ্ছে ৩০০ ÷ ৫ = ৬০ করে।
  3. ৪০ সেকেন্ড. Group খবর পেল, web-5-কে unhealthy চিহ্নিত করে বন্ধ করতে শুরু করল। Desired ৬ বদলায়নি, এটি scaling নয়, মেরামত।
  4. ৪৫ সেকেন্ড. Group বদলি web-7 চালু করল, AZ-c-তেই, যাতে zone সমান থাকে। Grace period শুরু।
  5. ১৬৫ সেকেন্ড. ১২০ সেকেন্ডে boot শেষ। Load balancer এবার পরীক্ষা শুরু করেছে, কিন্তু traffic দেওয়ার আগে পরপর ২টি সফল check চায়।
  6. ১৮৫ সেকেন্ড. ২ × ১০ সেকেন্ড পরে web-7 in service. আবার ৬টি, প্রতিটিতে ৫০. কেউ রাত ৩টায় ফোন পাননি। তবে ১,৫০০ অনুরোধের ক্ষতি detection-এর দাম; interval কমালে ক্ষতি কমে, কিন্তু সাময়িক ঝাঁকুনিতে ভুল করে বাদ পড়ার ঝুঁকি বাড়ে।

Health check-এ database জুড়বেন না। /healthz যদি database যাচাই করে আর database ধীর হয়, তাহলে সব instance একসাথে “অসুস্থ” হবে, আর group সবাইকে বদলাতে শুরু করবে। একটি ছোট সমস্যা পুরো দলের মৃত্যু হয়ে দাঁড়ায়। Instance বদলানোর সিদ্ধান্তে শুধু সেই instance-এর নিজের অবস্থা যাচাই করুন। এর বিস্তার System Design-এর load balancing পর্বে, আর Kubernetes-এর liveness ও readiness পর্ব ৪৩-এ।

৭ · Multi-AZ বণ্টন

Group-কে একাধিক availability zone-এ ছড়ালে সে নিজে সমান রাখার চেষ্টা করে। একটি zone গেলে কী হয়, ৯টি instance আর ৩টি zone দিয়ে দেখি:

ঘটনাAZ-aAZ-bAZ-cমোট
স্বাভাবিক3339
AZ-c বিকল3306
Group বদলি বসাল5409
AZ-c ফিরল, rebalance3339

তিনটি বাস্তব কথা। প্রথমত, বদলি আসতে মিনিট লাগে, আর সেই সময়ে বাকিদের ব্যস্ততা ৬০% থেকে ৯০%-এ যায় (ওপরের হিসাব F). তাই target-এ zone হারানোর হিসাব ধরে রাখুন। দ্বিতীয়ত, যে সময় একটি zone বিকল, তখন অনেক গ্রাহক একসাথে বাকি zone-গুলোতে instance চাইছেন। ক্ষমতা নাও মিলতে পারে (অংশ ৯)। তৃতীয়ত, rebalance-এর সময় group সাধারণত আগে নতুন বসায়, পরে পুরোনো সরায়। তাই লেখার সময়ে AWS-এর নথি অনুযায়ী সংখ্যা সাময়িকভাবে max ছাড়াতে পারে (প্রায় ১০% বা ১টি, যেটি বড়)।

Scale in-এও বণ্টন বজায় থাকে: সাধারণত সবচেয়ে বেশি instance যে zone-এ, সেখান থেকে আগে বাদ যায়। Zone-এর ধারণা বিস্তারে আছে পর্ব ০৫-এ।

৮ · ভদ্রভাবে কমানো — draining, hook আর protection

Scale out-এ ভুল হলে ধীর হয়; scale in-এ ভুল হলে চলমান পেমেন্ট মাঝপথে কাটা পড়ে। তিনটি হাতিয়ার এই ঝুঁকি কমায়।

রাতে দোকান বন্ধের আগে দোকানি শাটার অর্ধেক নামান। নতুন ক্রেতা আর ঢোকেন না, ভেতরের ক্রেতারা বিল মিটিয়ে বের হন। এটি connection draining. তারপর দিনের হিসাব খাতায় তোলা, ক্যাশ গোনা, এটি lifecycle hook. আর যে কর্মচারী বড় অর্ডার প্যাক করছেন, তাঁকে আগে ছুটি দেওয়া হয় না, এটি scale-in protection.

  • Draining: Load balancer নতুন অনুরোধ বন্ধ করে, চলমানগুলোকে একটি সময়সীমা পর্যন্ত শেষ করতে দেয়। AWS-এর target group-এ এর নাম deregistration delay (লেখার সময়ে ডিফল্ট ৩০০ সেকেন্ড)। সময়টি আপনার দীর্ঘতম স্বাভাবিক অনুরোধের চেয়ে একটু বড় রাখুন।
  • Lifecycle hook: Instance-কে “বন্ধ হচ্ছে” অবস্থায় আটকে রাখে, যতক্ষণ আপনার script log আপলোড বা কাজ হস্তান্তর শেষ না করে। Launch-এর পথেও hook আছে, যেমন traffic নেওয়ার আগে cache ভরা। সময়সীমা পেরোলে নির্ধারিত ফল ধরে এগিয়ে যায়।
  • Scale-in protection: চিহ্নিত instance scale in-এ বাছাই হয় না। লম্বা job চালানো worker-এর জন্য কাজের। সীমা মনে রাখুন: এটি health check-এর কারণে বদল, হাতে বন্ধ করা বা spot ফেরত নেওয়া ঠেকায় না।

নিচের উদাহরণে ১০টি instance, চাপ ৪০০ অনুরোধ/সেকেন্ড, zone বণ্টন ৪-৩-৩. Metric ৪০, তাই ⌈১০ × ৪০ ÷ ৬০⌉ = ৭. In-flight সংখ্যাগুলো অনুমিত।

Group-এর খাতা
ঘড়ি
LB-তে সেবা দিচ্ছে
প্রতি instance-এ চাপ
বাছাই করা ৩টির in-flight
বাছাই করা ৩টির অবস্থা
Zone (a-b-c)
ভাড়া চলছে
  1. সিদ্ধান্ত। পুরো window জুড়ে সুপারিশ ৭, তাই ৩টি কমবে। আগে zone a থেকে একটি, যেখানে সবচেয়ে বেশি। কিন্তু a-1 রিপোর্ট বানাচ্ছে আর protected, তাই বাছাই হলো a-2, b-1, c-1. বণ্টন সমান থাকবে।
  2. Load balancer থেকে সরানো। নতুন অনুরোধ এখন ৭টিতে, ৪০০ ÷ ৭ ≈ ৫৭.১. এটি ৬০-এর নিচে, তাই কমানো নিরাপদ। বাছাই করা ৩টিতে ৩৬টি অনুরোধ এখনো চলছে।
  3. Draining, ৩০ সেকেন্ড পরে। বেশিরভাগ শেষ, ৯টি বাকি, সম্ভবত বড় আপলোড। কেউ কেটে দিচ্ছে না।
  4. ৬০ সেকেন্ডে in-flight ০. সময়সীমার আগেই শেষ। এবার hook: instance অপেক্ষার অবস্থায়, script শেষ log object storage-এ পাঠাচ্ছে।
  5. Hook শেষ। Script group-কে “এগিয়ে যান” সংকেত দিল। AWS-এ এটি complete-lifecycle-action-এর CONTINUE. সংকেত না এলে সময়সীমা পর্যন্ত অপেক্ষা হতো, আর instance-এর ভাড়া চলত।
  6. Terminate. OS বন্ধ হওয়ার পথে প্রক্রিয়াগুলো SIGTERM পায় (পর্ব ১১)। ভাড়া ৭টিতে নামল, বণ্টন ৩-২-২. শেষ পর্যন্ত একটিও অনুরোধ কাটা পড়েনি। ধাপের ঠিক ক্রম provider-ভেদে একটু আলাদা হতে পারে।

App-কেও সহযোগিতা করতে হয়। SIGTERM পেলে নতুন কাজ বন্ধ করে হাতের কাজ শেষ করা, অর্থাৎ graceful shutdown, আপনার কোডের দায়িত্ব। Draining আর hook শুধু সময় দেয়।

৯ · যে সীমা autoscaler পার হতে পারে না

Desired ৩০ লেখা মানে ৩০টি পাওয়া নয়। Group চেষ্টা করে, ব্যর্থ হলে activity log-এ কারণ লেখে, কিন্তু আপনার app-এর চাপ তাতে কমে না। চারটি সীমা জেনে রাখুন:

  • Provider-এর হাতে ক্ষমতা: On-demand মানে “আজ পাবেনই” নয়। কোনো zone-এ নির্দিষ্ট instance type ফুরিয়ে যেতে পারে, বিশেষ করে একটি zone বিকল হলে বা বড় আঞ্চলিক ভিড়ে। AWS-এ দেখবেন InsufficientInstanceCapacity, Google Cloud-এ ZONE_RESOURCE_POOL_EXHAUSTED, Azure-এ AllocationFailed ধরনের error.
  • Quota: Account-এর vCPU বা instance-এর সীমা। লেখার সময়ে নতুন account-এ এটি প্রায়ই খুব কম থাকে, আর বাড়াতে অনুরোধ করতে হয় (পর্ব ০৬, ৩৫)। সেলের আগের রাতে নয়, কয়েক দিন আগে বাড়ান।
  • পেছনের সীমা: ৩০টি instance × ২০ connection = ৬০০, অথচ database পারে ৫০০. ওপরের স্তর বাড়ানো নিচের স্তর ডুবিয়ে দিতে পারে।
  • Network-এর সীমা: Subnet-এ ফাঁকা IP ঠিকানা ফুরালে নতুন instance বসবে না (পর্ব ২৫)।

প্রতিরক্ষার উপায়

উপায়কী দেয়দাম
একাধিক instance typeএকটি type ফুরালেও অন্যটিতে চলেPerformance সমান নয়, তাই load test আর weight লাগে
একাধিক zoneএক জায়গায় ফুরালে অন্য জায়গাZone-পার data transfer-এর খরচ থাকতে পারে
Capacity reservationনির্দিষ্ট zone-এ ক্ষমতা ধরে রাখাব্যবহার না করলেও সাধারণত ভাড়া লাগে
Warm pool বা standbyআগে থেকে তৈরি instance দ্রুত আসেথামানো অবস্থাতেও disk-এর খরচ; ক্ষমতার নিশ্চয়তা provider-ভেদে আলাদা
Load sheddingক্ষমতা না মিললেও মূল কাজ বাঁচেকিছু ব্যবহারকারী ফেরত যান

Instance না পেলে শেষ ভরসা সিস্টেমকে ভদ্রভাবে কম কাজ করানো। সেই কৌশলগুলো আছে System Design-এর overload পর্বে। আর alarm রাখুন: group max-এ পৌঁছালে, desired আর ready অনেকক্ষণ না মিললে, আর launch ব্যর্থ হলে।

আরও গভীরে: Autoscaler একটি feedback control loop. Target tracking প্রায় একটি proportional controller, আর boot-এর সময় হলো dead time; নিয়ন্ত্রণ তত্ত্বে dead time বেশি হলে বড় সংশোধন দোলন তৈরি করে। তাই বাস্তব সিস্টেমে ব্রেক থাকে। Kubernetes HPA-র নথিতে ডিফল্ট tolerance ১০%, অর্থাৎ অনুপাত ১-এর এত কাছে হলে কিছুই করে না, আর scale-down-এর stabilization window ডিফল্ট ৩০০ সেকেন্ড। AWS-এর target tracking-এর নিজে তৈরি alarm লেখার সময়ে বাড়াতে ৩ মিনিটের আর কমাতে ১৫ মিনিটের datapoint চায়, যা “বাড়ান দ্রুত, কমান ধীরে”-র সরাসরি রূপ।

পরীক্ষা ও ইন্টারভিউতে:

  • Target tracking-এর সূত্র? desired = ⌈current × metric ÷ target⌉, তারপর min-max-এ আটকানো।
  • CPU কেন সবসময় ভালো নয়? ১০০%-এ আটকে আসল চাপ লুকায়, আর I/O-নির্ভর app-এ চাপ দেখায় না।
  • Cooldown আর warm-up-এর পার্থক্য? Cooldown দুই সিদ্ধান্তের বিরতি; warm-up নতুন instance তৈরি হওয়ার সময়।
  • Hung app কেন বদলায় না? Group শুধু instance check শুনছে; load balancer check জুড়তে হবে।
  • Scale-in protection কী ঠেকায় না? Health-ভিত্তিক বদল, হাতে বন্ধ করা আর spot ফেরত নেওয়া।

১০ · AI-এর যুগে autoscaling যাচাই

AI কয়েক সেকেন্ডে পুরো group লিখে দেয়। কিন্তু সে আপনার boot-এর সময়, quota বা database-এর সীমা জানে না। সাধারণ ভুলগুলো:

AI যা লেখেবিপদযাচাই
বড় max, যেমন ২০০, কোনো budget ছাড়াবিল আর database, দুটোই ডোবেE হিসাব, budget alert
Health type শুধু instanceআটকে যাওয়া app বদলায় নাApp থামিয়ে পরীক্ষা
Grace period ০ বা খুব ছোটনতুন instance-কে মেরে ফেলার ঘূর্ণিমাপা boot-এর সাথে মেলানো
Launch template-এ $Latestনা জেনে নতুন version ছড়ায়Version বেঁধে রাখা
Security group-এ 0.0.0.0/0, IAM-এ *অকারণ খোলা দরজাশুধু load balancer থেকে, ন্যূনতম অনুমতি
User data-তে password বা keySecret ফাঁসSecret manager (পর্ব ৩৩)
পুরোনো launch configuration বা autoscaling/v2beta2সরানো বা বাতিল হওয়া APIবর্তমান নথি দেখা
বানানো flag বা argumentCommand ব্যর্থ, বা ভুল কিছু ঘটে--help, নথি, terraform plan

AI-কে নকশা লিখতে নয়, নকশার ফাঁক খুঁজতে কাজে লাগান। নিজের মাপা সংখ্যা দিয়ে দিন, আর হিসাব দেখাতে বলুন:

আমার একটি web service-এর instance group আছে। মাপা তথ্য: প্রতি instance সেকেন্ডে [১০০] অনুরোধ পারে, চাপের মধ্যে boot-এ লাগে [৩] মিনিট, স্বাভাবিক চাপ [৩৬০] req/s, সর্বোচ্চ সম্ভাব্য চাপ [১৮০০] req/s, ৩টি zone, vCPU quota [৯৬], instance-প্রতি [৪] vCPU, database সর্বোচ্চ [৫০০] connection, instance-প্রতি pool [২০]. ১. আমার min, max আর target কত হওয়া উচিত? প্রতিটি সংখ্যার হিসাব দেখাও। ২. একটি zone বিকল হলে কী হবে, হিসাব করে দেখাও। ৩. কোন signal বেছে নেবে, আর কেন? ৪. কোনো secret, account id বা key চাইবে না। ৫. কোনো কমান্ড দিলে আগে বলো সেটি কী বদলাবে, টাকা লাগবে কি না, আর কোনটি মুছে ফেলে। বর্তমান নথিতে যে flag নিশ্চিত নয়, সেটি স্পষ্ট করে বলো।

চালুর আগের চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১Cloud-এর বিজ্ঞাপনে “সীমাহীন” ক্ষমতার কথা শোনা যায়। তাহলে autoscaler instance চেয়েও না পায় কেন?

কারণ cloud-ও শেষ পর্যন্ত ভবনে রাখা যন্ত্র। Provider অনেক গ্রাহকের চাহিদা গড় করে ক্ষমতা কেনেন। সবার চাহিদা একসাথে না বাড়লে এই গড় ভালো কাজ করে, আর একজন গ্রাহকের কাছে ক্ষমতা সীমাহীন মনে হয়। সমস্যা হয় যখন চাহিদা একসাথে বাড়ে।

সবচেয়ে পরিচিত উদাহরণ ২০২০ সালের মার্চ। মহামারির শুরুতে অনলাইন ক্লাস আর দূর থেকে কাজ হঠাৎ বেড়ে গেলে Microsoft প্রকাশ্যে জানায় যে কিছু Azure region-এ ক্ষমতার চাপ দেখা দিয়েছে, আর জরুরি সেবাগুলোকে অগ্রাধিকার দেওয়া হচ্ছে। এটি কোনো “ত্রুটি” ছিল না; ভৌত ক্ষমতা রাতারাতি বাড়ানো যায় না, কারণ যন্ত্র, বিদ্যুৎ আর ভবন সবই সময় নেয়।

আরেকটি পরিস্থিতি একটি zone-এর বিকলতা। তখন হাজারো গ্রাহকের group একসাথে বাকি zone-গুলোতে instance চায়। আপনার autoscaler ঠিক তখনই সবচেয়ে বেশি চায়, যখন পাওয়া সবচেয়ে কঠিন। এজন্যই স্থিতিশীল নকশায় বিকলতার সময় নতুন কিছু চাওয়ার ওপর নির্ভর না করে আগে থেকেই বাড়তি চালু রাখা হয়, যাকে static stability বলে (পর্ব ০৫)।

তাই গুরুত্বপূর্ণ ঘটনার আগে তিনটি প্রশ্ন করুন: quota আছে? একাধিক instance type আছে? Reservation লাগবে কি না? Reservation-এর খরচ বেশি মনে হলে হিসাব করুন, এক ঘণ্টার ব্যর্থ সেলের ক্ষতি কত। ছোট দলের জন্য সস্তা অভ্যাসও আছে: বড় ঘটনার কয়েক দিন আগে কিছুক্ষণের জন্য পুরো max পর্যন্ত চালু করে দেখা। এতে quota, subnet আর instance type-এর ভুল আগেই ধরা পড়ে, যদিও সেদিনের ক্ষমতা পরের দিনের নিশ্চয়তা দেয় না। পরীক্ষা শেষে সংখ্যা নামিয়ে আনতে ভুলবেন না, নইলে বিল চলতে থাকবে।

মূল উপলব্ধি: Elasticity একটি পরিসংখ্যানগত সুবিধা, চুক্তিগত নিশ্চয়তা নয়। নিশ্চয়তা চাইলে আগে থেকে কিনতে হয়।

প্র ০২Target tracking এত সহজ হলে দ্রুত সাড়ার জন্য লক্ষ্য খুব নিচে, যেমন ২০%, রাখলেই তো হয়। সমস্যা কোথায়?

২০% target মানে আপনি পাঁচ গুণ ক্ষমতার ভাড়া দিচ্ছেন। এটি অবশ্যই কাজ করে: ধাক্কা এলে ৫ গুণ পর্যন্ত চাপ মিশে যায়, autoscaler-এর দেরি লুকিয়ে যায়। কিন্তু তখন autoscaling-এর আর্থিক যুক্তিটাই দুর্বল।

আসল প্রশ্ন তাই “কত নিচে” নয়, “কত ধাক্কা, কত সময়ে”। এই পর্বের হিসাব D সেটিই বলে: target ≤ ১ ÷ (১ + g)T. এখানে T হলো সাড়ার সময়। g কমানো আপনার হাতে নেই, কিন্তু T কমানো আছে। Image-এ সব package পুরে দিলে, warm pool রাখলে, অথবা container ব্যবহার করলে T ছোট হয়। আর T ছোট মানে একই নিরাপত্তায় target ওপরে তোলা যায়, অর্থাৎ বিল কমে। ওপরের হিসাবে চাপ ২০% হারে বাড়লে T ৪ থেকে ২ মিনিটে নামালে target ৪৮.২% থেকে ৬৯.৪%-এ যায়। ফলে একই চাপে প্রায় ৩০% কম instance লাগে।

অন্য একটি সীমাও আছে। খুব ছোট target-এ metric-এর শব্দ বড় হয়ে ওঠে, আর মাঝারি ওঠানামায় অকারণ scaling হয়। উল্টো দিকে খুব উঁচু target, যেমন ৯০%, queue-র তত্ত্ব মানে না: ব্যস্ততা ১০০%-এর কাছে গেলে অপেক্ষা হঠাৎ বেড়ে যায়, তাই সামান্য বাড়তি চাপেই latency লাফ দেয়। বেশিরভাগ web সার্ভিস তাই মাঝামাঝি একটি মান বেছে নেয়। সেই মান load test আর SLO থেকে আসা উচিত, অনুমান থেকে নয়।

মূল উপলব্ধি: Headroom হলো আপনার ধীর boot-এর জন্য দেওয়া নিয়মিত কিস্তি। Boot দ্রুত করা মানে সেই কিস্তি কমানো।

প্র ০৩Autoscaler কি নিজেই একটি outage ঘটাতে পারে? Max না রাখলে কী হতে পারে?

পারে, আর এটি তাত্ত্বিক ভয় নয়। ২০২১ সালের ডিসেম্বরে AWS-এর us-east-1 region-এ বড় বিভ্রাট হয়। AWS-এর প্রকাশিত সারাংশ অনুযায়ী, মূল network-এ চলা একটি সার্ভিসের ক্ষমতা বাড়ানোর স্বয়ংক্রিয় কাজ অভ্যন্তরীণ network-এর বহু client-এর মধ্যে অপ্রত্যাশিত আচরণ শুরু করে, যা সংযোগের জোয়ার তৈরি করে, আর retry সেটিকে আরও বাড়ায়। ক্ষমতা বাড়ানো, যা সাধারণত ভালো কাজ, ভুল সময়ে ভুল স্তরে বিপদ হয়ে উঠেছিল।

ছোট মাপেও একই ধাঁচ দেখা যায়। ধরুন database ধীর হলো। অনুরোধ লম্বা হলো, CPU বা concurrency বাড়ল, autoscaler আরও instance চালু করল। প্রতিটি নতুন instance connection pool খুলল, তাতে database-এর চাপ আরও বাড়ল। সিস্টেম নিজের সমস্যাকে নিজেই বড় করছে। এজন্য latency-কে একমাত্র signal করা ঝুঁকিপূর্ণ, কারণ latency বাড়ার কারণ app-এর ক্ষমতা নাও হতে পারে।

Max না থাকলে দ্বিতীয় বিপদ আর্থিক। একটি লুপে আটকে যাওয়া বাগ, retry-র ঝড় বা ক্ষতিকর traffic-এর ঢেউ, সবই metric বাড়ায়। Autoscaler সরল বিশ্বাসে instance বাড়ায়, আর বিল বাড়ে। আক্রমণের সময় ভালো উত্তর আরও server নয়, বরং edge-এ ছাঁকা (পর্ব ৩০) আর rate limit.

তাই max কোনো সাজসজ্জা নয়। এটি হিসাব করে বসানো একটি fuse: database connection, quota আর budget-এর ন্যূনতম। সাথে থাকবে alarm, যাতে মানুষ জানেন যে যন্ত্র সীমায় পৌঁছেছে।

মূল উপলব্ধি: Autoscaling সমস্যা সমাধান করে না, ক্ষমতা জোগায়। যে সমস্যা ক্ষমতার নয়, সেখানে বাড়তি ক্ষমতা আগুনে বাতাস দেয়।

প্র ০৪Predictive scaling থাকতে ঈদের জন্য হাতে schedule লিখতে হবে কেন? মেশিন কি নিজেই শিখতে পারে না?

Predictive scaling নতুন ধারণা নয়। Netflix ২০১৩ সালে Scryer নামের নিজেদের পূর্বাভাস-ইঞ্জিনের কথা ব্লগে লেখে, কারণ তাদের দৈনিক দর্শকের ঢেউ খুব নিয়মিত, আর reactive autoscaling সেই ঢেউয়ের পেছনে ছুটত। পরে বড় provider-রাও এমন সুবিধা যোগ করে।

এই পদ্ধতির ভিত্তি একটি অনুমান: আগামীকাল গতকালের মতো হবে। সাধারণত এটি সকাল-সন্ধ্যার ঢেউ আর সাপ্তাহিক ধাঁচ ভালো ধরে। কারণ এই ধাঁচ আগের কয়েক দিন বা সপ্তাহের তথ্যেই আছে।

ঈদ এই অনুমান ভেঙে দেয়, আর কারণটি এদেশের পাঠকের কাছে পরিচিত। ঈদের তারিখ চন্দ্র মাস ধরে আসে, তাই ইংরেজি ক্যালেন্ডারে প্রতি বছর প্রায় ১০–১১ দিন এগিয়ে যায়, আর চাঁদ দেখার ওপর এক দিন এদিক-ওদিক হয়। গত দুই সপ্তাহের তথ্যে সেই ভিড়ের কোনো চিহ্ন নেই। তেমনই একটি খেলার ফাইনাল, ফল প্রকাশ বা বিজ্ঞাপনের হঠাৎ ছড়িয়ে পড়া মডেলের অজানা। মডেল শুধু অতীতের ধাঁচ জানে, আপনার মার্কেটিং দলের পরিকল্পনা জানে না।

ভালো পদ্ধতি তাই স্তরে স্তরে। Predictive দৈনিক ঢেউ সামলায়। Scheduled জানা ঘটনা সামলায়, কারণ তারিখটি মানুষ জানে। Target tracking যা বাকি থাকে তা সামলায়। আর load shedding সামলায় অজানা ঘটনা। প্রতিটি স্তর আগেরটির ফাঁক ঢাকে।

একটি বাস্তব অভ্যাস: বছরের বিক্রি-ক্যালেন্ডার আর infrastructure-এর ক্যালেন্ডার এক জায়গায় রাখুন, আর বড় ক্যাম্পেইনের আগে মার্কেটিং দলকে “ক্ষমতা” নিয়ে প্রশ্ন করুন।

মূল উপলব্ধি: পূর্বাভাস অতীতকে বাড়িয়ে দেখে। ভবিষ্যতের পরিকল্পিত ঘটনা জানেন মানুষ, তাই সেটি নিয়মে লিখে দিতে হয়।

প্র ০৫CPU, requests per target, queue depth, এগুলোর বাইরে সবচেয়ে “ঠিক” signal কি latency নয়? ব্যবহারকারী তো latency-ই টের পান।

যুক্তিটি আকর্ষণীয়, আর SLO-র দৃষ্টিতে latency-ই আসল মাপ (পর্ব ৬৬)। তবু autoscaling-এর signal হিসেবে এর তিনটি সমস্যা আছে।

প্রথমত, latency সবসময় ক্ষমতার ওপর নির্ভর করে না। ধীর latency-র কারণ database, একটি বাইরের payment API, বা network হতে পারে। তখন app instance বাড়িয়ে কোনো লাভ নেই, উল্টো ক্ষতি (প্রশ্ন ৩)। দ্বিতীয়ত, এটি দেরিতে বাড়ে। Queue-র তত্ত্ব বলে, ব্যস্ততা মাঝামাঝি থাকা পর্যন্ত latency প্রায় সমতল, আর সীমার কাছে হঠাৎ খাড়া হয়। যখন latency বাড়ল, তখন আপনি ইতিমধ্যে সীমায়। তৃতীয়ত, p99-এর মতো মান ওঠানামা করে, আর target tracking-এ নিখুঁত অনুপাতে মেলে না: instance দ্বিগুণ করলে latency অর্ধেক হয় না। অথচ সূত্রটি ধরে নেয় metric instance-সংখ্যার ব্যস্তানুপাতিক।

এই শেষ বিষয়টি সবচেয়ে গুরুত্বপূর্ণ। ভালো target-tracking metric-এর শর্ত: instance বাড়লে metric সমানুপাতে কমবে। Requests per target আর CPU এই শর্ত মেনে চলে। Latency সাধারণত মানে না।

Queue-ভিত্তিক সিস্টেমে একটি উন্নত রূপ হলো সবচেয়ে পুরোনো কাজের বয়স (oldest message age). বেশি জমা মানেই খারাপ নয়, যদি কাজ দ্রুত শেষ হয়; কিন্তু কাজের বয়স সরাসরি বলে ব্যবহারকারী কতক্ষণ অপেক্ষা করছেন। তবে বয়স কমাতে কতজন worker লাগবে তা সরল অনুপাতে আসে না, তাই সাধারণত worker-প্রতি জমা কাজ দিয়ে scaling করে বয়সে alarm রাখা হয়।

তাই বাস্তব বিভাজনটি এমন: scaling চলে ক্ষমতার সৎ মাপ দিয়ে, আর latency থাকে alert আর SLO-তে। Latency বলে “ব্যথা আছে”, আর অন্য metric বলে “কোথায়”।

মূল উপলব্ধি: Signal হিসেবে ভালো হওয়ার শর্ত গুরুত্ব নয়, নিয়ন্ত্রণযোগ্যতা। যে সংখ্যা আপনার হাতল ঘোরালে সরল অনুপাতে বদলায় না, তা দিয়ে হাতল চালানো যায় না।

অনুশীলন

কোনোটিতেই cloud account লাগবে না। হাতে হিসাব করুন, অথবা পাতার simulator-এ মিলিয়ে দেখুন।

  1. হিসাব: একটি group-এ এখন ১২টি instance, min ৪, max ২০, target ৬০ req/s. (ক) Metric ৯৫ হলে desired কত? (খ) Metric ১২৫ হলে? (গ) (খ)-এর পরে সব instance চালু হলে metric কত দাঁড়াবে? (ঘ) প্রতি instance ১০০ req/s পারলে (খ)-এর সময় কত অনুরোধ/সেকেন্ড বাদ পড়ছে?

    (ক) ⌈১২ × ৯৫ ÷ ৬০⌉ = ⌈১৯⌉ = ১৯. (খ) ১২ × ১২৫ ÷ ৬০ = ২৫, কিন্তু max ২০, তাই ২০. (গ) মোট চাপ ১২ × ১২৫ = ১,৫০০, তাই ১,৫০০ ÷ ২০ = ৭৫, লক্ষ্যের ওপরে; max-এ পৌঁছানোর alarm বাজা উচিত। (ঘ) ক্ষমতা ১২ × ১০০ = ১,২০০, তাই ১,৫০০ − ১,২০০ = ৩০০ অনুরোধ/সেকেন্ড বাদ, boot শেষ না হওয়া পর্যন্ত।

  2. ফল অনুমান করুন: একটি group: min ২, desired ৪, max ৬, দুই zone-এ ২ + ২. target ৬০. পরপর চারটি ঘটনার পরে সংখ্যা আর বণ্টন কী হবে? (১) কেউ হাতে desired ৮ করার চেষ্টা করলেন। (২) AZ-b বিকল হলো। (৩) সব চালু হওয়ার পর metric ৯০ দেখা গেল। (৪) AZ-b ফিরে এলো।

    (১) অনুরোধ প্রত্যাখ্যাত, কারণ ৮ > max ৬; desired ৪-ই থাকে, ২ + ২. (২) ২টি হারাল, desired ৪ পূরণে AZ-a-তে আরও ২টি: ৪ + ০. (৩) ⌈৪ × ৯০ ÷ ৬০⌉ = ৬, যা max-এর সমান: ৬ + ০. (৪) Rebalance-এ শেষ অবস্থা ৩ + ৩, মোট ৬. পথে নতুন আগে বসে, তাই সংখ্যা সাময়িকভাবে ৬ ছাড়াতে পারে। লক্ষ করুন, ধাপ ৩-এর সময় সব instance এক zone-এ।

  3. নকশা সমালোচনা: একজন সহকর্মীর group: এক zone, min ১, max ৫০০, CPU target ৯০%, cooldown ০, grace period ০, health type instance, launch template $Latest. অন্তত পাঁচটি সমস্যা ধরুন আর বদলের প্রস্তাব দিন।
    • এক zone, min ১: একটি বিকলতাতেই সেবা বন্ধ। অন্তত দুই বা তিন zone, আর min প্রতি zone-এ অন্তত ১টি।
    • Max ৫০০: Database আর বিল অরক্ষিত। Quota আর connection থেকে হিসাব করা max, সাথে alarm.
    • Target ৯০%: Headroom নেই; zone গেলে সরাসরি overload. Load test থেকে আনা মাঝামাঝি মান, আর সম্ভব হলে requests per target.
    • Cooldown ০, grace ০: Flapping আর boot শেষের আগেই বদলের ঘূর্ণি। মাপা warm-up দিয়ে দুটিই বসানো।
    • Health type instance: আটকে যাওয়া app বদলাবে না। Load balancer check জোড়া।
    • $Latest: নতুন version না জেনে ছড়াতে পারে। Version বাঁধা, আর নিয়ন্ত্রিত rollout (পর্ব ৫৯)।
  4. Simulator নিয়ে: eid_spike.js-এ শেষের দিকে run(3, 1) আছে। দ্বিতীয় সংখ্যা 2 করলে কত অনুরোধ বাদ পড়বে, আগে হাতে বলুন, তারপর চালিয়ে মেলান। Boot b মিনিট আর ভিড় শুরু মিনিট ৫ হলে, সর্বোচ্চ কোন মিনিটে schedule বসালে ক্ষতি শূন্য হয়?

    run(3, 2)-এ সিদ্ধান্ত মিনিট ২-এর শেষে, instance আসে মিনিট ২ + ১ + ৩ = ৬-এ। তাই শুধু মিনিট ৫-এ ক্ষতি: (৯০০ − ৬০০) × ৬০ = ১৮,০০০. শূন্য ক্ষতির জন্য t + ১ + b ≤ ৫, অর্থাৎ t ≤ ৪ − b. Boot ৩ হলে মিনিট ১. বাস্তবে এর সাথে নিরাপত্তার সময় যোগ করুন, কারণ ভিড়ের boot শান্ত সময়ের boot নয়, আর ক্ষমতা না মিললে চেষ্টা করার সময় লাগে।

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

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

ক্রমএকটি instance-এর scale in-এর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Autoscaler ঠিক করে desired কমবে, আর কোন instance যাবে তা বাছে
  2. Load balancer সেই instance-এ নতুন অনুরোধ পাঠানো বন্ধ করে
  3. চলমান অনুরোধগুলো draining-এ শেষ হয়
  4. Lifecycle hook-এর script log পাঠিয়ে “এগিয়ে যান” সংকেত দেয়
  5. Instance terminate হয়, আর ভাড়া বন্ধ হয়

একটি group-এ ৮টি instance, metric ৯০, target ৬০, min ২, max ১০. Target tracking-এর সূত্রে desired কত হবে?

  • ৮
  • ১২
  • ১০
  • ১৫

৬টি instance-এর সবগুলোর CPU ১০০%, আর target ৬০%. আসল চাহিদায় ৩০টি instance লাগে। CPU-ভিত্তিক target tracking এক দফায় কেন ৩০টি চায় না?

  • Max সবসময় ১০ থাকে
  • CPU ১০০%-এ আটকে যায়, তাই সূত্র আসল চাপের চেয়ে কম দেখে
  • Warm-up শেষ না হলে desired বদলানো যায় না
  • Target tracking CPU দিয়ে একেবারেই কাজ করে না

একটি app deadlock-এ আটকে গেছে। VM চলছে, load balancer সেটিকে বাদ দিয়েছে, কিন্তু desired ৬ থাকা সত্ত্বেও কাজ করছে ৫টি, আর কোনো বদলি আসছে না। সবচেয়ে সম্ভাব্য কারণ কী?

  • Quota শেষ হয়ে গেছে
  • Cooldown চলছে
  • Instance-টি scale-in protected
  • Group শুধু VM-স্তরের instance check শুনছে

চাপ স্থির। নিয়ম: metric ৭০-এর ওপরে ২টি যোগ, ৫০-এর নিচে ২টি বাদ। ৬টি instance-এ metric ৪৮. কী হবে?

  • ৪টিতে নেমে metric ৭২ হবে, আবার বাড়বে: flapping
  • ৬টিতেই স্থির থাকবে
  • ৪টিতে নেমে metric ৩২ হবে, স্থির থাকবে
  • ১টিতে নেমে যাবে

তিনটি zone-এ সমান instance, target ৭০%. একটি zone হঠাৎ বিকল হলে, বদলি আসার আগে বাকি instance-গুলোর ব্যস্ততা কত হবে?

  • ৭০%
  • ৯০%
  • ১০৫%
  • ১৪০%

Scale-in protection চালু আছে এমন একটি instance health check-এ ব্যর্থ হলে সাধারণত কী হয়?

  • Protection-এর কারণে সেটি কখনো বদলাবে না
  • Group সেটিকে তবুও বদলে দিতে পারে
  • Desired এক কমে যায়
  • পুরো group-এর scaling থেমে যায়

শব্দকোষ

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

মনে রাখুন

  1. Autoscaler শুধু desired বদলায়; min নিরাপত্তা দেয়, max খরচ আর পেছনের স্তর বাঁচায়।
  2. desired = ⌈current × metric ÷ target⌉. এমন signal বাছুন, যা আটকে যায় না আর instance বাড়লে অনুপাতে কমে।
  3. Boot-এর দেরি অনুরোধ হারায়; জানা ভিড়ে scheduled, আর target-এ headroom রাখুন।
  4. Cooldown ঘূর্ণি ধীর করে; hysteresis আর কমানোর হিসাব ঘূর্ণি থামায়।
  5. Group-কে load balancer-এর health check শোনান, scale in-এ draining ও hook রাখুন, আর quota ও ক্ষমতার সীমা আগেই যাচাই করুন।

পরের পর্বে: এই পর্ব জুড়ে load balancer ছিল পাশের চরিত্র। পর্ব ১৮-এ সে মঞ্চে আসে: L4 আর L7, target group আর TLS termination.

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

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