সেশন ২৭

YouTube / Netflix Design - ঈদের রাতে ৫০ লাখ দর্শক

এই সেশনের লক্ষ্য: শূন্য থেকে একটা video streaming platform design করা, ঠিক যেভাবে একটা system design interview তে করতে হয়। Requirement লেখা, ধাপে ধাপে হিসাব করা, তারপর upload pipeline, transcoding, adaptive bitrate streaming, CDN আর view counter এর ভেতরটা বোঝা।

০০ যে প্রশ্নগুলোর উত্তর খুঁজবো

আগের চারটা সেশনে আমরা ধাপে ধাপে বড় হয়েছি: URL shortener এ একটা key আর একটা cache, rate limiter আর search এ Redis আর index, feed এ fan-out, আর chat এ real-time connection। এবার আরো বড় একটা system: শূন্য থেকে একটা পুরো video streaming platform, YouTube বা Netflix এর মতো। এখানে সবচেয়ে বড় চ্যালেঞ্জ data এর পরিমাণ। প্রতিটা video কয়েক GB, আর এক রাতে পাঠাতে হয় কয়েক petabyte।

কাঠামো আগের মতোই, সেশন ২৩ এর সাতটা ধাপ। আগে জানবো কী বানাতে হবে, তারপর হিসাব করবো কত বড় বানাতে হবে। দেখবেন, এখানে হিসাবটাই সবচেয়ে বড় কথা বলবে।

  • ১ "দেখো" এর জন্য ঠিক কী বানাবো? (functional ও non-functional requirements)
  • ২ System টা কত বড় হতে হবে? (back-of-envelope estimation, egress)
  • ৩ অ্যাপ কোন API call করবে, আর data কোথায় থাকবে? (API, data model, object storage)
  • ৪ পুরো system টা এক নজরে কেমন দেখায়? (high-level design)
  • ৫ Upload হওয়া video দেখার উপযোগী হয় কীভাবে? (upload pipeline, transcoding)
  • ৬ দুর্বল network এও video না থেমে চলে কীভাবে? (adaptive bitrate, segment, manifest, HLS, DASH)
  • ৭ ২০ লাখ মানুষকে একসাথে video পাঠাবো কোথা থেকে? (CDN, popular বনাম long-tail)
  • ৮ সেকেন্ডে হাজার হাজার view এলে গুনবো কীভাবে? (view counter at scale)
  • ৯ Design টা কোথায় চাপে পড়ে, আর কী ছাড় দিলাম? (bottlenecks ও trade-offs)

০১ “দেখো” এর জন্য ঠিক কী বানাবো? (functional ও non-functional requirements)

ঈদের ঠিক দুই সপ্তাহ আগের এক বিকেল। “দেখো” এর ছোট্ট অফিসে নাবিলা whiteboard এর সামনে দাঁড়িয়ে আছে। ছয় মাস আগে BSc শেষ করে সে এখানে backend engineer হিসেবে যোগ দিয়েছে। CTO ফাহিম ভাই এসে বললেন, “এবার ঈদের রাত ৯টায় আমাদের নাটক ‘ফেরা’ premiere হবে। Marketing বলছে, সেই রাতে ৫০ লাখ মানুষ দেখবে।” একটু থেমে যোগ করলেন, “গত ঈদে দুই লাখ মানুষেই অ্যাপ আটকে গিয়েছিলো, মনে আছে তো?” নাবিলার হাতের marker টা হঠাৎ ভারী মনে হলো।

“দেখো” একটা বাংলাদেশি startup। এদের অ্যাপ এ বাংলা নাটক আর টেলিফিল্ম দেখা যায়। Production house আর ছোট creator রা নিজেদের video upload করেন, আর দর্শক mobile, TV বা browser এ দেখেন।

নাবিলা সাথে সাথে box আঁকতে শুরু করলো না। প্রথমে সে লিখলো, system টা কী কী করবে। এগুলোকে বলে functional requirement। তারপর লিখলো, system টা কতটা ভালোভাবে করবে: কত দ্রুত, কত মানুষের জন্য, কতটা নির্ভরযোগ্যভাবে। এগুলোকে বলে non-functional requirement।

Functional requirement: system কী কী করবে

  1. Upload: Creator একটা video upload করতে পারবেন। একটা ৪৫ মিনিটের নাটকের raw file প্রায় 2 GB।
  2. দেখা: দর্শক mobile, TV আর browser এ video দেখতে পারবেন। Network দুর্বল হলেও video চলবে।
  3. View count: প্রতিটা video এর নিচে কতজন দেখেছেন, সেই সংখ্যা দেখাবে।

যা এই design এ রাখছি না, সেটাও লিখে রাখা জরুরি। Search, recommendation, comment, subscription এর payment আর DRM (video কপি হওয়া ঠেকানোর ব্যবস্থা) এই সেশনের বাইরে। Interview তেও এভাবে scope ছোট করে নিলে interviewer খুশিই হন। কারণ ৪৫ মিনিটে সবকিছু design করা যায় না।

Non-functional requirement: কতটা ভালোভাবে করবে

বিষয়লক্ষ্য
Scaleঈদের রাতে ৫০ লাখ দর্শক, রাত ৯টায় একসাথে প্রায় ২০ লাখ।
শুরু হওয়ার সময়Play চাপার ২ সেকেন্ডের মধ্যে video শুরু হবে।
Bufferingদেখার মোট সময়ের ১% এর কম সময় spinner ঘুরবে।
Availabilityদেখার পথ ৯৯.৯% সময় চালু থাকবে (SLO, সেশন ০১)। Upload এর পথ একটু ধীর হলেও চলে।
Durabilityএকবার upload হওয়া video কখনো হারাবে না।
ConsistencyView count কয়েক সেকেন্ড পিছিয়ে থাকলে সমস্যা নেই (eventual consistency, সেশন ০৩)।
খরচBandwidth এর খরচ startup এর সাধ্যের মধ্যে থাকবে।

এই table থেকে একটা বড় সত্য বেরিয়ে আসে। Upload হয় কালেভদ্রে, আর কয়েক মিনিট দেরি হলেও কেউ রাগ করেন না। কিন্তু দেখার সময় এক সেকেন্ডের আটকে যাওয়াও দর্শক টের পান। অর্থাৎ এটা একটা read-heavy system। পুরো design এর বেশিরভাগ মনোযোগ যাবে দেখার পথে।

Requirement এর আসল কাজ

Requirement লেখা মানে শুধু feature এর তালিকা বানানো নয়। আসল কাজ হলো আলাদা করা, কোন অংশ ধীর হলে চলে আর কোন অংশ এক মুহূর্তও ধীর হতে পারবে না। “দেখো” তে upload ধীর হলে চলে, দেখা ধীর হলে চলে না। এই একটা সিদ্ধান্তই পরের সব design ঠিক করে দেয়।

০২ System টা কত বড় হতে হবে? (back-of-envelope estimation, egress)

নাবিলা এবার একটা কাগজ টেনে নিলো। এবার back-of-envelope estimation এর পালা (সেশন ২৩)। মনে করিয়ে দিই, এর লক্ষ্য নিখুঁত সংখ্যা নয়। লক্ষ্য হলো সংখ্যাটা কোন মাপের, সেটা জানা: 3 GB নাকি 3 TB, ৩০০ request নাকি ৩ লাখ। মাপটা ঠিক থাকলে design ও ঠিক দিকে যায়।

হিসাবের আগে দুইটা শব্দ জেনে নিন। Bitrate মানে video এর প্রতি সেকেন্ডে কত bit data লাগে। 1080p এর একটা video তে সাধারণত প্রায় 5 Mbps (প্রতি সেকেন্ডে ৫০ লাখ bit) লাগে। আর egress মানে আপনার server থেকে বাইরের দুনিয়ায় যাওয়া data। Cloud এ ভেতরে data আনা প্রায় বিনা পয়সায় হয়, কিন্তু বাইরে পাঠানো প্রতিটা GB এর জন্য টাকা দিতে হয়।

এখানে ছয়টা ধাপে পুরো হিসাব। প্রথম ধাপের সংখ্যাগুলো নাবিলা ফাহিম ভাইয়ের সাথে কথা বলে ধরে নিয়েছে। বাকি সব ঐ সংখ্যা থেকে গুণ-ভাগ করে বের করা:

# ধাপ 0: ধরে নেওয়া সংখ্যা (assumption)
upload / দিন        = 1,000 টা video
গড় দৈর্ঘ্য           = 30 মিনিট = 1,800 সেকেন্ড
original bitrate    = 8 Mbps
rendition ladder    = 1080p 5 + 720p 3 + 480p 1.2 + 360p 0.6 + 240p 0.2
                    = 10 Mbps (পাঁচটা মিলিয়ে)

# ধাপ 1: একটা video কত জায়গা নেয়
original    = 8 Mbps  × 1,800 s = 14,400 Mb ÷ 8 = 1,800 MB ≈ 1.8 GB
renditions  = 10 Mbps × 1,800 s = 18,000 Mb ÷ 8 = 2,250 MB ≈ 2.25 GB
মোট         ≈ 4 GB প্রতি video

# ধাপ 2: storage
প্রতিদিন     = 1,000 × 4 GB  = 4 TB
প্রতি বছর    = 4 TB × 365    ≈ 1,460 TB ≈ 1.5 PB

# ধাপ 3: upload এর হার (write)
1,000 ÷ 86,400 s              ≈ 0.012 upload/s (দেড় মিনিটে প্রায় একটা)
ingress = 1,800 GB ÷ 86,400 s ≈ 21 MB/s ≈ 167 Mbps

# ধাপ 4: peak egress (read), ঈদের রাত 9টা
একসাথে দর্শক  = 20 লাখ = 2,000,000
গড় bitrate    = 1.5 Mbps (বেশিরভাগ mobile, 480p থেকে 720p)
peak egress    = 2,000,000 × 1.5 Mbps = 3,000,000 Mbps = 3 Tbps
এক server      ≈ 10 Gbps পাঠাতে পারে
server লাগবে   = 3 Tbps ÷ 10 Gbps = 300 টা, শুধু bandwidth এর জন্য

# ধাপ 5: এক রাতের মোট egress আর খরচ
প্রতি দর্শক     = 1 ঘণ্টা × 1.5 Mbps = 3,600 s × 1.5 = 5,400 Mb = 675 MB
50 লাখ দর্শক   = 5,000,000 × 675 MB ≈ 3,400,000 GB ≈ 3.4 PB
খরচ ($0.02/GB) = 3,400,000 × 0.02 ≈ $68,000 ≈ ৳80 লাখ (1 $ ≈ ৳120)

# ধাপ 6: view counter (write, একটাই নাটক)
20 লাখ মানুষ 10 মিনিটের মধ্যে play চাপে
2,000,000 ÷ 600 s ≈ 3,333 view/s, সবগুলো একই row এ

হিসাব শেষে নাবিলা কিছুক্ষণ চুপ করে বসে রইলো। তিনটা সংখ্যা তার চোখে আটকে গেছে।

এই তিনটা সংখ্যা থেকেই পরের তিনটা বড় design সিদ্ধান্ত আসে:

UPLOAD 1,000 video / দিন গড়ে 30 মিনিট, ~4 GB ~4 TB / দিন বছরে ~1.5 PB Object storage DB তে শুধু metadata WATCH 20 লাখ একসাথে গড়ে 1.5 Mbps ~3 Tbps peak এক data center এ অসম্ভব CDN + ABR দর্শকের কাছ থেকে পাঠানো VIEW COUNT 20 লাখ play 10 মিনিটের মধ্যে ~3,333 write/s একটাই row এ জমিয়ে গোনা Kafka + aggregator
উপরের সারিতে ধরে নেওয়া সংখ্যা, মাঝের সারিতে হিসাবের ফল, নিচের সারিতে সেই ফল থেকে আসা design সিদ্ধান্ত। 3 Tbps সংখ্যাটা দেখার পরই বোঝা যায়, এখানে CDN বাড়তি সুবিধা নয়, একমাত্র উপায়।
খরচের হিসাবও design এর অংশ

এক রাতের egress প্রায় 3.4 PB। প্রতি GB তে মাত্র দুই cent ধরলেও সেটা প্রায় $68,000, মানে প্রায় ৮০ লাখ টাকা। অথচ সারা বছরে জমানো 1.5 PB video এক মাস রাখতে খরচ এর অর্ধেকেরও কম। Video platform এ storage নয়, bandwidth ই সবচেয়ে বড় খরচ। তাই যে design প্রতিটা GB কে দর্শকের কাছাকাছি থেকে পাঠায়, সেটাই টিকে থাকে।

০৩ অ্যাপ কোন API call করবে, আর data কোথায় থাকবে? (API, data model, object storage)

API: অ্যাপ আর server এর চুক্তি

API হলো অ্যাপ আর server এর মধ্যে কথা বলার নিয়ম। কোন URL এ কী পাঠালে কী ফেরত আসবে, সেটা আগে থেকে ঠিক করা থাকে। “দেখো” এর জন্য পাঁচটা call যথেষ্ট:

# 1. Upload শুরু: video_id আর upload URL চাওয়া
POST /v1/videos
body:     { "title": "ফেরা", "size_bytes": 1932735283 }
response: { "video_id": "v_8f3k2",
            "upload_url": "https://store.dekho.example/raw/v_8f3k2?sig=..." }

# 2. File পাঠানো: সরাসরি object storage এ, 5 MB এর টুকরো করে
PUT {upload_url}
Content-Range: bytes 0-5242879/1932735283

# 3. Upload শেষ হয়েছে জানানো
POST /v1/videos/v_8f3k2/complete
response: { "status": "PROCESSING" }

# 4. দেখার আগে metadata আর manifest এর ঠিকানা নেওয়া
GET /v1/videos/v_8f3k2
response: { "title": "ফেরা", "status": "READY", "view_count": 1240000,
            "manifest_url": "https://cdn.dekho.example/v_8f3k2/master.m3u8" }

# 5. Player প্রতি 30 সেকেন্ডে জানায়: "এখনো দেখছি"
POST /v1/videos/v_8f3k2/heartbeat
body: { "session_id": "s_91c", "position_s": 1830 }

দুইটা জিনিস খেয়াল করুন। প্রথমত, 2 GB এর file টা আমাদের app server এর ভেতর দিয়ে যায় না। Upload API শুধু একটা pre-signed URL দেয়। এটা object storage এর একটা বিশেষ link, যেটা কিছুক্ষণের জন্য শুধু এই একটা file লেখার অনুমতি দেয়। অ্যাপ সেই link এ সরাসরি file পাঠায়। ফলে আমাদের server গুলো GB ভর্তি upload সামলাতে গিয়ে আটকে থাকে না।

দ্বিতীয়ত, file টা যায় 5 MB এর টুকরো করে। একে বলে resumable upload। মাঝপথে network কেটে গেলে creator কে পুরো 2 GB আবার পাঠাতে হয় না। শুধু যে টুকরোটা অসম্পূর্ণ ছিলো, সেখান থেকে আবার শুরু হয়।

আর দেখার সময় video এর আসল টুকরোগুলো এই API থেকে আসে না। API শুধু manifest_url দেয়। বাকিটা player সরাসরি CDN থেকে নেয়। সেটা আমরা ০৬ নম্বর প্রশ্নে খুলে দেখবো।

Data model: কোন data কোথায় থাকবে

“দেখো” তে দুই রকম data আছে। এদের স্বভাব একদম আলাদা, তাই এরা আলাদা জায়গায় থাকে।

Dataউদাহরণকোথায় থাকেকেন
Metadatatitle, status, view_countSQL database, video_id দিয়ে shard করা (সেশন ০৫), সাথে Redis cache (সেশন ০৪)ছোট, ঘনঘন পড়া হয়, query লাগে
Video fileraw file, segment, manifestObject storageবিশাল, একবার লেখা হয়, বদলায় না

Object storage আমরা সেশন ২৩ এ Pastebin এর জন্য, আর সেশন ২৫ এ ছবির জন্য দেখেছি। মনে করিয়ে দিই: এটা বিশাল file রাখার service (যেমন Amazon S3), যেখানে প্রতিটা file একটা key দিয়ে রাখা আর পড়া যায়, জায়গা প্রায় অসীম, আর প্রতিটা file এর কয়েকটা কপি থাকে। Video এর জন্য এটাই সবচেয়ে স্বাভাবিক জায়গা।

-- Metadata: SQL database, video_id দিয়ে shard করা (সেশন ০৫)
CREATE TABLE videos (
    video_id      VARCHAR(16) PRIMARY KEY,  -- 'v_8f3k2'
    creator_id    VARCHAR(16) NOT NULL,
    title         TEXT        NOT NULL,     -- 'ফেরা'
    duration_s    INT,                      -- 2700
    status        VARCHAR(12) NOT NULL,     -- UPLOADING, PROCESSING, READY, FAILED
    manifest_path TEXT,                     -- 'hls/v_8f3k2/master.m3u8'
    view_count    BIGINT DEFAULT 0,         -- কয়েক সেকেন্ড পিছিয়ে থাকতে পারে
    publish_at    TIMESTAMP,                -- 'ফেরা': ঈদের রাত 9টা
    created_at    TIMESTAMP NOT NULL
);

-- আসল file: object storage এ, key দিয়ে রাখা
raw/v_8f3k2/original.mp4              1.8 GB
hls/v_8f3k2/master.m3u8               1 KB
hls/v_8f3k2/720p/index.m3u8           14 KB
hls/v_8f3k2/720p/seg_00001.ts         2.25 MB  (3 Mbps × 6 s ÷ 8)

০৪ পুরো system টা এক নজরে কেমন দেখায়? (high-level design)

নাবিলা এবার whiteboard এ ফিরে গেলো। Requirement থেকে সে জানে, system এ দুইটা আলাদা পথ আছে। একটা লেখার পথ (upload), যেটা দিনে মাত্র ১,০০০ বার চলে। আরেকটা পড়ার পথ (দেখা), যেটা ঈদের রাতে ২০ লাখ মানুষ একসাথে ব্যবহার করে।

CLIENT API / EDGE QUEUE / DB WORKERS STORAGE Creator দর্শক 1. upload 5. metadata 6. segments Upload API upload URL দেয় Play API title, manifest URL CDN Edge segment পাঠায় 2. job Queue transcode এর job Metadata DB + Redis cache 3. transcode miss হলে origin থেকে আনে Transcode Workers rendition আর segment বানায় status = READY 4. segments লেখে Object Storage (origin) raw video, সব rendition আর সব segment এখানে থাকে
বাঁ দিকের পথটা লেখার (১ থেকে ৪): creator video দেয়, queue তে job যায়, worker রা video কেটে-ছেঁটে storage এ রাখে। ডান দিকের পথটা পড়ার (৫ আর ৬): দর্শক আগে Play API থেকে নাটকের তথ্য নেয়, তারপর আসল video এর টুকরোগুলো নেয় CDN থেকে। দুই পথের মিলনস্থল একটাই: object storage।

দুই পথে কী কী হয়, এক নজরে দেখে নিন:

দুই পথ, দুই রকম নিয়ম

লেখার পথে গতির চেয়ে নির্ভরযোগ্যতা জরুরি, তাই সেখানে queue, retry আর ধীরস্থির worker। পড়ার পথে গতিই সব, তাই সেখানে cache আর CDN। একই system এর দুই অংশে দুই রকম নিয়ম চালানো যায়, কারণ পথ দুটো একে অন্যের উপর নির্ভর করে না। এদের একমাত্র মিলনস্থল object storage।

এবার এই ছবির চারটা কঠিন অংশ একটা একটা করে খুলে দেখবো। এগুলোই case study এর deep dive।

০৫ Upload হওয়া video দেখার উপযোগী হয় কীভাবে? (upload pipeline, transcoding)

Raw file কেন সরাসরি দেখানো যায় না

‘ফেরা’ এর editor শুভ ভাই export করা file টা upload করলেন: ৪৫ মিনিট, 1080p, প্রায় 8 Mbps। এই file টাই কি দর্শককে পাঠিয়ে দেওয়া যায়? তিনটা কারণে যায় না।

তাই raw file থেকে নতুন করে কয়েকটা version বানাতে হয়। একটা video কে অন্য codec, resolution বা bitrate এ নতুন করে encode করার কাজকে বলে transcoding। প্রতিটা version কে বলে একটা rendition। “দেখো” প্রতিটা video থেকে পাঁচটা rendition বানায়: 1080p, 720p, 480p, 360p আর 240p।

Upload থেকে READY পর্যন্ত: upload pipeline

পুরো পথটাকে বলে upload pipeline। শুভ ভাই upload চাপার পর থেকে ‘ফেরা’ দর্শকের কাছে পৌঁছানো পর্যন্ত ছয়টা ধাপ:

1 অ্যাপ: upload শুরু করতে চাই Upload API দেয় video_id আর একটা pre-signed URL UPLOADING 2 5 MB এর টুকরো সরাসরি storage এ network কাটলে শুধু শেষ টুকরোটা আবার যায় 3 Upload শেষ: queue তে job app server আর অপেক্ষা করে না (সেশন ০৮) PROCESSING 4 Worker: কেটে টুকরো, তারপর transcode অনেক worker একসাথে, প্রতিটা 5 rendition 5 Packager: 6 সেকেন্ডের segment সাথে manifest (HLS আর DASH) 6 Thumbnail আর metadata DB তে manifest_path আর duration লেখা সব ঠিক বারবার fail READY দর্শক এখন দেখতে পারে FAILED job যায় DLQ তে, creator কে জানানো হয়
ডান পাশের লেখাগুলো video এর status: UPLOADING থেকে PROCESSING, তারপর READY বা FAILED। তিন নম্বর ধাপের পর থেকে সব কাজ background এ চলে, creator চাইলে অ্যাপ বন্ধ করে চা খেতে যেতে পারেন। কোনো worker crash করলে job আবার queue তে ফেরে, আর অন্য worker সেটা তুলে নেয়।

তিন নম্বর ধাপটা এই pipeline এর প্রাণ। Upload শেষ হওয়ামাত্র Upload API একটা job queue তে রেখে দেয়, আর creator কে সাথে সাথে “পেয়েছি” জানায়। ভারী কাজটা হয় পরে, worker দের হাতে। এটা ঠিক সেশন ০৮ এর asynchronous processing। Job retry, worker pool এর আকার আর timeout এর খুঁটিনাটি সেশন ০৯ এ আছে।

দেড় ঘণ্টার কাজ বারো মিনিটে: টুকরো করে transcoding

Transcoding ধীর কাজ। ধরুন একটা worker এ সব rendition বানাতে video এর দৈর্ঘ্যের দ্বিগুণ সময় লাগে। তাহলে ৪৫ মিনিটের ‘ফেরা’ তে লাগবে দেড় ঘণ্টা। কিন্তু video টাকে ছোট টুকরো করে আলাদা worker এ দিলে সব টুকরো একসাথে তৈরি হতে পারে:

ফেরা.mp4 45 মিনিট, 1.8 GB raw split: 5 মিনিট করে 9 টুকরা W1 0-5m W2 5-10m W3 10-15m W4 15-20m W5 20-25m W6 25-30m W7 30-35m W8 35-40m W9 40-45m Packager 9 টুকরো জোড়া লাগায়, তারপর segment আর manifest বানায় এক worker: ~90 মিনিট একটার পর একটা, সব rendition 9 worker: ~12 মিনিট সবাই একসাথে 10 মিনিট + 2 মিনিট জোড়া
ধরে নেওয়া হিসাব: একটা worker এ সব rendition বানাতে video এর দৈর্ঘ্যের দ্বিগুণ সময় লাগে। ৪৫ মিনিটের নাটক এক worker এ প্রায় দেড় ঘণ্টা নেয়। ৯ টুকরো করে ৯টা worker এ দিলে প্রতিটা টুকরো ১০ মিনিটে শেষ হয়, জোড়া লাগাতে আরো দুই মিনিট। একটা worker crash করলে শুধু তার ৫ মিনিটের টুকরোটা আবার করতে হয়।

টুকরো করার আরেকটা লাভ আছে। কোনো worker মাঝপথে crash করলে শুধু তার ৫ মিনিটের টুকরোটা আবার করতে হয়, পুরো নাটক নয়। আর প্রতিটা টুকরোর output এর নাম আগে থেকেই ঠিক করা (যেমন 720p/part_04.ts)। তাই একই টুকরো দুইবার transcode হলেও একই file আবার লেখা হয়, ভুল কিছু তৈরি হয় না। এটাই সেশন ০৮ এর idempotency।

Premiere এর আগে upload

Transcoding যত দ্রুতই হোক, শূন্য সেকেন্ডে হয় না। তাই ‘ফেরা’ ঈদের তিন দিন আগেই upload করা হয়, publish_at এ রাত ৯টা লিখে। এতে pipeline শান্তভাবে শেষ হয়, আর premiere এর আগে video টা সব edge এ পৌঁছে দেওয়ার সময়ও পাওয়া যায়।

০৬ দুর্বল network এও video না থেমে চলে কীভাবে? (adaptive bitrate, segment, manifest, HLS, DASH)

নাবিলার খালা থাকেন সিলেটের এক গ্রামে। ঈদের রাতে উঠানে সবাই মিলে phone এ ‘ফেরা’ দেখবেন। ঘরের ভেতরে signal ভালো, উঠানে গেলে কমে যায়। নাবিলা চায় না খালা একবারও spinner দেখুন।

Video কে ছোট টুকরো করা: segment

প্রথম কৌশল হলো প্রতিটা rendition কে ছোট ছোট টুকরো করে কাটা। প্রতিটা টুকরোকে বলে segment। “দেখো” প্রতিটা segment ৬ সেকেন্ডের রাখে। ৪৫ মিনিটের ‘ফেরা’ তে তাই প্রতিটা rendition এ ৪৫০টা segment হয়।

Player এখন পুরো নাটক একবারে নামায় না। সে segment #1 আনে, চালায়, ততক্ষণে #2 আর #3 আনতে থাকে। হাতে কয়েকটা segment জমা থাকে, যাকে বলে buffer। Network কিছুক্ষণের জন্য থমকে গেলেও buffer থেকে video চলতে থাকে।

কোন segment কোথায়: manifest

Player জানবে কীভাবে, কোন কোন quality আছে আর কোন segment এর পর কোনটা? এর জন্য থাকে একটা তালিকা, যাকে বলে manifest। Master manifest বলে কোন কোন rendition আছে। প্রতিটা rendition এর নিজের manifest বলে, তার segment গুলো কোন ক্রমে চালাতে হবে:

MANIFEST RENDITION SEGMENT (6 সেকেন্ড) master.m3u8 পাঁচটা তালিকার তালিকা 1080p · 5 Mbps #1 #2 #3 #4 #5 … #450 720p · 3 Mbps #1 #2 #3 #4 #5 … #450 480p · 1.2 Mbps #1 #2 #3 #4 #5 … #450 360p · 0.6 Mbps #1 #2 #3 #4 #5 … #450 240p · 0.2 Mbps #1 #2 #3 #4 #5 … #450 45 মিনিট = 2,700 সেকেন্ড; 2,700 ÷ 6 = 450 টা segment, প্রতিটা rendition এ
'ফেরা' এখন আর একটা বড় file নয়। এটা ৫টা quality তে ৪৫০টা করে, মোট ২,২৫০টা ছোট file। Master manifest বলে কোন কোন quality আছে। প্রতিটা quality এর নিজের manifest বলে, কোন segment এর পর কোনটা চালাতে হবে।

বাস্তবের একটা manifest দেখতে এমন। এটা HLS format এর, যার কথা একটু পরেই আসছে:

# master.m3u8: কোন কোন quality আছে
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1280x720
720p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1200000,RESOLUTION=854x480
480p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=600000,RESOLUTION=640x360
360p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=200000,RESOLUTION=426x240
240p/index.m3u8

# 720p/index.m3u8: এই quality র segment গুলো, ক্রম অনুযায়ী
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:6.0,
seg_00001.ts
#EXTINF:6.0,
seg_00002.ts
...
#EXTINF:6.0,
seg_00450.ts
#EXT-X-ENDLIST

Network বুঝে quality বদলানো: adaptive bitrate

এবার আসল কৌশল। প্রতিটা segment নামাতে কত সময় লাগলো, player সেটা মাপে। তা থেকে সে বোঝে, এই মুহূর্তে network এর গতি কেমন। তারপর পরের segment টা সেই অনুযায়ী quality থেকে চায়। Network ভালো থাকলে 720p, দুর্বল হলে 360p। এই কৌশলের নাম adaptive bitrate streaming, সংক্ষেপে ABR।

খালার phone এ ঈদের রাতের প্রথম এক মিনিটে ঠিক এমনটাই ঘটলো:

player যে quality নিলো মাপা bandwidth 1080p · 5 720p · 3 480p · 1.2 360p · 0.6 Mbps #1 #2 #3 #4 #5 #6 #7 #8 #9 #10 #11 #12 segment (প্রতিটা 6 সেকেন্ড) উঠানে গেলেন: signal কমলো signal ফিরলে ধীরে ওঠে
খালার phone এ ১২টা segment এর গল্প। প্রথম segment ইচ্ছা করে 480p এ, যাতে video তাড়াতাড়ি শুরু হয়। ৫ নম্বরে signal পড়ে গেলো, কিন্তু ঐ segment আগেই 720p তে চাওয়া হয়ে গেছে, তাই buffer এ জমানো video থেকে চলে। ৬ নম্বর থেকে player 360p চায়, আর video একবারও থামে না। Signal ফিরলে player একবারে লাফ দেয় না, ধাপে ধাপে ওঠে।

খেয়াল করুন, quality নামে দ্রুত কিন্তু ওঠে ধীরে। কারণটা সহজ। Network দুর্বল হলে quality না নামালে buffer খালি হয়ে spinner চলে আসে। আবার signal একটু ভালো হতেই 1080p এ লাফ দেওয়াও বিপদ। পরের মুহূর্তে signal আবার পড়ে গেলে বড় segment টা সময়মতো আসে না, আর video আটকে যায়। তাই player সাবধানে এক ধাপ এক ধাপ করে ওঠে।

HLS আর DASH: দুইটা প্রচলিত নিয়ম

Segment আর manifest কোন format এ হবে, তার দুইটা প্রচলিত নিয়ম আছে:

বিষয়HLS (HTTP Live Streaming)DASH (Dynamic Adaptive Streaming over HTTP)
কে বানিয়েছেAppleMPEG, একটা আন্তর্জাতিক standard
Manifest file.m3u8.mpd (XML)
কোথায় চলেiPhone আর Safari তে নিজে থেকেই; অন্য জায়গায় player library দিয়েAndroid, Smart TV আর browser এ player library দিয়ে

দুটোর মূল ধারণা একই: ছোট segment, একটা manifest, আর player নিজেই quality বেছে নেয়। আজকাল CMAF নামের একটা format দিয়ে একই segment file দুই নিয়মেই চালানো যায়। তাই “দেখো” segment একবারই বানায়, শুধু দুই রকম manifest লেখে।

Streaming আসলে অনেকগুলো ছোট download

HLS আর DASH এর segment গুলো সাধারণ HTTP file, ঠিক একটা ছবির মতো। তাই CDN এগুলো অন্য যেকোনো file এর মতোই cache করতে পারে। Streaming এর জন্য আলাদা কোনো বিশেষ server লাগে না। এই একটা সুবিধার জন্যই পরের প্রশ্নের CDN কৌশল এত সহজে কাজ করে।

০৭ ২০ লাখ মানুষকে একসাথে video পাঠাবো কোথা থেকে? (CDN, popular বনাম long-tail)

সেশন ০৬ এ আমরা CDN দেখেছি। মনে করিয়ে দিই: edge হলো দর্শকের কাছাকাছি বসানো cache server, আর origin হলো যেখানে আসল file থাকে। আমাদের origin হলো object storage।

এখানে সুখবর হলো, ‘ফেরা’ আকারে ছোট। পাঁচটা rendition মিলিয়ে পুরো নাটক মাত্র প্রায় 3.4 GB (10 Mbps × 2,700 সেকেন্ড ÷ 8)। ২০ লাখ দর্শক এই একই 3.4 GB এর segment গুলোই বারবার চাইছেন। তাই প্রতিটা edge এ পুরো নাটকটা অনায়াসে রাখা যায়। তখন প্রায় ৯৯% request edge এই শেষ হয়ে যায়।

তিন স্তরের CDN

VIEWERS EDGE SHIELD ORIGIN ঢাকা এর দর্শক চট্টগ্রাম এর দর্শক সিলেট এর দর্শক Edge: ঢাকা ISP এর ভেতরে cache Edge: চট্টগ্রাম ISP এর ভেতরে cache Edge: সিলেট ISP এর ভেতরে cache ফেরা: HIT ~99%, ~10 ms Origin Shield সব edge এর miss এখানে আসে একই segment এর অনেক miss এক হয়ে একবারই নিচে যায় shield এও miss Object storage সব video, সব segment 2015 এর পুরোনো নাটক: বেশিরভাগ সময় এখান থেকে ফেরা: রাত 8টায় এখান থেকে সব edge এ আগেই push
'ফেরা' এর মতো জনপ্রিয় নাটক দর্শকের সবচেয়ে কাছের edge থেকেই যায়, origin পর্যন্ত request প্রায় পৌঁছায়ই না। অনেক দিনের পুরোনো, কম দেখা নাটকের segment edge এ থাকে না। সেটা shield হয়ে origin থেকে আসে, তাই প্রথম segment আসতে একটু বেশি সময় লাগে।

জনপ্রিয় বনাম long-tail video

সব video তো ‘ফেরা’ এর মতো জনপ্রিয় নয়। “দেখো” তে কয়েক হাজার নাটক আছে। তার মধ্যে ২০১৫ সালের এমন নাটকও আছে, যেটা দিনে তিনজন দেখেন। সব নাটকের সব segment সব edge এ রাখার জায়গা নেই, দরকারও নেই।

view video, সবচেয়ে বেশি দেখা থেকে সবচেয়ে কম দেখা পর্যন্ত সাজানো HEAD: উপরের ~10% video মোট view এর ~80% এখানে যেমন 'ফেরা': সব edge এ আগেই রাখুন LONG TAIL: বাকি ~90% video প্রতিটার view খুব কম shield আর origin থেকে পাঠান 10%
সংখ্যাগুলো আনুমানিক, কিন্তু আকৃতিটা প্রায় সব video platform এ একই রকম। অল্প কয়েকটা video এর view অনেক বেশি, আর লম্বা একটা লেজ জুড়ে হাজার হাজার video এর view খুব কম। Edge এর জায়গা সীমিত, তাই সেখানে মাথার দিকের video রাখাই লাভজনক।

Video platform এ view এর ছবিটা প্রায় সবসময় এমন হয়। অল্প কিছু video পায় বেশিরভাগ view। আর লম্বা একটা লেজ জুড়ে থাকে হাজার হাজার video, যাদের প্রত্যেকের view খুব কম। এই লেজকে বলে long tail। দুই দলের জন্য কৌশলও দুই রকম:

বিষয়জনপ্রিয় video (‘ফেরা’)Long-tail video (২০১৫ এর নাটক)
কোথা থেকে যায়Edge থেকেShield বা origin থেকে
কখন cache হয়Premiere এর আগেই push করা হয়কেউ চাইলে তখন cache হয়, পরে মুছে যায়
প্রথম segment আসার সময়~10-20 msকয়েকশো ms পর্যন্ত

রাত ৯টা ০০ মিনিট ০০ সেকেন্ডের বিপদ

একটা বিপদ এখনো বাকি। রাত ঠিক ৯টায় ২০ লাখ মানুষ একসাথে play চাপবেন। সবাই চাইবেন একই file: ‘ফেরা’ এর segment #1। কোনো edge এ সেটা তখনো না থাকলে সব miss একসাথে origin এর দিকে ছুটবে। এটা সেশন ০৪ এর cache stampede, শুধু অনেক বড় আকারে।

এর দুইটা সমাধান, আর “দেখো” দুটোই ব্যবহার করে:

  1. আগে থেকে পৌঁছে দেওয়া (pre-warm): রাত ৮টার মধ্যেই ‘ফেরা’ এর সব segment সব edge এ push করে রাখা হয়। ৯টায় কেউ চাওয়ার আগেই cache ভর্তি।
  2. একই miss একবার (request coalescing): তবু কোনো edge এ segment না থাকলে, প্রথম request টাই শুধু origin এ যায়। একই segment এর বাকি request গুলো কয়েক millisecond অপেক্ষা করে, আর ঐ একই উত্তর পায়।
সবচেয়ে সস্তা byte হলো যেটা দূরে যায়ই না

Edge এ HIT মানে দ্রুত video, আর origin এ শান্তি। ISP এর ভেতরে HIT মানে তার চেয়েও বেশি: data দেশের বাইরের বা শহরের বাইরের লম্বা পথ পাড়ি দেয় না, তাই bandwidth এর খরচও কমে। Video platform এর design এর বড় অংশই হলো এই প্রশ্নের উত্তর: কোন byte কোথায় আগে থেকে রেখে দেবো।

০৮ সেকেন্ডে হাজার হাজার view এলে গুনবো কীভাবে? (view counter at scale)

সহজ উপায়, আর সেটা কেন ভাঙে

প্রথমে ঠিক করতে হবে, একটা “view” মানে কী। কেউ play চেপে দুই সেকেন্ড পর বন্ধ করলে কি সেটা view? “দেখো” ঠিক করলো, কেউ টানা ৩০ সেকেন্ড দেখলে তবেই একটা view গোনা হবে।

সবচেয়ে সহজ উপায় হলো, প্রতিটা view এ database এ একটা update চালানো:

-- প্রতিটা view এ একবার করে চলে
UPDATE videos SET view_count = view_count + 1 WHERE video_id = 'v_8f3k2';

কম traffic এ এটা দিব্যি চলে। কিন্তু ২ নম্বর প্রশ্নের হিসাব মনে করুন। রাত ৯টার পরের দশ মিনিটে ২০ লাখ মানুষ ‘ফেরা’ চালু করেন। মানে সেকেন্ডে প্রায় ৩,৩৩৩টা update, আর সবগুলো একই row তে। একটা row একবারে একটাই transaction বদলাতে পারে। বাকিরা lock এর জন্য লাইনে দাঁড়ায়।

সেশন ০৫ এ এর নাম শিখেছিলাম: hot key। Shard বাড়িয়েও লাভ নেই, কারণ ‘ফেরা’ এর row থাকে একটাই shard এ। পুরো চাপ সেই একটা shard এর উপরেই পড়ে।

সমাধান: আগে জমানো, পরে একবারে লেখা

মূল কৌশল হলো প্রতিটা view আলাদা করে না লিখে, কয়েক সেকেন্ডের view জমিয়ে একবারে লেখা:

আগে: প্রতি view এ UPDATE দর্শক দর্শক দর্শক 3,333 / s videos: 'ফেরা' এর row view_count = view_count + 1 একটাই row এ lock এর লাইন shard বাড়ালেও লাভ নেই: hot key পরে: জমিয়ে গোনা Player 30 সেকেন্ড দেখলে view event Kafka: view topic session_id দিয়ে ছড়ানো Aggregator 5 সেকেন্ড ধরে memory তে যোগ 5 সেকেন্ডে একটা write view_count += 16,665
বাঁ দিকে প্রতিটা view একটা করে UPDATE, সব একই row এ। Row টা একবারে একজনই বদলাতে পারে, তাই বাকিরা লাইনে দাঁড়ায়। ডান দিকে view গুলো আগে Kafka তে জমা হয়। Aggregator ৫ সেকেন্ডের সব view memory তে যোগ করে, তারপর database এ একবারে লেখে: ৩,৩৩৩ × ৫ = ১৬,৬৬৫।
  1. ৩০ সেকেন্ড দেখা হলে player একটা ছোট view event পাঠায়।
  2. Event টা Kafka তে যায়। Kafka একটা লম্বা খাতার মতো: event গুলো আসার ক্রমে লেখা থাকে, আর অনেক reader একসাথে পড়তে পারে। Kafka আর event-driven design এর বিস্তারিত সেশন ১০ এ।
  3. কয়েকটা aggregator process event গুলো পড়ে। প্রত্যেকে ৫ সেকেন্ড ধরে memory তে গোনে: ‘ফেরা’ +১৬,৬৬৫, অন্য নাটক +১২।
  4. ৫ সেকেন্ড পর প্রতিটা aggregator প্রতিটা video এর জন্য database এ একটাই update চালায়।

ফলে ৩,৩৩৩টা write এর জায়গায় প্রতি ৫ সেকেন্ডে কয়েকটা write হয়। দর্শক যে সংখ্যা দেখেন, সেটা Redis cache থেকে আসে, আর কয়েক সেকেন্ড পুরোনো থাকে। Requirement এ আমরা এটা আগেই মেনে নিয়েছিলাম। সেশন ২৫ এ like গোনার সময়ও ঠিক এই কৌশলটাই দেখেছিলাম, এখানে শুধু সংখ্যাটা অনেক বড়।

একটা ছোট ফাঁদ আছে। Kafka তে event গুলোকে video_id দিয়ে ভাগ করলে ‘ফেরা’ এর সব event একটাই partition এ (Kafka topic এর একটা ভাগ, সেশন ১০) যাবে। সেই partition আর তার aggregator আবার hot হয়ে যাবে। তাই event গুলো session_id দিয়ে ছড়িয়ে দেওয়া হয়। প্রত্যেক aggregator ‘ফেরা’ এর একটা অংশ গোনে, আর database এ সবার যোগফল জমা হয়।

দুইটা আলাদা গণনা

শেষ কথা। Screen এ দেখানো সংখ্যাটা একটু পিছিয়ে থাকলে ক্ষতি নেই। কিন্তু মাস শেষে production house কে view অনুযায়ী টাকা দিতে হলে প্রতিটা view নির্ভুল হওয়া চাই। Bot দিয়ে বানানো ভুয়া view বাদ দিতে হয়। একই session থেকে আসা duplicate event একবারই গুনতে হয় (idempotency, সেশন ০৮)।

তাই “দেখো” দুইটা গণনা রাখে। দ্রুত গণনা চলে aggregator দিয়ে, শুধু দেখানোর জন্য। আর Kafka তে জমা সব event থেকে রাতে একটা আলাদা job নির্ভুল হিসাব করে, টাকার জন্য।

সংখ্যাটা কে দেখবে, সেটা আগে জানুন

View count এর মতো সংখ্যা দুই রকম কাজে লাগে। দর্শককে দেখানোর জন্য দ্রুত আর মোটামুটি ঠিক সংখ্যাই যথেষ্ট। টাকা দেওয়ার জন্য লাগে ধীর কিন্তু নির্ভুল সংখ্যা। দুটো কাজের জন্য দুটো পথ রাখলে কোনোটাতেই ছাড় দিতে হয় না।

০৯ Design টা কোথায় চাপে পড়ে, আর কী ছাড় দিলাম? (bottlenecks ও trade-offs)

পুরো ছবি

চারটা deep dive জোড়া লাগালে “দেখো” এর পুরো architecture এমন দাঁড়ায়:

CLIENT API / EDGE DATA WORKERS STORAGE Creator দর্শক (20 লাখ) segments Upload API pre-signed URL Play API metadata, heartbeat CDN Edge ISP cache, HIT ~99% job view event miss Queue transcode job Metadata DB sharded + Redis cache Kafka view topic Origin Shield miss এক করে Transcode Workers chunk করে, একসাথে Aggregator 5 s জমিয়ে যোগ READY view_count segments miss হলে Object Storage (origin) raw 1.8 GB + 5 rendition × 450 segment প্রতিটা নাটকের জন্য
পুরো system এক ছবিতে। বাঁ দিকের কলাম upload আর transcoding, মাঝের কলাম metadata আর view গোনা, ডান দিকের কলাম video পাঠানো। সবচেয়ে বেশি traffic যায় ডান দিকের highlight করা পথে, আর সেই পথের প্রায় সব request edge এই শেষ হয়ে যায়।

কোথায় চাপ পড়ে, আর কী দিয়ে সামলালাম

চাপের জায়গাকী হতে পারতোকী দিয়ে সামলালাম
রাত ৯টায় 3 Tbps egressOrigin আর তার network বসে যেতোISP এর ভেতরে edge, ৯৯% HIT
৯টা ০০ মিনিটে segment #1সব miss একসাথে origin এPre-warm আর request coalescing
দুর্বল mobile networkবারবার spinnerছোট segment আর ABR
৪৫ মিনিটের transcodingPremiere এর আগে video ready নাটুকরো করে অনেক worker এ, আর আগেভাগে upload
‘ফেরা’ এর metadata, সেকেন্ডে হাজারো readএকটা DB row এ hot keyRedis cache (সেশন ০৪)
‘ফেরা’ এর view countএকটা row এ সেকেন্ডে ৩,৩৩৩ writeKafka আর aggregator দিয়ে জমিয়ে লেখা

এই design আমাদের যা দিলো

  • 3 Tbps সামলানো যায়: প্রায় সব segment দর্শকের কাছের edge থেকে যায়, origin এ আসে শুধু miss।
  • দুর্বল network এও video চলে: ABR প্রতি ৬ সেকেন্ডে quality ঠিক করে নেয়, তাই spinner খুব কম দেখা যায়।
  • Upload আর দেখা একে অন্যকে আটকায় না: transcoding এর ভারী কাজ queue আর worker এ আলাদা চলে।
  • View গোনা database কে বসিয়ে দেয় না: ৩,৩৩৩টা write এর বদলে প্রতি ৫ সেকেন্ডে একটা write।
  • Video হারায় না: object storage নিজেই প্রতিটা file এর একাধিক copy রাখে।

Trade-off গুলো

  • Storage দ্বিগুণের বেশি: raw 1.8 GB এর পাশে আরো 2.25 GB rendition রাখতে হয়। মসৃণ playback পেতে বাড়তি জায়গা লাগে।
  • Upload এর পরেই দেখা যায় না: transcoding শেষ হতে কয়েক মিনিট লাগে। তাই premiere এর video আগেভাগে upload করতে হয়।
  • View count একটু পিছিয়ে থাকে: দর্শক যে সংখ্যা দেখেন, সেটা কয়েক সেকেন্ড পুরোনো (eventual consistency)।
  • Bandwidth ই সবচেয়ে বড় খরচ: ঈদের এক রাতের egress (প্রায় $68,000) সারা বছরে জমানো 1.5 PB video এক মাস রাখার খরচের (প্রায় $30,000) দ্বিগুণের বেশি।
  • চালানোর মতো অংশ অনেক: queue, worker, Kafka, aggregator, CDN চুক্তি; প্রতিটা আলাদাভাবে monitor করতে হয়।

ঈদের রাত, ৯টা বেজে ৩ মিনিট

নাবিলা অফিসের বড় screen এর সামনে বসে আছে। Dashboard এ একসাথে দর্শক ১৯ লাখ ৬০ হাজার। Edge এর hit rate ৯৮.৭%। Origin এর graph টা প্রায় সমতল, যেন কিছুই হচ্ছে না। ফাহিম ভাই পেছন থেকে চায়ের কাপ এগিয়ে দিলেন। ঠিক তখন phone এ খালার message এলো: “নাটকটা খুব সুন্দর হইছে। উঠানে বসেও একবারও আটকায় নাই।” নাবিলা এবার নিশ্চিন্তে চায়ে চুমুক দিলো।

১০ মগজে প্রেশার দিন

আগে নিজে ভাবুন। তারপর দেখুন: সবাই যেভাবে ভাবে, কেন সেটা অসম্পূর্ণ, আর আসল insight টা কোথায়।

প্রশ্ন ১: Interviewer বললেন, "একটা YouTube design করুন।" প্রথম পাঁচ মিনিট কী করবেন?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“প্রথমে একটা load balancer আঁকবো, তার পেছনে কয়েকটা app server, একটা database, আর video রাখার জন্য storage। তারপর scale এর জন্য cache আর CDN যোগ করবো।”

এখানে কোনো box ভুল নয়। কিন্তু শুরুটা ভুল জায়গা থেকে।

যে জায়গাটা যোগ করা দরকার

প্রথম পাঁচ মিনিট যায় প্রশ্ন করায়। কোন feature লাগবে আর কোনটা লাগবে না? কতজন user, কতগুলো upload? কোন অংশ ধীর হলে চলে? তারপর মোটামুটি হিসাব। এই সেশনে হিসাবটাই দেখিয়ে দিয়েছে যে আসল চাপ upload এ নয়, egress এ: ভেতরে আসে 167 Mbps, বাইরে যায় 3 Tbps। এই সংখ্যা জানার পর CDN আর ABR কে design এর কেন্দ্রে রাখার পক্ষে আপনার কাছে শক্ত যুক্তি থাকে।

মনে রাখার মতো

Box আঁকার আগে requirement আর হিসাব। হিসাবটাই বলে দেয়, interview এর বাকি সময় কোন অংশে খরচ করতে হবে।

প্রশ্ন ২: Video কে ৬ সেকেন্ডের segment এ কাটা হয় কেন? পুরো file একবারে পাঠালে সমস্যা কী?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“ছোট file তাড়াতাড়ি load হয়। তাই video তাড়াতাড়ি শুরু হয়।”

কথাটা ঠিক, কিন্তু segment এর আসল কাজের অর্ধেকও এতে আসেনি।

যে জায়গাটা যোগ করা দরকার

Segment এর সীমানাই হলো quality বদলানোর সুযোগ। পুরো 2 GB একটা file হলে network দুর্বল হওয়ার পর quality নামানোর কোনো উপায় থাকে না। ৬ সেকেন্ডের segment হলে player প্রতি ৬ সেকেন্ডে নতুন করে সিদ্ধান্ত নিতে পারে। তাছাড়া ছোট segment CDN এ সাধারণ file এর মতো cache হয়। মাঝখান থেকে দেখা শুরু করলে শুধু সেই জায়গার segment আনলেই চলে।

Segment এর দৈর্ঘ্যেও একটা trade-off আছে। খুব ছোট (১ সেকেন্ড) হলে request অনেক বেড়ে যায়, আর manifest লম্বা হয়। খুব বড় (৩০ সেকেন্ড) হলে quality বদলাতে দেরি হয়, আর video শুরু হতেও দেরি হয়। ২ থেকে ১০ সেকেন্ডের মধ্যে বেশিরভাগ platform এর পছন্দ।

মনে রাখার মতো

Segment শুধু ছোট file নয়। প্রতিটা segment এর সীমানায় player quality বদলানোর সুযোগ পায়। আর CDN প্রতিটা segment কে আলাদা file হিসেবে cache করে।

প্রশ্ন ৩: "View count এর জন্য Redis এর INCR ই যথেষ্ট, Kafka কেন?" এই দাবি কতটা ঠিক?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“Redis এর একটা node সেকেন্ডে লাখখানেক INCR সামলাতে পারে। ৩,৩৩৩ তো তার কাছে কিছুই না। তাই Kafka আর aggregator বাড়তি ঝামেলা।”

আংশিক ঠিক। শুধু screen এ সংখ্যা দেখানোর জন্য Redis এর একটা counter এই scale এ সত্যিই কাজ করবে।

যে জায়গাটা যোগ করা দরকার

প্রথমত, ঐ counter একটাই key, তাই সেটা থাকে একটাই Redis node এ। আরো বড় কোনো event এ, বা প্রতি ৩০ সেকেন্ডের heartbeat ও গুনতে চাইলে (২০ লাখ ÷ ৩০ ≈ সেকেন্ডে ৬৬,৬৬৭) সেই node টাই আবার hot key হয়ে যায়। দ্বিতীয়ত, Redis এর counter শুধু একটা সংখ্যা। কোন view bot এর, কোনটা duplicate, সেটা পরে আর যাচাই করা যায় না। টাকার হিসাবের জন্য প্রতিটা event এর রেকর্ড লাগে। Kafka সেই রেকর্ড রাখে, আর দরকার হলে আবার শুরু থেকে পড়ে হিসাব মেলানো যায়।

মনে রাখার মতো

দেখানোর জন্য Redis এর counter চলতে পারে। কিন্তু সত্যের উৎস হলো event এর রেকর্ড। Counter হারালে event থেকে আবার বানানো যায়, উল্টোটা যায় না।

১১ যে টার্মগুলো শিখলাম

টার্মমানে
Functional requirementSystem কী কী করবে: upload, দেখা, view count।
Non-functional requirementSystem কতটা ভালোভাবে করবে: কত দ্রুত, কত মানুষের জন্য, কতটা নির্ভরযোগ্যভাবে।
Back-of-envelope estimationকাগজে মোটামুটি হিসাব করে storage, bandwidth আর request এর মাপ বের করা। নিখুঁত সংখ্যা নয়, ঠিক মাপটা জানাই লক্ষ্য।
BitrateVideo এর প্রতি সেকেন্ডে কত bit data লাগে, যেমন 720p তে প্রায় 3 Mbps।
EgressServer থেকে বাইরে যাওয়া data। Cloud এ এর জন্য প্রতি GB টাকা দিতে হয়।
Object storageবিশাল file রাখার service (যেমন S3)। প্রতিটা file একটা key দিয়ে রাখা হয়, আর নিজেই একাধিক copy রাখে।
Pre-signed URLObject storage এর একটা অস্থায়ী link, যেটা দিয়ে অ্যাপ সরাসরি একটা নির্দিষ্ট file লিখতে বা পড়তে পারে।
Resumable uploadFile টুকরো করে পাঠানো, যাতে network কাটলে শুধু বাকি অংশটা পাঠাতে হয়।
CodecVideo ছোট করে রাখার নিয়ম, যেমন H.264।
Transcodingএকটা video কে অন্য codec, resolution বা bitrate এ নতুন করে encode করা।
Renditionএকই video এর একটা নির্দিষ্ট quality এর version, যেমন 720p।
Upload pipelineUpload থেকে READY পর্যন্ত ধাপগুলো: জমা নেওয়া, transcode, segment বানানো, প্রকাশ করা।
SegmentVideo এর ছোট একটা টুকরো, সাধারণত ২ থেকে ১০ সেকেন্ডের।
Manifestকোন quality আছে আর কোন segment কোন ক্রমে চলবে, তার তালিকা।
Adaptive bitrate (ABR)Network এর গতি মেপে player প্রতিটা segment এর quality নিজেই বেছে নেয়।
HLSApple এর বানানো streaming নিয়ম, manifest হয় .m3u8 file।
DASHআন্তর্জাতিক standard streaming নিয়ম, manifest হয় .mpd file।
Origin shieldEdge আর origin এর মাঝের cache স্তর, যেটা সব edge এর miss এক করে origin কে বাঁচায়।
Long tailকম জনপ্রিয় হাজার হাজার video, যাদের প্রত্যেকের view কম কিন্তু সংখ্যায় অনেক।
Pre-warmচাওয়ার আগেই জনপ্রিয় content edge এ পৌঁছে দেওয়া।
Request coalescingএকই জিনিসের অনেকগুলো miss এক করে origin এ একবারই যাওয়া।
AggregatorEvent গুলো কিছুক্ষণ memory তে জমিয়ে যোগ করে, তারপর database এ একবারে লেখে।

১২ শর্ট সামারি

  1. Case study শুরু হয় requirement আর back-of-envelope estimation দিয়ে। “দেখো” এর হিসাব দেখিয়েছে, upload এ ভেতরে আসে মাত্র 167 Mbps কিন্তু ঈদের রাতে egress 3 Tbps, তাই design এর কেন্দ্র হলো দেখার পথ।
  2. Upload হওয়া video queue আর worker দিয়ে asynchronous ভাবে transcode হয়। একটা raw file থেকে পাঁচটা rendition তৈরি হয়, প্রতিটা ৬ সেকেন্ডের segment এ কাটা হয়, আর manifest এ তালিকা থাকে।
  3. Adaptive bitrate এ player প্রতিটা segment এর আগে network মেপে quality বেছে নেয়। HLS আর DASH এই কাজের দুইটা প্রচলিত নিয়ম, আর segment সাধারণ HTTP file বলে CDN সহজেই cache করে।
  4. জনপ্রিয় video premiere এর আগেই ISP এর ভেতরের edge এ পৌঁছে যায়, long-tail video আসে shield আর origin থেকে। আর view গোনা হয় Kafka আর aggregator দিয়ে জমিয়ে, যাতে একটা row এ হাজারো write না পড়ে।

১৩ মনে রাখুন