কনজেশন কন্ট্রোল — স্লো স্টার্ট ও AIMD
এই পাঠে যা শিখবেন
- ফ্লো কন্ট্রোল (L26) ও কনজেশন কন্ট্রোলের মধ্যে স্পষ্ট পার্থক্য
- কনজেশন উইন্ডো (cwnd) ও ssthresh কী, আর প্যাকেট লস কেন কনজেশনের সংকেত ধরা হয়
- স্লো স্টার্টের এক্সপোনেনশিয়াল বৃদ্ধি কীভাবে ও কেন কাজ করে
- AIMD-এর অ্যাডিটিভ ইনক্রিজ ও মাল্টিপ্লিকেটিভ ডিক্রিজ — cwnd-এর সম্পূর্ণ বিবর্তন Python দিয়ে সিমুলেট করে করাত-দাঁত প্যাটার্ন দেখা
১ · কনজেশন কন্ট্রোল বনাম ফ্লো কন্ট্রোল
L26-এ আমরা দেখেছি ফ্লো কন্ট্রোল কীভাবে একটি দ্রুত সেন্ডারকে একটি ধীর রিসিভারকে ওভারলোড করা থেকে ঠেকায় — এটি সম্পূর্ণভাবে রিসিভারের বাফার ক্যাপাসিটি নিয়ে চিন্তা করে। কিন্তু রিসিভার দ্রুত হলেও, সেন্ডার ও রিসিভারের মাঝখানের নেটওয়ার্ক পাথNetwork Pathসেন্ডার থেকে রিসিভার পর্যন্ত রাউটার ও লিংকের সমষ্টি, যাদের প্রত্যেকের নিজস্ব সীমিত ক্যাপাসিটি (ব্যান্ডউইথ, বাফার) আছে। — অর্থাৎ রাউটার ও লিংকগুলো — নিজেই ওভারলোড হয়ে যেতে পারে। এই দ্বিতীয় সমস্যাটিই কনজেশন কন্ট্রোলCongestion ControlTCP সেন্ডারের এমন একটি মেকানিজম যা নিজের পাঠানোর হার নেটওয়ার্কের প্রকৃত ক্ষমতার সাথে মানিয়ে নেয়, যাতে সেন্ডার-রিসিভারের মাঝের রাউটার/লিংক ওভারলোড না হয়। সমাধান করে।
রিসিভার-সাইড সমস্যা — রিসিভারের বাফার ওভারফ্লো এড়ানো।
নেটওয়ার্ক-সাইড সমস্যা — মাঝের রাউটার/লিংক ওভারলোড এড়ানো।
একটি TCP সেন্ডার আসলে দুটি সীমার মধ্যে ছোটটি মেনে চলে — রিসিভারের ঘোষিত receive window (L26) এবং সেন্ডারের নিজের হিসাব করা congestion window (cwnd, এই পাঠ)। যেটি ছোট, সেটিই একচুয়াল in-flight ডেটার সীমা নির্ধারণ করে।
২ · Congestion window (cwnd) ও ssthresh
cwnd হলো সেন্ডারের নিজের উপর আরোপ করা একটি সীমা — নেটওয়ার্ক পরিস্থিতির
উপর ভিত্তি করে সে কতটুকু ডেটা "in-flight" (পাঠানো হয়েছে কিন্তু এখনও ACK আসেনি) রাখতে
পারবে। TCP-র কাছে নেটওয়ার্কের ভেতরের অবস্থা সরাসরি দেখার কোনো উপায় নেই — তাই এটি একটি
সহজ কিন্তু কার্যকর সংকেত ব্যবহার করে —
প্যাকেট লসPacket Loss as Congestion SignalTCP ধরে নেয় প্যাকেট লস (টাইমআউট বা ডুপ্লিকেট ACK) মানে নেটওয়ার্ক কোথাও ওভারলোড, তাই সেন্ডারের উচিত পাঠানোর হার কমানো — এটি একটি অনুমান, বিট-এরর থেকেও লস হতে পারে, কিন্তু বাস্তবে বেশিরভাগ ক্ষেত্রে এই অনুমান কাজ করে।
মানে কোথাও কনজেশন হয়েছে। ssthresh (slow-start threshold) হলো সেই
cwnd-এর মান, যেখানে পৌঁছালে সেন্ডার এক্সপোনেনশিয়াল বৃদ্ধি (স্লো স্টার্ট) বন্ধ করে
সতর্ক, লিনিয়ার বৃদ্ধির (AIMD) দিকে চলে যায়।
৩ · স্লো স্টার্ট — এক্সপোনেনশিয়াল বৃদ্ধি
নামে "স্লো" হলেও, স্লো স্টার্ট আসলে দ্রুততম বৃদ্ধির ধাপ — এটি "স্লো" নামে পরিচিত কারণ এটি cwnd=1 থেকে শুরু করে (আগের সরলীকৃত অ্যালগরিদমের তুলনায় সতর্কভাবে), কিন্তু প্রতিটি সফল RTT-তে cwnd দ্বিগুণ করে —
১ → ২ → ৪ → ৮ → ১৬ → ৩২ → ...
এই এক্সপোনেনশিয়াল বৃদ্ধি চলতে থাকে যতক্ষণ না cwnd ssthresh-এ পৌঁছায়
(এরপর AIMD শুরু হয়) অথবা একটি প্যাকেট লস ঘটে (তখনই তাৎক্ষণিকভাবে মাল্টিপ্লিকেটিভ
ডিক্রিজ ঘটে, নিচে দেখুন)। এত দ্রুত বৃদ্ধির কারণ — একটি নতুন কানেকশনের জন্য নেটওয়ার্কের
প্রকৃত ক্যাপাসিটি খুঁজে বের করতে বেশি সময় নষ্ট না করা।
৪ · AIMD — Additive Increase, Multiplicative Decrease
একবার cwnd ssthresh-এ পৌঁছালে, সেন্ডার কনজেশন এভয়ডেন্স
ধাপে ঢোকে, যেখানে AIMD নিয়ম প্রযোজ্য হয় —
- Additive Increase — প্রতি RTT-তে cwnd মাত্র +১ সেগমেন্ট বাড়ে (সতর্ক, লিনিয়ার বৃদ্ধি — আরও ব্যান্ডউইথ আছে কি না তা ধীরে ধীরে "প্রোব" করা)।
- Multiplicative Decrease — একটি লস শনাক্ত হলে, cwnd তাৎক্ষণিকভাবে অর্ধেক করে দেওয়া হয় (আক্রমণাত্মক ব্যাকঅফ — কনজেশন আরও খারাপ হওয়ার আগেই দ্রুত সরে আসা)।
বৃদ্ধি ধীর কিন্তু হ্রাস আকস্মিক — এই ইচ্ছাকৃত অসামঞ্জস্যতাই cwnd-কে একটি "করাত-দাঁত" (sawtooth) প্যাটার্নে চালায়: ধীরে ধীরে উপরে ওঠা, লসে হঠাৎ নিচে পড়া, আবার ধীরে ধীরে ওঠা। এই আচরণ ইচ্ছাকৃতভাবে ডিজাইন করা — যখন অনেকগুলো TCP ফ্লো একই বটলনেক লিংক শেয়ার করে, তখন এই নিয়ম সবাইকে মোটামুটি ন্যায্য অংশ পেতে সাহায্য করে।
# TCP কনজেশন কন্ট্রোলের সিমুলেশন — স্লো স্টার্ট + AIMD + মাল্টিপ্লিকেটিভ ডিক্রিজ
cwnd = 1 # শুরুতে ১ সেগমেন্ট
ssthresh = 16 # স্লো স্টার্ট থামার থ্রেশহোল্ড
loss_at_rtt = 9 # এই RTT-তে একটি প্যাকেট লস সিমুলেট করা হবে
total_rtts = 12
phase = "স্লো স্টার্ট"
history = [(0, cwnd, phase)]
for rtt in range(1, total_rtts + 1):
if rtt == loss_at_rtt:
cwnd = cwnd // 2 # মাল্টিপ্লিকেটিভ ডিক্রিজ — তাৎক্ষণিক অর্ধেক
ssthresh = cwnd # নতুন ssthresh = লসের সময়ের cwnd-এর অর্ধেক
phase = "AIMD (লসের পর)"
elif phase == "স্লো স্টার্ট":
cwnd = cwnd * 2 # এক্সপোনেনশিয়াল বৃদ্ধি — প্রতি RTT-তে দ্বিগুণ
if cwnd >= ssthresh:
phase = "AIMD (কনজেশন এভয়ডেন্স)"
else:
cwnd = cwnd + 1 # অ্যাডিটিভ ইনক্রিজ — প্রতি RTT-তে +১
history.append((rtt, cwnd, phase))
print(f"{'RTT':>4} | {'cwnd':>5} | ফেজ")
print("-" * 36)
for rtt, c, p in history:
print(f"{rtt:>4} | {c:>5} | {p}")
print("\nলসের ঠিক আগে cwnd:", history[loss_at_rtt - 1][1])
print("লসের ঠিক পরে cwnd (অর্ধেক):", history[loss_at_rtt][1])
assert history[loss_at_rtt][1] == history[loss_at_rtt - 1][1] // 2
print("মাল্টিপ্লিকেটিভ ডিক্রিজ ঠিক অর্ধেক করেছে?", True)
কনজেশন কন্ট্রোল সেন্ডারকে নেটওয়ার্কের প্রকৃত ক্ষমতা ক্রমাগত "প্রোব" করতে দেয় — দ্রুত এক্সপোনেনশিয়ালি শুরু করে (স্লো স্টার্ট), তারপর সতর্কভাবে লিনিয়ারি বাড়ায় (AIMD-এর additive increase), আর কোনো সংকেত পেলে দ্রুত পিছিয়ে আসে (multiplicative decrease) — এই সাধারণ নিয়মই লক্ষ লক্ষ TCP কানেকশনকে একসাথে শেয়ার্ড নেটওয়ার্কে মোটামুটি ন্যায্যভাবে সহাবস্থান করতে দেয়।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ প্যাকেট লসকে কনজেশনের সংকেত হিসেবে ধরার এই কৌশলটি কেন যুক্তিসঙ্গত, যদিও লস অন্য কারণেও (যেমন বিট-এরর) হতে পারে?
বেশিরভাগ আধুনিক ওয়্যারড নেটওয়ার্কে (ফাইবার/কপার) বিট-এরর অত্যন্ত বিরল, আর রাউটারের বাফার ওভারফ্লো হলে প্যাকেট ড্রপ হওয়াই সবচেয়ে সাধারণ কারণ — তাই পরিসংখ্যানগতভাবে "লস = কনজেশন" একটি ভালো অনুমান। এই অনুমান ওয়্যারলেস নেটওয়ার্কে (M8) কম নির্ভুল, যেখানে সিগন্যাল-সংক্রান্ত লসও সাধারণ — এটিই আধুনিক TCP ভ্যারিয়েন্টগুলো (যেমন BBR) কেন লস ছাড়াও লেটেন্সির মতো অন্য সংকেত ব্যবহার করে তার একটি কারণ।
প্র ০২ স্লো স্টার্টের নাম "স্লো" হলেও এটি আসলে সবচেয়ে দ্রুত বৃদ্ধির ধাপ কেন?
নামটি ঐতিহাসিক প্রেক্ষাপট থেকে এসেছে — স্লো স্টার্টের আগের অ্যালগরিদমগুলো নতুন কানেকশনকে সরাসরি রিসিভার-উইন্ডো সমান cwnd দিয়ে শুরু করাতো, যা প্রায়ই তাৎক্ষণিক কনজেশন কলাপ্স ঘটাতো। cwnd=1 থেকে শুরু করাটা তুলনামূলকভাবে "স্লো" (ধীর) সূচনা — কিন্তু একবার শুরু হলে, প্রতি RTT-তে দ্বিগুণ হওয়া গাণিতিকভাবে এক্সপোনেনশিয়াল, তাই অল্প কয়েকটি RTT-তেই cwnd যথেষ্ট বড় হয়ে যায়।
প্র ০৩ AIMD-তে বৃদ্ধি ধীর (+১ প্রতি RTT) কিন্তু হ্রাস তাৎক্ষণিক (অর্ধেক) — এই অসামঞ্জস্যতার নকশাগত যুক্তি কী?
এটি একটি ইচ্ছাকৃত নিরাপত্তা মার্জিন — নেটওয়ার্ক ক্যাপাসিটি খুঁজে বের করা নিরাপদ এবং ধীরে করা উচিত (ভুল করে বেশি বাড়িয়ে ফেললে কনজেশন আরও খারাপ হতে পারে), কিন্তু একবার কনজেশনের সংকেত (লস) পেলে দ্রুত ও জোরালোভাবে পিছিয়ে আসা উচিত, যাতে নেটওয়ার্ক দ্রুত স্বাভাবিক অবস্থায় ফিরতে পারে। গাণিতিকভাবে প্রমাণিত যে এই "Additive Increase, Multiplicative Decrease" নিয়মই একাধিক ফ্লো শেয়ার্ড বটলনেকে মোটামুটি ন্যায্য (fair) ব্যান্ডউইথ বণ্টনে একত্রিত হয় (converge করে)।
অনুশীলন
-
চিন্তা করুন: উপরের কোড সেলে
ssthresh-এর মান ৮ করলে সিকোয়েন্স কীভাবে বদলাবে?স্লো স্টার্ট আরও আগে থামবে — cwnd ১→২→৪→৮ (RTT ৩-তেই ৮ = ssthresh-এ পৌঁছাবে, আগের মতো RTT ৪ পর্যন্ত অপেক্ষা করতে হবে না), এরপর তাড়াতাড়ি AIMD-এর লিনিয়ার বৃদ্ধিতে চলে যাবে। এটি দেখায় ssthresh সরাসরি নিয়ন্ত্রণ করে স্লো স্টার্ট কতক্ষণ চলবে।
-
পরীক্ষা করুন:
loss_at_rtt-এর মান বদলে অন্য একটি RTT (যেমন ৬ বা ১১) বসিয়ে রান করুন — লসটি স্লো স্টার্ট চলাকালীন হলে কী ঘটে তা লক্ষ করুন।যদি লসের RTT স্লো স্টার্ট চলাকালীন পড়ে (cwnd তখনও ssthresh-এর নিচে), তাহলেও কোডটি সঠিকভাবে সেই মুহূর্তের cwnd-কে অর্ধেক করে দেবে ও সেখান থেকে AIMD শুরু করবে — কারণ
if rtt == loss_at_rttচেকটি ফেজ নির্বিশেষে সবার আগে পরীক্ষা করা হয়। এটি দেখায় লস যেকোনো ফেজেই ঘটতে পারে, শুধু AIMD-এ নয়।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ পরবর্তী পাঠ থেকে M6 — অ্যাপ্লিকেশন লেয়ার প্রোটোকল শুরু হবে।
- Cloud Computing & DevOps কোর্স সঙ্গী কোর্স লোড ব্যালেন্সার ও অটো-স্কেলিং কীভাবে ব্যবহারিক ট্রাফিক ব্যবস্থাপনায় ব্যবহৃত হয় তা শিখতে দেখুন।
- Cybersecurity & Ethical Hacking কোর্স সঙ্গী কোর্স SYN ফ্লাড ও DoS আক্রমণ কীভাবে TCP-র কানেকশন-স্টেট ব্যবস্থাকে টার্গেট করে তা শিখতে দেখুন।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps ও Computer Networks — সব এক জায়গায়।