---
title: 'Video Yayın Servisi'
source: 'https://academia.sh/tr/kurslar/vaka-calismalari/video-yayin-servisi'
course: 'Vaka Çalışmaları'
language: tr
updated: '2026-08-17T18:10:55+00:00'
license: 'CC BY-SA 4.0'
---

# 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.

Ö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

```js
// 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.

```js
// 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.
