স্কেলে লাইভ ডেলিভারি
সবাই একই সেকেন্ডে একই নতুন সেগমেন্ট চায়, আর প্লেলিস্ট প্রতি কয়েক সেকেন্ডে বদলায় — এই দুই কারণে লাইভ ভিডিও CDN-এর জন্য VOD-এর চেয়ে অনেক কঠিন। TTL, request collapsing, negative caching, ফ্ল্যাশ ক্রাউড, মাল্টি-CDN আর ইগ্রেসের হিসাব।
গল্পে বুঝি
ঈদের সকালে জাতীয় ঈদগাহ। সামনে মিম্বরের পাশে ইমাম রাজি, তাঁর সামনে একটা মাইক। মুসল্লিরা ময়দান ছাড়িয়ে হাইকোর্টের মোড়, প্রেসক্লাবের সামনের রাস্তা পর্যন্ত কাতার বেঁধে দাঁড়িয়েছেন। এত দূরে কেউ ইমামের গলা সরাসরি শুনবেন, সে উপায় নেই। তাই সাউন্ড সিস্টেমের দায়িত্বে থাকা কিন্দি একটা শিকল বানিয়েছেন: মাইক থেকে সিগন্যাল যায় ময়দানের মাঝখানের একটা বড় অ্যাম্প্লিফায়ারে, সেখান থেকে ময়দানের চার কোনার চারটা স্পিকার টাওয়ারে, আর প্রতিটা টাওয়ার থেকে রাস্তার খুঁটিতে খুঁটিতে ঝোলানো ছোট ছোট হর্নে। ইমাম “আল্লাহু আকবার” বলার সাথে সাথে লাখো মানুষ একই মুহূর্তে একই শব্দটা শুনতে চান, কারণ সবাই একসাথে রুকুতে যাবেন।
কিন্দির শিকলের বুদ্ধিটা হলো, ইমামকে লাখো মানুষের সামনে আলাদা আলাদা করে বলতে হয় না। তিনি একবার বলেন, মাঝের অ্যাম্প্লিফায়ার একবার নেয়, চার টাওয়ার সেখান থেকে একবার করে নেয়, আর রাস্তার প্রতিটা হর্ন তার কাছের টাওয়ার থেকে নেয়। প্রতিটা স্তর উপরের স্তর থেকে একবারই শব্দটা টানে, তারপর নিচের সবাইকে ভাগ করে দেয়। গতবার একটা গোলমাল হয়েছিল: প্রেসক্লাবের দিকের একটা হর্নের তার আলগা ছিল, নামাজের আগে পরীক্ষার সময় সেটা চুপ ছিল, আর একজন স্বেচ্ছাসেবক খাতায় লিখে রেখেছিলেন “এই হর্ন নষ্ট”। তারপর তার ঠিক হয়ে গেলেও কেউ সেই লেখা মোছেনি, ফলে প্রথম রাকাতে ওদিকের মানুষ কিছুই শুনলেন না, কারণ সবাই খাতা দেখে ধরে নিয়েছিল ওখানে শব্দ নেই। এবার কিন্দি নিয়ম করেছেন, “নষ্ট” লেখা খাতায় এক মিনিটের বেশি থাকবে না, বারবার যাচাই হবে।
আরও দুটো জিনিস কিন্দি শিখেছেন। এক, নামাজ শুরুর ঠিক আগের পাঁচ মিনিটে মানুষ সবচেয়ে বেশি আসে, তাই সব হর্ন আর অ্যাম্প্লিফায়ার আধা ঘণ্টা আগে থেকেই চালু রেখে গরম করা থাকে, শুরুর মুহূর্তে কিছু চালু করতে হয় না। দুই, এত বড় জামাতে একটা সাউন্ড কোম্পানির উপর পুরো ভরসা করা যায় না; তাই দুইটা আলাদা কোম্পানির সিস্টেম পাশাপাশি বসানো, একটা বিগড়ালে কিন্দি সুইচ ঘুরিয়ে অন্যটায় চলে যান। আর পেছনের কাতারের মানুষ পাশের জনকে দেখে রুকু-সিজদা করেন, যা সাহায্য করে, কিন্তু সবার উপর নির্ভর করা যায় না।
মিলিয়ে নিই: ইমাম রাজি হলেন origin (packager যেখানে নতুন সেগমেন্ট লেখে), মাঝের অ্যাম্প্লিফায়ার হলো origin shield, চার কোনার টাওয়ার আর রাস্তার হর্নগুলো হলো edge PoP। সবাই একই মুহূর্তে একই “আল্লাহু আকবার” শুনতে চাওয়া হলো লাইভের সমকালীন চাহিদা: সব দর্শক একই সেকেন্ডে একই নতুন সেগমেন্ট চায়। প্রতিটা স্তর উপর থেকে একবারই টানা হলো request collapsing, আর খাতায় লেখা “এই হর্ন নষ্ট” যেটা কেউ মোছেনি, সেটা হলো ক্যাশ করা 404 (negative caching)। আধা ঘণ্টা আগে থেকে সব চালু রাখা হলো ফ্ল্যাশ ক্রাউডের আগে pre-scaling ও pre-warming, দুই সাউন্ড কোম্পানি হলো মাল্টি-CDN, আর পাশের জনকে দেখে নামাজ পড়া হলো P2P ডেলিভারি। বাস্তবে বড় ক্রিকেট ম্যাচ, ঈদের জামাতের লাইভ, বা নির্বাচনের ফল সম্প্রচারের দিন ঠিক এই নকশাই লাখো দর্শককে একসাথে সামলায়।
লাইভ ডেলিভারি VOD থেকে কোথায় আলাদা
CDN-এর সাধারণ কাজ (cache key, shield, hit ratio, signed URL) ভিডিও ট্র্যাকের ডেলিভারি ও CDN চ্যাপ্টার আর পুরো CDN ট্র্যাক-এ আছে। এখানে শুধু লাইভের তিনটা বৈশিষ্ট্য, যেগুলো VOD-এর নিয়ম ভেঙে দেয়:
- চাহিদা একই মুহূর্তে জমাট বাঁধে। VOD-এ দশ হাজার দর্শক একটা সিনেমার দশ হাজার আলাদা জায়গায় থাকে। লাইভে দশ হাজার দর্শকই লাইভ এজের কাছাকাছি, তাই নতুন সেগমেন্টটা প্রকাশ হওয়ার পর প্রথম এক-দুই সেকেন্ডে প্রায় সবাই সেটাই চায়। প্রতিটা নতুন সেগমেন্ট জন্মের মুহূর্তে একটা ছোট thundering herd।
- প্লেলিস্ট কখনো স্থির থাকে না। VOD-এর প্লেলিস্ট একবার লেখা হয়, তারপর চিরকাল একই। লাইভের media playlist প্রতি সেগমেন্টে একবার বদলায়। তাকে বেশিক্ষণ ক্যাশ করলে দর্শক পিছিয়ে পড়ে, একদম না করলে origin পুড়ে যায়।
- কনটেন্টের আয়ু ছোট। একটা লাইভ সেগমেন্ট দশ মিনিট পরে প্রায় কেউ চায় না (DVR বাদে)। তাই “লম্বা TTL, বিশাল ক্যাশ” ভাবনার চেয়ে “ঠিক এই মুহূর্তের জিনিস দ্রুত ছড়ানো” বেশি জরুরি।
দুই ধরনের অবজেক্ট, দুই রকম TTL
লাইভ স্ট্রিমে CDN আসলে দুই রকম জিনিস বহন করে, আর দুটোর ক্যাশিং নিয়ম সম্পূর্ণ উল্টো।
| অবজেক্ট | বদলায়? | সঠিক TTL (মোটামুটি) | কেন |
|---|---|---|---|
| Multivariant (master) playlist | প্রায় কখনো না | কয়েক মিনিট | rendition-এর তালিকা ইভেন্টের মাঝে সাধারণত বদলায় না |
| Media playlist (লাইভ) | প্রতি সেগমেন্টে | টার্গেট ডিউরেশনের অর্ধেক বা কম | বেশি রাখলে দর্শক পিছিয়ে পড়ে |
| Media segment | কখনো না (নাম অনন্য হলে) | লম্বা, immutable | একবার লেখা সেগমেন্ট আর বদলায় না |
| Init segment | কখনো না | লম্বা | কোডেক কনফিগ, প্রতিটা rendition-এ একটা |
| LL-HLS partial / blocking reload | প্রতি পার্টে | খুব ছোট, origin ধরে রাখে | লো লেটেন্সি চ্যাপ্টার দেখুন |
| না-থাকা সেগমেন্টের 404 | পরের সেকেন্ডেই বদলাতে পারে | ১ সেকেন্ড বা ক্যাশ নয় | নিচে “negative caching-এর ফাঁদ” দেখুন |
Media playlist-এর TTL কেন “অর্ধেক টার্গেট ডিউরেশন”
এই সংখ্যাটা প্রোটোকলের নিয়ম থেকেই আসে। HLS স্পেকের দ্বিতীয় সংস্করণের খসড়া (draft-pantos-hls-rfc8216bis, ২০২৬ সালের অক্টোবর অনুযায়ী সর্বশেষ সংস্করণ -22) বলে: প্লেলিস্ট বদলালে ক্লায়েন্ট অন্তত শেষ সেগমেন্টের ডিউরেশন অপেক্ষা করে আবার রিলোড করে, আর রিলোডে যদি কিছু না বদলায়, তাহলে টার্গেট ডিউরেশনের অর্ধেক অপেক্ষা করে আবার চেষ্টা করে। সার্ভারের দিকে নিয়ম হলো আগের আপডেটের পর দেড় গুণ টার্গেট ডিউরেশনের মধ্যে প্লেলিস্ট আপডেট করতেই হবে।
এখন ধরুন সেগমেন্ট ৬ সেকেন্ডের, আর edge প্লেলিস্টটা ৬ সেকেন্ড ক্যাশ করে রাখে। খারাপ সময়ে একজন প্লেয়ার এমন একটা কপি পায় যেটা প্রায় ৬ সেকেন্ড পুরনো। সে “কিছু বদলায়নি” ভেবে আরও ৩ সেকেন্ড অপেক্ষা করে, আবার সেই পুরনো কপিই পেতে পারে। ফলাফল: দর্শক প্রতি কয়েক রিলোডে একটা সেগমেন্ট পিছিয়ে পড়ে, লেটেন্সি বাড়ে, আর খুব খারাপ ক্ষেত্রে প্লেয়ার নতুন সেগমেন্ট না পেয়ে বাফার শেষ করে আটকে যায়। TTL অর্ধেক টার্গেট ডিউরেশন বা তার কম রাখলে সবচেয়ে খারাপ বিলম্বও প্লেয়ারের নিজের রিট্রাই ছন্দের ভেতরে থাকে।
Apple-এর নিজের একটা পরীক্ষা আছে। HLS Authoring Specification for Apple Devices (২০২৬ সালের অক্টোবরে দেখা) বলে, লাইভ প্লেলিস্টের আপডেটকে অবৈধ ধরা উচিত যদি Last-Modified হেডার Date হেডার থেকে তিন টার্গেট ডিউরেশনের বেশি পুরনো হয়। অর্থাৎ CDN যদি একটা পুরনো প্লেলিস্ট আঁকড়ে ধরে থাকে, Apple ডিভাইস সেটাকে প্রত্যাখ্যান করতে পারে। একই স্পেক প্লেলিস্টে gzip বাধ্যতামূলক করে। নিজের টার্গেট ডিভাইসের জন্য সর্বশেষ সংস্করণটা মিলিয়ে নিন।
Origin হেডার দিয়ে TTL ঠিক করুন, CDN কনসোলে নয়
TTL-এর আসল মালিক হওয়া উচিত origin, কারণ সে-ই জানে কোন ফাইল কী। একটা ভালো লাইভ origin এক্সটেনশন দেখে হেডার দেয়:
# illustrative: what a healthy live origin returns
$ curl -sD - -o /dev/null https://live.baytalhikma.org/eid/720p/index.m3u8
HTTP/2 200
content-type: application/vnd.apple.mpegurl
content-encoding: gzip
cache-control: public, max-age=2
last-modified: Sun, 25 Oct 2026 01:30:14 GMT
age: 1
x-cache-status: HIT
$ curl -sD - -o /dev/null https://live.baytalhikma.org/eid/720p/seg_184213.m4s
HTTP/2 200
content-type: video/iso.segment
cache-control: public, max-age=86400, immutable
age: 4
x-cache-status: HIT immutable দেওয়ার আগে নিশ্চিত হোন সেগমেন্টের নাম কখনো আবার ব্যবহার হয় না। কিছু পুরনো packager বা কনফিগ সেগমেন্টের নম্বর একটা চক্রে ঘোরায় (যেমন শুধু শেষ ১০টা ফাইল রেখে নাম ফিরিয়ে আনে), কিছু আবার এনকোডার রিস্টার্টে নম্বর শূন্য থেকে শুরু করে। তখন seg_5.m4s নামটা আধা ঘণ্টা আগের কনটেন্ট নিয়ে CDN-এ বসে থাকে, আর নতুন seg_5.m4s কেউ দেখে না। সমাধান: নম্বর হোক ওয়াল-ক্লক বা স্ট্রিমের শুরুর সময় থেকে নির্ধারিত (একঘেয়েভাবে বাড়ে, কখনো ফেরে না), আর প্রতিটা ইভেন্টের পাথে একটা অনন্য আইডি থাকুক।
stale-while-revalidate: প্লেলিস্টে সাবধান
পার্জ ও ইনভ্যালিডেশন চ্যাপ্টারে stale-while-revalidate-কে বন্ধু হিসেবে দেখেছি। লাইভ প্লেলিস্টে এটা দুই ধার-ওয়ালা ছুরি। এর মানে, TTL শেষ হলেও edge পুরনো কপিটাই দিতে থাকবে যতক্ষণ পেছনে নতুনটা আসছে। প্লেলিস্টে “পুরনো” মানেই দর্শক পিছিয়ে পড়া। নিয়মটা হলো:
- স্টেল থাকার সময় সীমিত রাখুন।
stale-while-revalidate=2গ্রহণযোগ্য,=60নয়। মূলত আপনি শুধু origin-এর ফেচের সময়টুকু ঢাকতে চান। - nginx-এ
updatingস্টেলনেসকে নিজেই সীমিত রাখে।proxy_cache_use_stale updatingমানে “কেউ নতুন কপি আনছে, ততক্ষণ পুরনোটা দাও”। ফেচ শেষ হলেই নতুন কপি, তাই স্টেলনেস ফেচের সময়ের সমান। এটা প্লেলিস্টের জন্য ঠিক আছে। stale-if-errorছোট মাত্রায় কাজের। origin কয়েক সেকেন্ডের জন্য হোঁচট খেলে পুরনো প্লেলিস্ট দিলে প্লেয়ার অন্তত বাফার থেকে চলতে থাকে। কিন্তু origin মিনিটখানেক মারা থাকলে চিরকাল পুরনো প্লেলিস্ট দেওয়ার চেয়ে এরর দেওয়াই ভালো, যাতে প্লেয়ার অন্য পাথে (ব্যাকআপ স্ট্রিম বা অন্য CDN) চলে যায়। রিলায়েবিলিটি চ্যাপ্টার দেখুন।
Request collapsing: লাইভে এটা ঐচ্ছিক নয়
একটা হিসাব করি (সংখ্যাগুলো উদাহরণমাত্র)। একটা edge-এ ২০,০০০ দর্শক, পাঁচটা rendition, সেগমেন্ট ৪ সেকেন্ডের। নতুন সেগমেন্ট seg_184214 প্রকাশ হলো। পরের এক সেকেন্ডে ওই edge-এ মোটামুটি কয়েক হাজার রিকোয়েস্ট আসে একই পাঁচটা ফাইলের জন্য। ক্যাশে তখনো নেই, কারণ ফাইলটা এইমাত্র জন্মেছে।
Collapsing ছাড়া: প্রতিটা MISS আলাদা করে shield বা origin-এ যায়। কয়েক হাজার রিকোয়েস্ট একই ফাইলের জন্য, প্রতি edge থেকে, প্রতি ৪ সেকেন্ডে। এটা origin-এর উপর একটা নিয়মিত DDoS।
Collapsing সহ: প্রথম রিকোয়েস্টটা উপরে যায়, বাকিরা অপেক্ষা করে, উত্তর এলে সবাই একই কপি পায়। প্রতি edge থেকে প্রতি ফাইলে ঠিক একটা রিকোয়েস্ট। আর shield-ও একই কাজ করলে origin প্রতি ফাইলে প্রতি shield থেকে মাত্র একটা রিকোয়েস্ট দেখে।
# origin load per new segment (illustrative arithmetic)
renditions = 5
edges = 40
shields = 2
viewers asking per edge = ~2,000 in the first second
no collapsing, no shield : 40 edges x 2,000 x 5 = 400,000 origin requests
collapsing at edge only : 40 edges x 1 x 5 = 200 origin requests
collapsing + shield : 2 shields x 1 x 5 = 10 origin requests বেশিরভাগ বাণিজ্যিক CDN এটা নিজে থেকে করে (নাম ভিন্ন: request coalescing, collapsed forwarding)। তবু নিজের ভেন্ডরের ডকসে নিশ্চিত হোন যে এটা লাইভ পাথে চালু আছে, আর shield স্তরেও করে। নিজে nginx চালালে এটা proxy_cache_lock, যেটা ডিফল্টে বন্ধ।
proxy_cache_lock_timeout-এর একটা সূক্ষ্মতা। nginx ডকস (২০২৬ সালের অক্টোবরে nginx.org) অনুযায়ী লক ডিফল্টে ৫ সেকেন্ড ধরে থাকে। ৫ সেকেন্ড পেরোলে অপেক্ষমাণ রিকোয়েস্ট origin-এ যায় ঠিকই, কিন্তু সেই রেসপন্স ক্যাশ হয় না। ২ সেকেন্ডের সেগমেন্টে origin ধীর হলে লক টাইমআউট মানে সবাই একসাথে origin-এ ছুটবে, যা ঠিক উল্টো ফল। টাইমআউট এমন রাখুন যাতে একটা স্বাভাবিক ধীর ফেচ তার ভেতরে শেষ হয়, আর origin-কে এত ধীর হতে দেবেন না।
Negative caching-এর ফাঁদ: যে 404 পুরো স্ট্রিম মেরে ফেলে
এটা লাইভ ডেলিভারির সবচেয়ে বিশ্বাসঘাতক বাগ, কারণ এটা ঘটে মাত্র এক সেকেন্ডের ভুলে আর ফল থাকে এক মিনিট।
কী ঘটে: একজন প্লেয়ার একটু আগেভাগে seg_184215 চায়, হয়তো তার ঘড়ি একটু এগিয়ে, হয়তো সে প্লেলিস্ট থেকে পরের নাম আন্দাজ করছে, হয়তো packager প্লেলিস্টে নামটা লিখেছে ফাইলটা পুরো লেখার আগেই। origin বলে 404। edge সেই 404 টা ক্যাশ করে ফেলে, CDN-এর ডিফল্ট negative TTL অনুযায়ী (অনেক জায়গায় দশ সেকেন্ড থেকে কয়েক মিনিট; নিজের ভেন্ডরে দেখুন)। এক সেকেন্ড পরে ফাইলটা origin-এ এসে যায়, কিন্তু ওই edge-এর সব দর্শক পরের এক মিনিট seg_184215-এর জন্য 404 পায়। তাদের প্লেয়ার সেগমেন্টটা বাদ দেয়, বা আটকে যায়, বা এরর দেখায়। আর আপনার ড্যাশবোর্ডে origin সুস্থ দেখায়, কারণ origin-এর কাছে ওই রিকোয়েস্ট আর যাচ্ছেই না।
সমাধান তিন স্তরে:
- Origin-এ: না-থাকা লাইভ সেগমেন্টের 404-এ
Cache-Control: no-storeবাmax-age=1দিন। origin-ই জানে এটা “এখনো নেই” নাকি “কখনো ছিল না”। - Edge-এ: 404-এর TTL ১ সেকেন্ড বা শূন্য করুন লাইভ পাথে। nginx-এ
proxy_cache_valid 404 1s;। - Packager-এ: প্লেলিস্টে নাম তখনই লিখুন যখন ফাইল পুরো লেখা হয়ে গেছে। আগে টেম্প নামে লিখে তারপর atomic rename, তারপর প্লেলিস্ট আপডেট। এতে “প্লেলিস্টে আছে কিন্তু ফাইল নেই” অবস্থাটাই আর তৈরি হয় না।
# confirm whether an edge is holding a stale 404 (illustrative)
$ curl -sD - -o /dev/null https://live.baytalhikma.org/eid/720p/seg_184215.m4s
HTTP/2 404
cache-control: max-age=60 # bad: origin or CDN default let this live 60s
age: 37 # served from cache for 37s already
x-cache-status: HIT # a cached 404, origin never asked again
$ curl -sD - -o /dev/null --connect-to ::origin.baytalhikma.org:443 \
https://live.baytalhikma.org/eid/720p/seg_184215.m4s
HTTP/2 200 # the file exists at origin right now একটা লাইভ origin আর edge-এর nginx কনফিগ
নিচের কনফিগ একটা সাধারণ নকশা দেখায়: packager সেগমেন্ট লেখে একটা tmpfs-এ (মেমরিতে, ডিস্কের ধীরতা নেই), origin সেগুলো এক্সটেনশন অনুযায়ী হেডার দিয়ে দেয়, আর edge nginx ক্যাশ করে collapsing আর ছোট negative TTL সহ। নিজের CDN কীভাবে কয়েকটা VPS দিয়ে বানাবেন, তার পূর্ণ আলোচনা নিজের CDN বানানো চ্যাপ্টারে।
# ---------- origin: serves what the packager writes ----------
server {
listen 443 ssl;
server_name origin.baytalhikma.org;
root /dev/shm/live; # packager writes here (tmpfs)
gzip on;
gzip_types application/vnd.apple.mpegurl application/dash+xml;
location ~ \.m3u8$ {
types { application/vnd.apple.mpegurl m3u8; }
add_header Cache-Control "public, max-age=2" always;
}
location ~ \.(m4s|mp4|ts)$ {
add_header Cache-Control "public, max-age=86400, immutable" always;
}
# a segment that does not exist yet must not be cached downstream
error_page 404 = @missing;
location @missing {
add_header Cache-Control "no-store" always;
return 404;
}
} # ---------- edge: caches, collapses, keeps 404s short ----------
proxy_cache_path /var/cache/live levels=1:2 keys_zone=live:100m
max_size=20g inactive=10m use_temp_path=off;
server {
listen 443 ssl;
server_name live.baytalhikma.org;
proxy_cache live;
proxy_cache_key $scheme$host$uri; # query noise must not split the cache
proxy_cache_lock on;
proxy_cache_lock_timeout 3s;
proxy_cache_valid 404 1s; # fallback if origin forgets its header
add_header X-Cache-Status $upstream_cache_status always;
location ~ \.m3u8$ {
proxy_pass https://origin.baytalhikma.org;
proxy_cache_valid 200 1s;
proxy_cache_use_stale updating error timeout;
proxy_cache_background_update on;
}
location ~ \.(m4s|mp4|ts)$ {
proxy_pass https://origin.baytalhikma.org;
proxy_cache_valid 200 10m;
}
} nginx ডকস অনুযায়ী upstream রেসপন্সের Cache-Control/Expires/X-Accel-Expires হেডার proxy_cache_valid-এর চেয়ে বেশি অগ্রাধিকার পায়। তাই উপরের edge-এ proxy_cache_valid আসলে নিরাপত্তা জাল: origin ঠিক হেডার দিলে সেটাই চলে, ভুলে গেলে এই মানগুলো। আর Set-Cookie থাকা রেসপন্স nginx একেবারেই ক্যাশ করে না, তাই লাইভ পাথে origin যেন কখনো কুকি না বসায়।
Origin shield: লাইভে কেন আরও জরুরি
VOD-এ shield-এর লাভ হলো long tail-এর জিনিস একবার এনে সব edge-কে দেওয়া। লাইভে লাভটা আরও সরাসরি: প্রতিটা নতুন সেগমেন্টে প্রতিটা edge একবার করে উপরে যাবেই। চল্লিশটা edge মানে প্রতি সেগমেন্টে প্রতি rendition-এ চল্লিশটা origin রিকোয়েস্ট, যা origin-এর জন্য ছোট মনে হলেও তিনটা জিনিস খারাপ করে: origin-এর ইগ্রেস (চল্লিশ গুণ), origin-এর কাছে লেটেন্সির ঝুঁকি (চল্লিশটা দূরের edge একসাথে), আর origin হোঁচট খেলে চল্লিশটা জায়গায় একসাথে MISS।
লাইভের জন্য shield বসানোর নিয়ম:
- Shield থাকুক origin-এর কাছে, নেটওয়ার্কের হিসেবে। লক্ষ্য origin-কে রক্ষা করা আর প্রথম কপিটা দ্রুত আনা।
- Shield-এও collapsing আর ছোট 404 TTL চালু থাকুক। নইলে negative caching-এর ফাঁদ এক স্তর উপরে উঠে আসে, আর তখন সব edge একসাথে 404 পায়।
- একাধিক shield হলে প্রতিটা edge একটা নির্দিষ্ট shield-এ যাক। ঘুরে ঘুরে গেলে collapsing-এর লাভ ভাগ হয়ে যায়।
ফ্ল্যাশ ক্রাউড: খেলা শুরুর পাঁচ মিনিট
লাইভের দর্শকসংখ্যা একটা সমান রেখা নয়। একটা বড় ম্যাচ বা ঈদের জামাতের লাইভে বেশিরভাগ মানুষ আসে ঠিক শুরুর আগের কয়েক মিনিটে, আর একটা উইকেট পড়লে বা একটা গোল হলে মুহূর্তে আরেক ঢেউ। এই ঢেউ CDN-এর জন্য যতটা না সমস্যা, তার চেয়ে বেশি সমস্যা আপনার নিজের অংশগুলোর জন্য: অথ বা টোকেন সার্ভিস, প্লেব্যাক API, অ্যানালিটিক্স বিকন, আর origin।
আগে থেকে যা করবেন:
- CDN ভেন্ডরকে আগে জানান। বড় ইভেন্টে বেশিরভাগ ভেন্ডর আগাম নোটিশ চায় বা ভালোবাসে, যাতে তারা নিজেদের দিক থেকে ক্যাপাসিটি দেখে। কত আগে, কোন ফর্মে, সেটা নিজের চুক্তি আর ভেন্ডরের ডকসে দেখুন।
- স্ট্রিম আগে থেকে চালু রাখুন। শুরুর ৩০ মিনিট আগে থেকে একটা স্লেট বা প্রি-শো চালান। এতে এনকোডার, packager, origin, shield আর edge সবার ক্যাশ গরম থাকে, প্লেয়ারগুলো আগেই কানেক্ট হয়ে থাকে, আর আসল শুরুর মুহূর্তে কিছু “চালু” করতে হয় না।
- আপনার নিজের API আগে থেকে স্কেল করুন। অটোস্কেলিং ঢেউয়ের সময় সাধারণত দেরিতে প্রতিক্রিয়া দেয়। প্লেব্যাক টোকেন ইস্যু করে এমন সার্ভিস প্রত্যাশিত পিকের জন্য আগেই বাড়িয়ে রাখুন।
- রিট্রাইতে jitter দিন। একটা ছোট গোলমালে সব প্লেয়ার যদি ঠিক ২ সেকেন্ড পরপর রিট্রাই করে, প্রতি ২ সেকেন্ডে একটা কৃত্রিম ঢেউ তৈরি হয়। প্লেয়ারের রিট্রাই কনফিগে এক্সপোনেনশিয়াল ব্যাকঅফ আর র্যান্ডম jitter রাখুন।
- লোড টেস্ট শুধু origin-এ নয়, পুরো পাথে। ইভেন্টের আগে প্রত্যাশিত দর্শকের একটা ভগ্নাংশ দিয়ে পুরো পাথ (টোকেন API থেকে CDN পর্যন্ত) চালিয়ে দেখুন। CDN-এর মাধ্যমে বড় লোড টেস্টের আগে ভেন্ডরের অনুমতি নিন, নইলে সেটা আক্রমণ মনে হতে পারে।
বড় ইভেন্টে মাল্টি-CDN
মাল্টি-CDN-এর সাধারণ যুক্তি আর DNS-ভিত্তিক স্টিয়ারিং ভিডিও ট্র্যাকের ডেলিভারি চ্যাপ্টারে আছে। লাইভে দুটো জিনিস আলাদা:
দুই CDN একই shield বা origin থেকে টানে, একই নামে। সেগমেন্টের নাম আর কনটেন্ট দুই CDN-এ হুবহু এক হলে প্লেয়ার মাঝপথে এক CDN থেকে আরেকটায় গেলেও টাইমলাইন ভাঙে না। এর জন্য সেগমেন্ট নম্বর হতে হবে নির্ধারিত (ওয়াল-ক্লক থেকে), আর দুই CDN-এর cache key নিয়ম মিলিয়ে রাখতে হবে।
স্ট্রিম চলার মাঝে দর্শক সরানো। DNS-ভিত্তিক স্টিয়ারিং শুধু নতুন কানেকশনকে প্রভাবিত করে, আর DNS ক্যাশের কারণে ধীর। HLS-এর Content Steering এটার জন্যই: multivariant playlist-এ EXT-X-CONTENT-STEERING ট্যাগ একটা স্টিয়ারিং সার্ভারের ঠিকানা দেয়, প্রতিটা variant একটা PATHWAY-ID (যেমন CDN-A, CDN-B) পায়, আর প্লেয়ার নিয়মিত স্টিয়ারিং সার্ভার থেকে একটা ছোট JSON নিয়ে জানে কোন pathway এখন অগ্রাধিকার পাবে। একটা CDN খারাপ করলে স্টিয়ারিং সার্ভারে অগ্রাধিকার বদলালেই চলমান দর্শকরা কয়েক সেকেন্ডের মধ্যে সরে যায়।
# illustrative multivariant playlist with two pathways
#EXTM3U
#EXT-X-CONTENT-STEERING:SERVER-URI="https://steer.baytalhikma.org/eid.json",PATHWAY-ID="CDN-A"
#EXT-X-STREAM-INF:BANDWIDTH=3200000,RESOLUTION=1280x720,PATHWAY-ID="CDN-A",STABLE-VARIANT-ID="720p"
https://a.cdn.baytalhikma.org/eid/720p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3200000,RESOLUTION=1280x720,PATHWAY-ID="CDN-B",STABLE-VARIANT-ID="720p"
https://b.cdn.baytalhikma.org/eid/720p/index.m3u8 ২০২৬ সালের অক্টোবর অনুযায়ী: rfc8216bis খসড়া Content Steering-কে “redundant variant stream-গুলোকে pathway-তে ভাগ করে গতিশীলভাবে অগ্রাধিকার দেওয়ার” উপায় হিসেবে বর্ণনা করে, আর একটা ব্যর্থ pathway-কে মোটামুটি দুই মিনিট শাস্তি দেওয়ার কথা বলে। Apple-এর authoring spec বলে Content Steering ব্যবহার করলে প্লেলিস্টে STABLE-VARIANT-ID আর STABLE-RENDITION-ID দিতেই হবে, আর EXT-X-CONTENT-STEERING-এ PATHWAY-ID থাকা উচিত। প্লেয়ার সাপোর্ট (hls.js, AVPlayer, Shaka) ভার্সন অনুযায়ী আলাদা; চালুর আগে নিজের টার্গেট প্লেয়ারে পরীক্ষা করুন।
P2P ডেলিভারি, সংক্ষেপে
একটা পুরনো ধারণা আবার ফিরে এসেছে: একই স্ট্রিম দেখা দর্শকরা WebRTC ডেটা চ্যানেল দিয়ে নিজেদের মধ্যে সেগমেন্ট ভাগ করে, যাতে CDN-এর ইগ্রেস কমে। বড়, সমকালীন লাইভ ইভেন্ট এর জন্য আদর্শ, কারণ সবাই একই মুহূর্তে একই সেগমেন্ট চায়।
তবে তিনটা খরচ আছে যেগুলো পণ্যের সিদ্ধান্ত, শুধু প্রযুক্তির নয়:
- দর্শকের আপলোড ডেটা খরচ হয়। বাংলাদেশে অনেক দর্শক মিটারড মোবাইল ডেটায় দেখেন। তাদের অজান্তে তাদের ডেটা দিয়ে অন্যকে ভিডিও পাঠানো স্বচ্ছ নয়। চালু করলে স্পষ্ট opt-in রাখুন, আর মোবাইল ডেটায় ডিফল্ট বন্ধ রাখুন।
- দর্শকের IP একে অপরের কাছে প্রকাশ পায়। WebRTC peer কানেকশনের প্রকৃতিই এমন। গোপনীয়তার নীতিতে এটা বলুন।
- জটিলতা বাড়ে। একটা সেগমেন্ট peer থেকে সময়মতো না এলে CDN থেকে আনার ফলব্যাক লাগে, আর সমস্যা ডিবাগ করা কঠিন হয়। ছোট বা মাঝারি ইভেন্টে সাধারণত এটা লাগে না।
একটা বড় লাইভ ইভেন্টের ইগ্রেস হিসাব
দাম ভেন্ডর আর চুক্তি অনুযায়ী এত আলাদা যে এখানে কোনো সংখ্যা দেওয়া অর্থহীন। কিন্তু পরিমাণের হিসাবটা যে কেউ করতে পারেন, আর ভেন্ডরের সাথে কথা বলার আগে করা উচিত।
# illustrative: a two-hour match
peak concurrent viewers = 200,000
average delivered bitrate = 3 Mbps # weighted by which rungs people actually watch
duration = 2 hours = 7,200 s
peak edge throughput = 200,000 x 3 Mbps = 600 Gbps
total edge egress = 600 Gbps x 7,200 s / 8 = 540,000 GB (~540 TB)
origin egress, with 2 shields and 5 renditions (~2.3 Mbps average per rung):
per shield = 5 x 2.3 Mbps x 7,200 s / 8 = ~10 GB
total = ~20 GB # tiny next to edge egress এই হিসাব থেকে তিনটা শিক্ষা আসে। এক, গড় বিটরেট সবচেয়ে বড় নিয়ন্ত্রণযোগ্য সংখ্যা: ladder-এর উপরের rung কতজন পায়, সেটা ABR আর ডিফল্ট কোয়ালিটি নির্ধারণ করে, আর সেটা খরচ সরাসরি গুণ করে। দুই, পিক থ্রুপুট (Gbps) আর মোট পরিমাণ (TB) দুটো আলাদা জিনিস, আর অনেক চুক্তিতে দুটোর হিসাব আলাদা। তিন, ভালো shield আর collapsing থাকলে origin-এর ইগ্রেস প্রায় নগণ্য; origin-এর বিল বড় হলে সেটা collapsing বা shield-এর গোলমালের লক্ষণ।
ডিবাগিং: এই চ্যাপ্টারের সমস্যাগুলো
| লক্ষণ | নিশ্চিত করার উপায় | সমাধান |
|---|---|---|
| দর্শকের লেটেন্সি ধীরে ধীরে বাড়ছে, origin-এর দর্শক ঠিক আছে | edge থেকে প্লেলিস্ট কয়েকবার curl -sD - করে age আর cache-control দেখুন; age টার্গেট ডিউরেশনের কাছাকাছি হলে দোষী | media playlist-এর TTL অর্ধেক টার্গেট ডিউরেশন বা কম; stale-while-revalidate ছোট করুন |
| একটা অঞ্চলের সবাই একই সেগমেন্টে আটকে, তারপর এক মিনিট পর ঠিক | সেই সেগমেন্টের URL edge-এ curl করে দেখুন: 404 সাথে x-cache-status: HIT আর বড় age | origin-এ 404-এ no-store, edge-এ proxy_cache_valid 404 1s, packager-এ atomic rename |
| প্রতি সেগমেন্টে origin-এ CPU বা ইগ্রেসের কাঁটা | origin অ্যাক্সেস লগে একই সেগমেন্টের রিকোয়েস্ট সংখ্যা গুনুন: প্রতি shield একটার বেশি হলে collapsing কাজ করছে না | edge আর shield-এ collapsing চালু; লক টাইমআউট যথেষ্ট রাখুন; cache key থেকে query string বাদ দিন |
| পুরনো কনটেন্ট হঠাৎ লাইভে ফিরে আসছে | একই সেগমেন্ট নাম ভিন্ন সময়ে আসছে কিনা দেখুন; packager-এর নম্বরিং নিয়ম দেখুন | নম্বর ওয়াল-ক্লক বা স্ট্রিম শুরু থেকে একঘেয়ে; ইভেন্ট-প্রতি অনন্য পাথ |
| Apple ডিভাইসে প্লেব্যাক থেমে যায়, অন্যগুলোতে চলে | প্লেলিস্ট রেসপন্সের Last-Modified আর Date তুলনা করুন; তিন টার্গেট ডিউরেশনের বেশি ফারাক হলে কারণ এটাই | প্লেলিস্টের ক্যাশ ছোট করুন; origin-এ ঠিক Last-Modified দিন |
| খেলা শুরুর মুহূর্তে প্লেব্যাক শুরু হয় না, CDN সুস্থ | টোকেন বা প্লেব্যাক API-এর এরর রেট আর লেটেন্সি দেখুন | API আগে থেকে স্কেল করুন; রিট্রাইতে jitter; শুরুর আগে থেকে স্ট্রিম চালু |
| এক CDN-এ সমস্যা, কিন্তু দর্শক সরছে না | প্লেয়ারের নেটওয়ার্ক লগে স্টিয়ারিং JSON আসছে কিনা দেখুন; DNS-ভিত্তিক হলে DNS TTL দেখুন | Content Steering; নয়তো DNS TTL ছোট রাখুন আর প্লেয়ারে বিকল্প pathway দিন |
| origin-এর ইগ্রেস বিল অপ্রত্যাশিত বড় | origin লগে কোন edge বা shield থেকে রিকোয়েস্ট আসছে দেখুন; edge সরাসরি origin-এ যাচ্ছে কিনা | সব edge-কে shield-এর পেছনে রাখুন; origin-কে শুধু shield-এর IP থেকে অনুমতি দিন |
মূল শিক্ষা
- লাইভ মানে প্রতিটা নতুন সেগমেন্টে একটা ছোট thundering herd। সবাই একই সেকেন্ডে একই নতুন ফাইল চায়, তাই request collapsing আর shield ঐচ্ছিক নয়।
- দুই রকম অবজেক্ট, দুই রকম TTL। media playlist অর্ধেক টার্গেট ডিউরেশন বা কম, সেগমেন্ট লম্বা ও immutable, আর না-থাকা সেগমেন্টের 404 এক সেকেন্ড বা ক্যাশ নয়।
- TTL-এর মালিক origin। এক্সটেনশন দেখে সঠিক
Cache-Controlদিন; CDN কনফিগ শুধু নিরাপত্তা জাল। - ক্যাশ করা 404 পুরো অঞ্চলের স্ট্রিম মেরে ফেলতে পারে। আর origin তখন সুস্থ দেখায়, কারণ রিকোয়েস্ট তার কাছে আসেই না।
immutableতখনই নিরাপদ যখন সেগমেন্টের নাম কখনো ফেরে না। নম্বর ওয়াল-ক্লক থেকে নির্ধারিত হোক।- ফ্ল্যাশ ক্রাউড সামলায় প্রস্তুতি, অটোস্কেলিং নয়। আগে থেকে স্ট্রিম চালু, API আগে স্কেল, রিট্রাইতে jitter, ভেন্ডরকে আগাম নোটিশ।
- মাল্টি-CDN-এ মাঝপথে সরানোর জন্য Content Steering, আর দুই CDN-এ হুবহু একই সেগমেন্ট নাম।
- ইগ্রেস আগে হিসাব করুন। দর্শক × গড় বিটরেট × সময়; গড় বিটরেটই সবচেয়ে বড় নিয়ন্ত্রণযোগ্য সংখ্যা।