Loading...

تحویل · 9 دقیقه مطالعه

CDN ویدیو: تحویل HLS واقعاً چگونه کار می‌کند

ویدیو سنگین‌ترین چیزی است که بیشتر سایت‌ها سرو می‌کنند — یک بیننده‌ی یک ویدیوی ده‌دقیقه‌ای بیش از هزار بازدید صفحه بایت مصرف می‌کند. خبر خوبی که درون HLS پنهان است — فرمتی که تقریباً همه‌ی ویدیوهای وب از آن استفاده می‌کنند — این است که یک stream چیزی نیست جز یک playlist و یک پوشه از فایل‌های استاتیک کوچک، و سرو کردن فایل‌های استاتیک از edge دقیقاً همان کاری است که یک CDN انجام می‌دهد. این راهنما نشان می‌دهد قطعات چطور کنار هم می‌نشینند، کدام قواعد کش سرنوشت‌ساز است، و یک مثال کامل از آپلود تا پخش را مرور می‌کند.

Updated

CDN ویدیو: تحویل HLS واقعاً چگونه کار می‌کند

چرا ویدیو با هر چیز دیگری که سرو می‌کنید فرق دارد

یک صفحه‌ی وب چند مگابایت وزن دارد. ده دقیقه ویدیوی 1080p چیزی در حدود یک گیگابایت به‌ازای هر بیننده وزن دارد. همین شکاف سه‌مرتبه‌ای است که باعث می‌شود ویدیویی که به‌عنوان بازدید صفحه خطای گردکردن حساب می‌شد، روزی که محبوب شود یک سرور مبدأ را اشباع کند: صد بیننده‌ی همزمانِ یک فایل یعنی صد stream پرپهنای‌باند پیوسته از یک ماشین.

اقتصاد ماجرا هم از همین منحنی پیروی می‌کند. روی سرویس‌دهنده‌هایی که egress را به‌ازای هر گیگابایت صورتحساب می‌کنند، یک ویدیوی نسبتاً موفق یک فاکتور محسوس است؛ یک ویدیوی وایرال، یک تماس تلفنی از واحد مالی. هر دو مشکل — سقف پهنای‌باند و صورتحساب — همان شکل هر مشکل محتوای استاتیک دیگری را دارند، و یعنی همان راه‌حل را هم دارند: به درخواست‌های تکراری، هر بار، از کشی نزدیک به بیننده پاسخ بدهید نه از مبدأ.

رمزگشایی از HLS: یک playlist است و یک پوشه فایل

HLS (پخش زنده روی HTTP) تا وقتی فایل‌ها را باز نکرده‌اید عجیب به نظر می‌رسد. encoder ویدیو را به segmentهای کوتاه — هرکدام چند ثانیه — برش می‌زند و یک playlist متنی ساده (.m3u8) می‌نویسد که آن‌ها را به‌ترتیب فهرست می‌کند. player این playlist را دانلود می‌کند و بعد segmentها را یکی‌یکی روی HTTP معمولی می‌گیرد، چند ثانیه جلوتر از آنچه نمایش می‌دهد. کیفیت تطبیقی همان ترفند است دو بار: یک master playlist به چند variant playlist (1080p، 720p، 480p) اشاره می‌کند و player با تغییر پهنای‌باند بین آن‌ها جابه‌جا می‌شود.

نتیجه ارزش دارد که صریح گفته شود: در مسیر تحویل هیچ پروتکل ویدیویی خاصی وجود ندارد. نه socket، نه سرور استریم، نه زیرساخت عجیبی. هر درخواستی که player می‌فرستد یک GET برای یک فایل استاتیک کوچک است — و فایل‌های استاتیک کوچکی که میلیون‌ها بار سرو می‌شوند دقیقاً همان باری است که edge یک CDN برای آن وجود دارد.

یک variant playlist — متن ساده که به فایل‌های ساده اشاره می‌کند

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:6.000,
segment_000.ts
#EXTINF:6.000,
segment_001.ts
#EXTINF:6.000,
segment_002.ts
#EXT-X-ENDLIST

خط لوله‌ی VOD: یک‌بار encode کنید، یک‌بار ذخیره کنید، از edge سرو کنید

برای ویدیوی درخواستی، خط لوله سه ایستگاه دارد. یک‌بار encode کنید، روی ماشین خودتان یا در build — ffmpeg با یک فرمان، ویدیوی خام را به پوشه‌ی playlist-به‌همراه-segmentها تبدیل می‌کند. یک‌بار ذخیره کنید، در object storage سازگار با S3، که دقیقاً برای فایل‌های یک‌بار-بنویس-بارها-بخوان مثل همین‌ها وجود دارد. از edge سرو کنید: با bucket پشت CDN، نخستین بیننده‌ی هر segment کش را پر می‌کند و به همه‌ی نفرات بعدی نزدیک جایی که هستند پاسخ داده می‌شود، در حالی که storage شما به هر فایل یکتا تقریباً یک‌بار پاسخ می‌دهد.

روی cdn.com.tr، storage و edge یک پلتفرم واحدند، پس این یک پروژه‌ی integration نیست: یک bucket بسازید، پوشه را آپلود کنید، و edge همان حساب — به‌همراه WAF و حفاظت DDoS — جلوی آن قرار می‌گیرد.

از فایل خام تا stream سروشده از CDN

# 1) encode into HLS (6-second segments, one quality for brevity)
ffmpeg -i talk.mp4 -c:v h264 -c:a aac \
  -hls_time 6 -hls_playlist_type vod \
  -hls_segment_filename 'talk/segment_%03d.ts' talk/playlist.m3u8

# 2) create the bucket and an access key (panel works too)
cdnctl object-storage buckets create --account <uuid> --name videos
cdnctl object-storage access-keys create --account <uuid> --bucket <bucket_uuid>

# 3) upload the folder with the standard AWS CLI
aws --endpoint-url https://s3.cdn.com.tr s3 sync ./talk s3://videos/talk

# the player now points at the playlist behind your CDN hostname:
#   https://video.example.com/talk/playlist.m3u8

قواعد کشی که تحویل ویدیو را می‌سازند یا خراب می‌کنند

CDN ویدیو: تحویل HLS واقعاً چگونه کار می‌کند — قواعد کشی که تحویل ویدیو را می‌سازند یا خراب می‌کنند
یک قاعدهٔ توزیع برای داشته‌های استاتیک: regex مسیر به‌همراه زمان کش ۳۰ روزه.

ویدیو به انضباط cache-headerی پاداش می‌دهد که محتواهای دیگر فقط از آن خوششان می‌آید، چون دو نوع فایل درون یک stream مربوط به HLS رفتار متضادی می‌خواهند.

segmentها به‌حکم ساختار تغییرناپذیرند — segment_042.ts هرگز بایت‌های متفاوتی نخواهد داشت، چون یک encode دوباره پوشه‌ای تازه می‌نویسد. آن‌ها را هرچقدر می‌خواهید کش کنید؛ یک سال بی‌احتیاطی نیست، درست است. هر segment طولانی‌کش‌شده پهنای‌باندی است که مبدأ شما دیگر هرگز سرو نمی‌کند.

playlist بخش متحرک ماجراست. برای VOD تمام‌شده فقط وقتی تغییر می‌کند که ویدیو را جایگزین کنید، پس یک ساعت کافی است. لحظه‌ای که به یک playlist چیزی افزوده می‌شود — که سازوکار near-live همین است — باید در حد چند ثانیه کش شود، چون player آن را دوباره می‌خواند تا segmentهای تازه را کشف کند. اشتباه گرفتن همین یک header همان باگ کلاسیک ویدیوست: بینندگانی که روی segmentهای قدیمی منجمد شده‌اند در حالی که playlist می‌گوید چیز تازه‌ای وجود ندارد.

روی cdn.com.tr دقیقاً همین تفکیک را به‌صورت قواعد تحویل در پنل تنظیم می‌کنید: یک قاعده برای مسیر segmentها با زمان طولانی، یکی برای *.m3u8 با زمان کوتاه.

جزئیاتی که گاز می‌گیرند: range، CORS و فشرده‌سازی

سه نکته‌ی عملی، بیشتر تیکت‌های پشتیبانی ویدیو را نجات می‌دهد. اول، درخواست‌های range: playerها و مرورگرها به‌طور معمول بازه‌های بایتی از فایل‌های رسانه‌ای می‌خواهند و edge محتوای جزئی را از کش سرو می‌کند — همین است که به بیننده اجازه می‌دهد بدون دانلود دقیقه‌های یک تا پنجِ یک MP4، به دقیقه‌ی شش بپرد.

دوم، CORS: اگر player روی hostnameای متفاوت از فایل‌های ویدیو اجرا شود، مرورگر روی segmentها و playlistها هدر Access-Control-Allow-Origin مطالبه می‌کند، و نشانه‌ی فراموش کردنش playerای است که در یک تب خالی کار می‌کند اما embedشده در صفحه‌ی شما نه.

سوم، فشرده‌سازی: برای رسانه خاموشش بگذارید. ویدیو و صدا از قبل توسط codec فشرده شده‌اند؛ gzip کردن یک segment با پسوند .ts یعنی خرج کردن CPU برای هیچ. playlistها را اگر دوست دارید فشرده کنید — متن‌اند — اما سود آن میکروسکوپی است. edge از قبل می‌داند که انواع رسانه را دوباره فشرده نکند؛ این نکته برای پیکربندی مبدأ خودتان اهمیت دارد.

و پخش زنده؟ یک پاسخ صادقانه

پخش زنده همان داستان تحویل است با زنجیره‌ی تأمینی سخت‌تر. نیمه‌ی تحویل یکسان است: یک stream زنده‌ی HLS همچنان یک playlist و segmentهاست، فقط playlist هر چند ثانیه رشد می‌کند و بسیار کوتاه کش می‌شود. edge آن را عالی سرو می‌کند — هزاران بیننده که فایل‌هایی چندثانیه‌ای را می‌خوانند همچنان فقط cache hit است.

آنچه پخش زنده اضافه می‌کند، همه‌ی اتفاقات پیش از وجود فایل‌هاست: ingest (دریافت فید دوربین روی RTMP یا SRT)، transcode بلادرنگ به نردبان کیفیت، و packaging — یک خط لوله‌ی در حال اجرا با حالت‌های خرابی خودش، نه پوشه‌ای که یک‌بار آپلود می‌کنید. آن خط لوله چیزی نیست که سرسری سرهم شود، و کاری هم نیست که محصول self-serve این پلتفرم انجام می‌دهد: cdn.com.tr نیمه‌ی ذخیره‌سازی-و-تحویل داستان است. اگر پروژه‌ی شما زنجیره‌ی کامل پخش زنده را لازم دارد، به‌جای فشردن آن در قالبی VODشکل، مستقیم با ما درباره‌اش صحبت کنید — و مراقب هر ارائه‌دهنده‌ای باشید که «پخش زنده» می‌فروشد بی‌آنکه بگوید encoder را چه کسی اداره می‌کند.

پرسش‌های متداول

آیا می‌توانم به‌جای HLS مستقیماً یک فایل MP4 سرو کنم؟

برای کلیپ‌های کوتاه، بله — یک MP4 پشت CDN با درخواست‌های range کار می‌کند و playerها به‌خوبی در آن جلو و عقب می‌روند. HLS وقتی پیچیدگی‌اش را جبران می‌کند که ویدیوها طولانی یا مخاطبان متنوع شوند: کیفیت تطبیقی، شروع سریع‌تر، و segmentهای کوچکی که بهتر از یک فایل بزرگ کش و از سر گرفته می‌شوند.

آیا cdn.com.tr ویدیوهای من را encode می‌کند؟

نه — encoding سمت شما از خط لوله است (ffmpeg به‌صورت محلی یا در CI مسیر استاندارد است و فرمان بالا یک نقطه‌ی شروع کامل است). پلتفرم خروجی encodeشده را در object storage نگه می‌دارد و از طریق edge تحویل می‌دهد.

وقتی یک ویدیو وایرال شود چه اتفاقی می‌افتد؟

این همان سناریویی است که این معماری برایش ساخته شده: پس از نخستین بیننده در هر مکان edge، به segmentها از کش پاسخ داده می‌شود، پس بار مبدأ تقریباً تکان نمی‌خورد در حالی که تحویل با edge مقیاس می‌گیرد. چیزی که باید مراقبش باشید cache headerهای شماست — segmentهای تغییرناپذیرِ طولانی‌کش‌شده همان چیزی است که حساب‌وکتاب را جور می‌کند.

چطور یک ویدیو را جایگزین کنم بدون اینکه بینندگان ترکیبی خراب از قدیم و جدید ببینند؟

در یک پوشه‌ی جدید encode کنید (talk-v2/) و player را به URL جدید playlist بچرخانید — segmentهای کش‌شده‌ی قدیمی به‌جای غلط شدن بی‌ربط می‌شوند و نیازی به purge نیست. بازنویسی درجای فایل‌ها و purge کردن هم کار می‌کند، اما مسیرهای نسخه‌دار الگوی آرام‌تری است، دقیقاً مثل هر asset استاتیک دیگری.