İçeriğe geç
academia.sh

Ders 11 / 14

Video Yayın Servisi

Aynı içeriğin birden çok temsilinin tutulduğu vaka: kodlama boru hattının işlemci-saniye ile bütçelenmesi, kalite basamaklarının izleyici bant genişliği dağılımı üzerinde ölçülmesi, basamak başına kazanılan bant kullanımının azalması ve üç ayrı kısıtın üç ayrı merdiveni elemesi.

İçindekiler

Önceki vakada nesne, servis için anlamsız bir bayt dizisiydi: yazıldığı gibi saklandı, okunduğu gibi verildi. Bu vaka o varsayımı kaldırır. Yüklenen dosya bir kez saklanmaz; içeriğinden birden çok temsil üretilir ve hangi temsilin verileceği isteği yapanın o andaki bandına göre belirlenir. Yeni kalem kodlama boru hattıdır (transcoding pipeline) ve yeni ödünleşim uyarlanabilir akışın (adaptive streaming) kaç kalite basamağı (bitrate ladder) taşıyacağıdır.

Ölçülecek karar şu: her basamak hem saklanan bayta hem de işlemci-saniyeye mal olur, ama karşılığı izleyicinin bandına daha iyi uyan bir akıştır. Basamak sayısı bu iki eğrinin kesiştiği yerde seçilir ve kesişme noktası izleyici bandının dağılımına bağlıdır.

Kısıtlar

İşlevsel gereksinim: yüklenen kaynak kopyadan birden çok kalite basamağı üretme, her basamağı sabit süreli parçalara bölme, parça listesini istemciye verme ve istemcinin basamaklar arasında geçmesine izin verme.

İşlevsel olmayan gereksinim, sayıyla: bandı en düşük basamağı taşımadığı için oynatamayan izleyici oranı yüzde 10’un altında kalır; saklanan bayt kaynak kopyanın 2,5 katını geçmez; kodlamaya sürekli ayrılan işlemci 1500’ü geçmez; bir saatlik videonun yüklemeden izlenebilir olmaya geçmesi 10 dakikayı aşmaz.

Kapsam daraltması: içerik koruma, canlı yayın, öneri, altyazı üretimi ve reklam yerleştirme tasarlanmaz.

Varsayımlar

Kod Varsayım Değer Gerekçe
VY1 günlük yüklenen video saati 4.000 yükleyenlerin günlük toplamı
VY2 kaynak kopyanın bit hızı 20.000 kbit/s kodlanmamış yükleme
VY3 günlük izlenen saat 900.000 izleme yüklemeden çok daha yoğun
VY4 tepe çarpanı 3 tepe saatin gün ortalamasına oranı
VY5 saklama süresi 365 gün katalog bir yıl tutulur
VY6 kodlama maliyeti 0,4 + 0,25 × Mbit/s video-saniye başına işlemci-saniye
VY7 izleyici bandı dağılımı 0,25/1,5 + 0,50/6 + 0,25/20 üç sınıflı karışım, üstel, Mbit/s
VY8 bandın kullanılabilir payı 0,8 protokol yükü ve dalgalanma payı
VY9 parça süresi 4 s basamak değişimi bu tanecikte olur
VY10 kenar önbelleği isabet oranı 0,95 parçalar değişmez, uzun tutulur

VY6 ve VY7 bu tasarımın iki taşıyıcı varsayımıdır: biri üretim maliyetini, öteki isabeti belirliyor. İkisi de gerekçelidir, ölçüm değildir.

Ölçek

// video-olcek.mjs — VY tablosundan cikan olcek hesabi; hepsi aritmetiktir
const VY = { yuklenenSaat: 4000, kaynakKbit: 20_000, izlenenSaat: 900_000, saklamaGun: 365,
  sabitCpu: 0.4, kbitBasinaCpu: 0.25, parcaSn: 4 };
const BASAMAK = [400, 1200, 3000, 6000, 12_000];          // secilen kalite basamaklari, kbit/s
const toplam = BASAMAK.reduce((a, b) => a + b, 0);
const cpu = BASAMAK.reduce((a, k) => a + VY.sabitCpu + VY.kbitBasinaCpu * (k / 1000), 0);
const videoSn = VY.yuklenenSaat * 3600;
for (const [ad, d] of [
  ["izlenen / yuklenen saat", VY.izlenenSaat / VY.yuklenenSaat],
  ["basamak toplami kbit/s", toplam],
  ["kodlama islemci-sn / video-sn", cpu],
  ["gunluk saklanan TB", (videoSn * (VY.kaynakKbit + toplam) * 1000) / 8 / 1e12],
  ["yil sonu saklanan PB", (videoSn * (VY.kaynakKbit + toplam) * 1000 * VY.saklamaGun) / 8 / 1e15],
  ["gunluk uretilen parca", (videoSn / VY.parcaSn) * BASAMAK.length],
]) console.log(ad.padEnd(30) + d.toFixed(2).padStart(14));

console.log(`\nbir saatlik video ${(3600 * cpu).toFixed(0)} islemci-sn ister:`);
for (const n of [30, 60, 120])
  console.log(`  ${n} isci -> yukleme-izlenebilirlik ${((3600 * cpu) / n / 60).toFixed(2)} dk`);
izlenen / yuklenen saat               225.00
basamak toplami kbit/s              22600.00
kodlama islemci-sn / video-sn           7.65
gunluk saklanan TB                     76.68
yil sonu saklanan PB                   27.99
gunluk uretilen parca            18000000.00

bir saatlik video 27540 islemci-sn ister:
  30 isci -> yukleme-izlenebilirlik 15.30 dk
  60 isci -> yukleme-izlenebilirlik 7.65 dk
  120 isci -> yukleme-izlenebilirlik 3.83 dk

Bu sayılar hesap sınıfındadır. Üçü tasarımı belirliyor. Her yüklenen saat 225 saat izleniyor: bir kez ödenen kodlama maliyeti iki yüz yirmi beş kez okunuyor, bu yüzden içeriği izleme anında değil yükleme anında hazırlamak baştan makul görünüyor. Günde 18.000.000 parça üretiliyor — dağıtım katmanının gördüğü nesne sayısı budur, video sayısı değil. Ve son satır bir kısıtı doğrudan karşılıyor: 10 dakikalık gecikme kısıtı en az 46 işçi ister; 30 işçiyle 15,30 dakikaya çıkıp kısıt çiğneniyor, 60 işçiyle 7,65 dakika kalıyor.

Basamak Seçimi

Basamak sayısı ancak izleyici bandının dağılımı verildiğinde savunulabilir. Aşağıdaki model bir ağ kurmaz, kodlayıcı çalıştırmaz: VY7’nin üç sınıflı karışımından bant çeker, her izleyicinin kullanılabilir bandına sığan en yüksek basamağı seçer ve dört merdiveni aynı izleyici kümesi üzerinde karşılaştırır.

// basamak.mjs — surec ici model: izleyici bant genisligi dagilimindan basamak seciminin
// isabeti. Ag yok, kodlayici yok; dagilim uc sinifli bir karisimdir ve model oldugu yazilir.
const IZLEYICI = 200_000, TOHUM = 20260731, PAY = 0.8;       // VY8: bandin kullanilabilir payi
const SINIF = [[0.25, 1500], [0.50, 6000], [0.25, 20_000]];  // VY7: pay, ortalama kbit/s
const KAYNAK = 20_000, SABIT = 0.4, KBIT_CPU = 0.25;         // VY2, VY6
const IZLENEN_SAAT = 900_000, TEPE = 3, ISABET = 0.95;       // VY3, VY4, VY10
const YUKLENEN_SN = 4000 * 3600;                             // VY1: gunluk kodlanan video-saniye

let durum = TOHUM;
const rast = () => { durum = (durum * 1103515245 + 12345) % 2147483648; return durum / 2147483648; };
function bant() {                                            // sinif sec, ustel dagilimdan cek
  let u = rast(), i = 0;
  while (i < SINIF.length - 1 && u > SINIF[i][0]) { u -= SINIF[i][0]; i += 1; }
  return -Math.log(1 - rast()) * SINIF[i][1];
}
const bantlar = Array.from({ length: IZLEYICI }, bant);

const MERDIVEN = { "1 basamak": [3000], "3 basamak": [800, 3000, 9000],
  "5 basamak": [400, 1200, 3000, 6000, 12_000],
  "8 basamak": [300, 600, 1000, 1800, 3000, 5000, 8000, 12_000] };

function olc(m) {
  let oynamayan = 0, secilenToplam = 0, kullanimToplam = 0;
  for (const b of bantlar) {
    const kullanilabilir = b * PAY;
    const s = m.filter((k) => k <= kullanilabilir).pop();
    if (s === undefined) { oynamayan += 1; continue; }
    secilenToplam += s; kullanimToplam += s / kullanilabilir;
  }
  const oynayan = IZLEYICI - oynamayan;
  const toplamKbit = m.reduce((a, b) => a + b, 0);
  return { oynamayan: oynamayan / IZLEYICI, ortSecilen: secilenToplam / oynayan,
    kullanim: kullanimToplam / oynayan, saklama: (KAYNAK + toplamKbit) / KAYNAK,
    cpu: m.reduce((a, k) => a + SABIT + KBIT_CPU * (k / 1000), 0) };
}

console.log(`model: ${IZLEYICI} izleyici, tohum ${TOHUM}, sinif paylari ` +
  `${SINIF.map(([p, o]) => `${p}/${o}`).join(" ")} kbit/s (ustel)\n`);
console.log("merdiven".padEnd(11) + "oynamayan".padStart(11) + "ort secilen".padStart(13) +
  "bant kullanimi".padStart(16) + "saklama kati".padStart(14) + "surekli islemci".padStart(17) +
  "tepe uc Gbit/s".padStart(16) + "koken Gbit/s".padStart(14));
const R = {};
for (const [ad, m] of Object.entries(MERDIVEN)) {
  const r = olc(m);
  R[ad] = r;
  const uc = (IZLENEN_SAAT * 3600 * r.ortSecilen * 1000 / 86_400) * TEPE / 1e9;
  console.log(ad.padEnd(11) + `%${(r.oynamayan * 100).toFixed(2)}`.padStart(11) +
    r.ortSecilen.toFixed(0).padStart(13) + `%${(r.kullanim * 100).toFixed(1)}`.padStart(16) +
    r.saklama.toFixed(2).padStart(14) + ((YUKLENEN_SN * r.cpu) / 86_400).toFixed(0).padStart(17) +
    uc.toFixed(2).padStart(16) + (uc * (1 - ISABET)).toFixed(2).padStart(14));
}

const k = Object.keys(MERDIVEN);
console.log("\nbasamak basina kazanilan bant kullanimi:");
for (let i = 1; i < k.length; i += 1) {
  const d = MERDIVEN[k[i]].length - MERDIVEN[k[i - 1]].length;
  console.log(`  ${k[i - 1]} -> ${k[i]}: ${(((R[k[i]].kullanim - R[k[i - 1]].kullanim) * 100) / d).toFixed(2)} puan/basamak`);
}
const kapali = olc([400, 1200, 3000, 6000]);                         // tepe basamak kapatilirsa
console.log(`tepe basamak kapali: ort secilen ${kapali.ortSecilen.toFixed(0)} kbit/s, uc cikisi ` +
  `x${(kapali.ortSecilen / R["5 basamak"].ortSecilen).toFixed(2)}, oynamayan ayni %${(kapali.oynamayan * 100).toFixed(2)}`);
const ozelCpu = IZLENEN_SAAT * 3600 * (SABIT + KBIT_CPU * 6);        // izleyici basina tek akis
const merdivenCpu = YUKLENEN_SN * R["5 basamak"].cpu;
console.log(`izleyiciye ozel kodlama: ${ozelCpu.toExponential(2)} islemci-sn/gun, 5 basamagin ` +
  `${(ozelCpu / merdivenCpu).toFixed(1)} kati (${(merdivenCpu).toExponential(2)})`);
model: 200000 izleyici, tohum 20260731, sinif paylari 0.25/1500 0.5/6000 0.25/20000 kbit/s (ustel)

merdiven     oynamayan  ort secilen  bant kullanimi  saklama kati  surekli islemci  tepe uc Gbit/s  koken Gbit/s
1 basamak       %45.75         3000           %43.2          1.15              192          337.50         16.88
3 basamak       %13.77         3846           %56.5          1.64              733          432.71         21.64
5 basamak        %8.91         4442           %64.9          2.13             1275          499.72         24.99
8 basamak        %6.08         4607           %73.8          2.58             1854          518.24         25.91

basamak basina kazanilan bant kullanimi:
  1 basamak -> 3 basamak: 6.66 puan/basamak
  3 basamak -> 5 basamak: 4.22 puan/basamak
  5 basamak -> 8 basamak: 2.96 puan/basamak
tepe basamak kapali: ort secilen 3242 kbit/s, uc cikisi x0.73, oynamayan ayni %8.91
izleyiciye ozel kodlama: 6.16e+9 islemci-sn/gun, 5 basamagin 55.9 kati (1.10e+8)

Tablodaki oranlar ölçüm, maliyet sütunları hesap sınıfındadır; ölçülen oranlar bu koşumun tohumuna bağlıdır, kısıtları ayıran farklar ise tohumdan bağımsız büyüklüktedir. Basamak başına kazanılan bant kullanımı 6,66’dan 4,22’ye, oradan 2,96 puana düşüyor: her yeni basamak bir öncekinden daha az kazandırıyor, ama maliyeti daha az düşmüyor.

Tasarım

Ölçüm beş basamaklı merdiveni işaret ediyor; tasarım onun üstüne kurulur. Kodlama boru hattı bir mesaj kuyruğu ve rekabet eden tüketiciler üzerine oturur (Uygulama Katmanı ve Servis Etkileşimi kursunun Kuyruklar ve İş Akışları konusu). Parametre işçi sayısıdır: 60 işçi bir saatlik videoyu 7,65 dakikada izlenebilir yapar. Aynı konudaki öncelikli kuyruk yeni yüklemeyi geri dolduran yeniden kodlama işlerinin önüne alır; bu, gecikme kısıtının yalnız yeni yüklemeler için geçerli olmasını sağlar. İş iletisi baytları taşımaz, kaynak nesnenin anahtarını taşır — talep fişi kalıbı (Dayanıklılık ve Güvenilirlik kursunun Dağıtık Doğruluk konusu). Kodlama işi etkisizdir (aynı konu); tekillik anahtarı video kimliği ile basamağın ikilisidir, böylece yarıda kalan iş yeniden sürüldüğünde ikinci bir çıktı üretmez.

Dağıtım tarafı içerik dağıtım ağı ve kenar önbelleği üzerine kurulur (Trafik Katmanı kursunun Giriş Noktaları konusu). Parametre isabet oranıdır: VY10’un yüzde 95’i tepe uçtaki 499,72 Gbit/s’yi kökende 24,99 Gbit/s’ye indiriyor. Parçalar üretildikten sonra hiç değişmediği için bayatlık penceresi diye bir soru yok; aynı konudaki itme tabanlı dağıtım yeni yüklenen içeriğin ilk parçalarını izlenmeden önce kenara taşır, gerisi çekmeyle gelir. Parça listesi ve parçalar statik dosyalardır (aynı konu, Statik İçerik Barındırma), bu yüzden okuma yolunda uygulama kodu yok.

Bilerek kullanılmayan kalıp: devre kesici. Dayanıklılık ve Güvenilirlik kursunun Arıza Yalıtımı konusundaki devre kesici kodlama katmanına konmaz, çünkü işçiler senkron çağrı yapmaz; kuyruktan çeker ve başarısız işi yeniden görünür kılar — kesilecek bir çağrı yolu yoktur. İkincisi komut ve sorgu sorumluluğu ayrımıdır (Veri Katmanı Ölçekleme kursunun Okuma–Yazma Ayrımı konusu): okuma yolu bir sorgu değil, adı önceden bilinen bir dosyanın getirilmesidir ve ayrı bir okuma modeli türetmenin karşılığı yoktur.

Elenen Alternatifler

Üç alternatif üç ayrı sayıyla eleniyor ve her biri farklı bir kısıta takılıyor.

Tek basamak en ucuzudur: saklama katı 1,15, sürekli 192 işlemci. Ama izleyicilerin yüzde 45,75’i o tek basamağı taşıyamıyor ve hiç oynatamıyor — yüzde 10 kısıtının dört buçuk katı. Üç basamak da yüzde 13,77 ile kısıtın üstünde kalıyor.

Sekiz basamak isabet tarafında en iyisidir: bant kullanımı yüzde 73,8, oynatamayan yüzde 6,08. İki kısıtı birden çiğniyor: saklama katı 2,58 (sınır 2,5) ve sürekli 1854 işlemci (sınır 1500). Kazandığı 8,9 puanlık kullanım, saklamada yüzde 21, işlemcide yüzde 45 fazla ödemeye mal oluyor.

İzleyiciye özel kodlama — her akışı izleyicinin bandına tam uyduracak biçimde anlık üretmek — isabet sorununu tamamen çözer, çünkü kullanım yüzde 100 olur ve fazladan basamak saklanmaz. Günde 6,16 milyar işlemci-saniye ister; beş basamaklı merdivenin 110 milyon işlemci-saniyesinin 55,9 katı. Sebep ölçek hesabındaki ilk satırdır: kodlama yükleme başına bir kez değil, izleme başına bir kez ödenir ve izleme yüklemenin 225 katıdır.

Geriye beş basamak kalıyor: oynatamayan yüzde 8,91, saklama katı 2,13, sürekli 1275 işlemci — üç kısıt da karşılanıyor. Hangi kısıt değişirse alternatif kazanır: saklama sınırı 2,6’ya çıkarılırsa sekiz basamak girer ve bant kullanımını 8,9 puan artırır; izleyici bandı dağılımı daralırsa (üç sınıf birbirine yaklaşırsa) az basamak yeter ve üç basamak kısıtı karşılamaya başlar.

Arıza Davranışı ve Feda Edilen

Kodlama katmanı tümüyle düştüğünde katalog izlenmeye devam eder; yalnız yeni yüklemeler izlenebilir olmaz ve kuyrukta birikir. Bu zarif bozulmadır (Arıza Yalıtımı konusu) ve maliyeti gecikme kısıtının askıya alınmasıdır. Köken düştüğünde kenar önbelleği isteklerin yüzde 95’ini karşılamayı sürdürür, çünkü parçalar değişmezdir ve bayat sunum diye bir risk yoktur. Çıkış tarafında tepe yük sınırı zorladığında en üst basamak kapatılır: ortalama seçilen bit hızı 4442’den 3242 kbit/s’ye, uçtaki çıkış 0,73 katına iner ve oynatamayan izleyici oranı yüzde 8,91’de değişmeden kalır — yani bozulma kaliteyi düşürür, kimseyi dışarıda bırakmaz.

Feda edilen: bant kullanımı yüzde 64,9’da bırakıldı. İzleyicinin kullanılabilir bandının üçte biri boşta duruyor ve bu, saklamayı 2,5 katın, kodlamayı 1500 işlemcinin altında tutmanın bedelidir.

Özet

  • Yüklenen her saat 225 saat izleniyor; kodlama maliyetinin izleme anında değil yükleme anında ödenmesinin gerekçesi bu orandır ve izleyiciye özel kodlamayı 55,9 kat pahalı yapan da odur.
  • Kalite basamaklarının isabeti ancak izleyici bandı dağılımıyla birlikte ölçülebilir: beş basamakta bant kullanımı yüzde 64,9, oynatamayan izleyici yüzde 8,91.
  • Basamak başına kazanılan kullanım 6,66’dan 4,22’ye, oradan 2,96 puana düşerken maliyet basamak başına düşmüyor; merdivenin sonu bu yüzden vardır.
  • Üç alternatif üç ayrı kısıtla elenir: tek basamak oynatamayan oranıyla (yüzde 45,75), sekiz basamak saklama (2,58) ve işlemci (1854) sınırlarıyla, izleyiciye özel kodlama işlemci-saniyeyle.
  • Kenar önbelleği çıkışı 499,72 Gbit/s’den 24,99 Gbit/s’ye indiriyor ve parçalar değişmez olduğu için bayatlık penceresi tartışması hiç açılmıyor.

Sonraki Adım

Bu vakada da veri yazıldığı gibi saklandı: bir parça üretildi, bir yere kondu ve sonra aynen okundu. Üretilen her bayt saklanmaya değerdi. Sonraki vaka bu varsayımı kaldırır. Orada kayıtlar saniyede yüz binlerce üretilir, tek tek hiçbiri anlamlı değildir ve hepsini saklamak imkânsızdır. Soru şuna dönüşür: hangi kayıt ne kadar süreyle ham tutulur, ne zaman toplulaştırılır ve toplulaştırılmış veriden okunan yanıt ham veriden okunandan ne kadar sapar.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat