---
title: 'Haber Akışı'
source: 'https://academia.sh/tr/kurslar/vaka-calismalari/haber-akisi'
course: 'Vaka Çalışmaları'
language: tr
updated: '2026-08-17T18:10:56+00:00'
license: 'CC BY-SA 4.0'
---

# Haber Akışı

Aynı akışın iki dağıtım modeliyle kurulması: yazmada dağıtma ile okumada toplamanın iş miktarının ölçülmesi, takipçi dağılımının ucunun ortalamayla yapılan hesabı yanıltması, karma modelin eşiğinin dağıtım kapasitesi ile görünme penceresinden bir sayı olarak türetilmesi ve dağıtım tüketicisi yavaşladığında pencerenin aşılma anının hesaplanması.

Önceki vakada okumanın yanıtı tek bir kayıttı: anahtar verilir, hedef döner. Bu vakada okuma oranı
benzer kalır ama yanıt değişir — **haber akışı** çok sayıda kaynaktan derlenmiş sıralı bir listedir.
Soru bu yüzden "kaydı nerede önbelleğe alayım" olmaktan çıkar ve şuna döner: liste **ne zaman**
derlenir? İki seçenek vardır — **yazmada dağıtma**, gönderiyi yayımlandığı anda her takipçinin
kutusuna yazar; **okumada toplama**, akış istendiği anda takip edilen hesapların gönderilerini
birleştirir. Bu ders ikisinin iş miktarını ölçer ve karma modelin eşiğini bir sayı olarak verir.

## Kısıtlar

**İşlevsel gereksinimler.** I1: kullanıcı gönderi yayımlar. I2: kullanıcı, takip ettiklerinin
gönderilerini zamana göre sıralı olarak ister. I3: kullanıcı takip eder ve takibi bırakır. I4:
silinen gönderi akışta görünmez.

**Kapsam daraltması.** İlgi puanına göre sıralama, ortam dosyaları, bildirim ve arama bu tasarımın
dışındadır; sıralama modeli akışın **içeriğini** değiştirir, dağıtım kararını değil.

| Kod | Eşik | Eşiğin kaynağı |
|---|---|---|
| G1 | akışın ilk sayfası (20 gönderi) 200 ms'de döner | akış açılışında beklenen ilk görüntü |
| G2 | yayımlanan gönderi takipçi akışında 60 saniye içinde görünür | akışın canlı sayılması |
| G3 | akış kutusu deposu 20 GB'yi geçmez | kutunun bellekte tutulması |

## Varsayımlar

| Kod | Varsayım | Değer | Gerekçe |
|---|---|---|---|
| VH1 | günlük etkin kullanıcı | 1.000.000 | akışı günde en az bir kez açan kullanıcı |
| VH2 | kullanıcı başına günlük gönderi | 0,2 | çoğu kullanıcı okur, azı yazar |
| VH3 | kullanıcı başına günlük akış isteği | 8 | akış gün içinde birkaç kez tazelenir |
| VH4 | tepe çarpanı | 3 | tepe saatteki hızın gün ortalamasına oranı |
| VH5 | takipçi dağılımı | taban 33, üs 1,16 | takipçi az sayıda hesapta yoğunlaşır; üs kuyruğun kalınlığıdır |
| VH6 | kutuda tutulan girdi | 400 | yirmi sayfalık geçmiş yeter, gerisi gönderi deposundan gelir |
| VH7 | kutu girdisi | 32 bayt | gönderi kimliği ve zaman damgası |

VH5 bir sayı değil bir **dağılımdır**; ortalaması modelden çıkar ve bir varsayım olarak
seçilmemiştir. Bir hesabın takipçi sayısı kullanıcı sayısını geçemez, model bu tavanı uygular.

## Kabaca Büyüklük Hesabı ve İki Modelin İş Miktarı

```js
// akis/hesap.mjs — VH1–VH7'den cikan hesap ve iki dagitim modelinin is miktari.
// Takipci dagilimi kendi yazilmis uretecle uretilir (tohum sabit), tavan kullanici sayisidir. MODELDIR.
const VH = { kullanici: 1_000_000, gonderi: 0.2, akisIstegi: 8, tepe: 3, taban: 33, us: 1.16, kutuGirdi: 400, girdiBayt: 32 };
const GUN = 86_400;
const gonderiTepe = (VH.kullanici * VH.gonderi / GUN) * VH.tepe;
const akisTepe = (VH.kullanici * VH.akisIstegi / GUN) * VH.tepe;

let s = 20260730 % 2147483647;
const rast = () => (s = (s * 48271) % 2147483647) / 2147483647;
const takipci = new Float64Array(VH.kullanici);
let tavanda = 0;
for (let i = 0; i < VH.kullanici; i += 1) {
  const v = Math.round(VH.taban * Math.pow(rast(), -1 / VH.us));
  if (v > VH.kullanici - 1) tavanda += 1;
  takipci[i] = Math.min(VH.kullanici - 1, v);
}
const toplamBag = takipci.reduce((a, b) => a + b, 0), ortalama = toplamBag / VH.kullanici;
const sirali = Float64Array.from(takipci).sort();
const y = (p) => sirali[Math.floor(p * VH.kullanici)];
const ustPay = sirali.slice(VH.kullanici - VH.kullanici / 1000).reduce((a, b) => a + b, 0) / toplamBag;

const b = (x, n = 2) => x.toFixed(n);
console.log(`tepe gonderi/s = ${b(gonderiTepe)}   tepe akis istegi/s = ${b(akisTepe)}   okuma/yazma orani = ${b(akisTepe / gonderiTepe)}`);
console.log(`kutu deposu = ${b(VH.kullanici * VH.kutuGirdi * VH.girdiBayt / 1e9)} GB (kullanici basina ${VH.kutuGirdi} girdi)`);
console.log(`\ntakipci dagilimi: ortalama ${b(ortalama)}  p50 ${y(0.5)}  p90 ${y(0.9)}  p99 ${y(0.99)}  ` +
  `p99,9 ${y(0.999)}  en buyuk ${sirali[VH.kullanici - 1]}  tavandaki hesap ${tavanda}`);
console.log(`en ustteki binde birlik dilim baglantilarin ${b(ustPay, 4)}'ini tutuyor`);

const yazmaIs = gonderiTepe * ortalama, okumaIs = akisTepe * ortalama;
console.log(`\n${"model".padEnd(20)}${"yazma basina is".padStart(17)}${"okuma basina is".padStart(17)}${"tepede is/s".padStart(14)}`);
console.log(`${"yazmada dagitma".padEnd(20)}${b(ortalama).padStart(17)}${"1.00".padStart(17)}${b(yazmaIs + akisTepe).padStart(14)}`);
console.log(`${"okumada toplama".padEnd(20)}${"1.00".padStart(17)}${b(ortalama).padStart(17)}${b(okumaIs + gonderiTepe).padStart(14)}`);
console.log(`oran = ${b((okumaIs + gonderiTepe) / (yazmaIs + akisTepe))}`);

const iki = ((VH.kullanici * VH.akisIstegi * 2 / GUN) * VH.tepe) * ortalama;
console.log(`\nVH3 duyarliligi: gunluk akis istegi 8 -> 16 ise okumada toplama ${b(okumaIs)} -> ${b(iki)} is/s, ` +
  `yazmada dagitma ${b(yazmaIs)} is/s degismiyor`);
```

```
tepe gonderi/s = 6.94   tepe akis istegi/s = 277.78   okuma/yazma orani = 40.00
kutu deposu = 12.80 GB (kullanici basina 400 girdi)

takipci dagilimi: ortalama 203.63  p50 60  p90 241  p99 1763  p99,9 12474  en buyuk 999999  tavandaki hesap 7
en ustteki binde birlik dilim baglantilarin 0.2753'ini tutuyor

model                 yazma basina is  okuma basina is   tepede is/s
yazmada dagitma                203.63             1.00       1691.87
okumada toplama                  1.00           203.63      56570.71
oran = 33.44

VH3 duyarliligi: gunluk akis istegi 8 -> 16 ise okumada toplama 56563.76 -> 113127.53 is/s, yazmada dagitma 1414.09 is/s degismiyor
```

Üç sayı kararı taşıyor. Birincisi oran: aynı akış yazmada dağıtmayla tepede 1691,87, okumada
toplamayla 56.570,71 iş/s istiyor — **33,44 kat**. Fark okuma/yazma oranının kendisidir; iş, hangi
tarafta çoğaltılırsa o tarafın hızıyla çarpılır ve okuma tarafı kırk kat daha sık koşar. İkincisi
kutu deposu 12,80 GB, G3'ün 20 GB'lik eşiğinin altında. Üçüncüsü duyarlılık: akış isteği ikiye
katlandığında okumada toplama 113.127,53'e çıkarken yazmada dağıtma 1414,09'da kalıyor. Yazmada
dağıtma **okuma hacminden bağımsızdır**; asıl özelliği budur.

Dağılım satırı bir uyarı taşıyor. Ortalama 203,63 ama ortanca 60, yüzde 99,9'luk değer 12.474 ve en
büyük hesap tavanda. En üstteki binde birlik dilim bağlantıların 0,2753'ünü tutuyor. Ortalamayla
yapılan hesap kararlı hızı doğru veriyor, ama tek bir gönderinin ne istediğini hiç göstermiyor.

## Karma Modelin Eşiği

```js
// akis/karma.mjs — karma modelin esigi: esigin ustundeki hesaplar okuma aninda toplanir.
// Ayni dagilim ureteci ve ayni tohum; takip olasiligi populerlikle orantili kabul edilir. MODELDIR.
const VH = { kullanici: 1_000_000, gonderi: 0.2, akisIstegi: 8, tepe: 3, taban: 33, us: 1.16 };
const GUN = 86_400, PENCERE = 60;                       // PENCERE: G2 esigi
const gonderiTepe = (VH.kullanici * VH.gonderi / GUN) * VH.tepe;
const akisTepe = (VH.kullanici * VH.akisIstegi / GUN) * VH.tepe;

let s = 20260730 % 2147483647;
const rast = () => (s = (s * 48271) % 2147483647) / 2147483647;
const takipci = new Float64Array(VH.kullanici);
for (let i = 0; i < VH.kullanici; i += 1)
  takipci[i] = Math.min(VH.kullanici - 1, Math.round(VH.taban * Math.pow(rast(), -1 / VH.us)));
const sirali = Float64Array.from(takipci).sort();
const ortalama = sirali.reduce((a, b) => a + b, 0) / VH.kullanici;

// Esigin altinda kalan baglantilar yazmada dagitilir, ustundekiler okumada toplanir.
function is(esik) {
  let alt = 0, ust = 0, enBuyukAlt = 0, ustHesap = 0;
  for (const f of sirali) {
    if (f <= esik) { alt += f; enBuyukAlt = f; } else { ust += f; ustHesap += 1; }
  }
  return { yazma: gonderiTepe * (alt / VH.kullanici), okuma: akisTepe * (ust / VH.kullanici), enBuyukAlt, ustHesap };
}

const b = (x, n = 2) => x.toFixed(n);
const tamYazma = is(VH.kullanici), KAPASITE = 3 * tamYazma.yazma;    // kapasite kararli hizin uc kati kurulur
const ESIK = Math.round(PENCERE * (KAPASITE - tamYazma.yazma));      // tek gonderiye kalan pay penceredeki paydir
console.log(`kararli yazma hizi = ${b(tamYazma.yazma)} kutu yazmasi/s, kapasite ${b(KAPASITE)}/s, ` +
  `tek gonderiye kalan ${b(KAPASITE - tamYazma.yazma)}/s -> ${PENCERE} s penceresinde esik = ${ESIK.toLocaleString("tr-TR")} takipci`);
console.log(`\n${"esik".padStart(9)}${"ustteki hesap".padStart(15)}${"yazma is/s".padStart(13)}${"okuma is/s".padStart(13)}` +
  `${"toplam is/s".padStart(14)}${"en buyuk patlama/s".padStart(20)}`);
for (const e of [1000, 10_000, 84_846, ESIK, VH.kullanici]) {
  const r = is(e);
  console.log(`${e.toLocaleString("tr-TR").padStart(9)}${String(r.ustHesap).padStart(15)}${b(r.yazma).padStart(13)}` +
    `${b(r.okuma).padStart(13)}${b(r.yazma + r.okuma).padStart(14)}${b(r.enBuyukAlt / PENCERE).padStart(20)}`);
}

const secilen = is(ESIK);
console.log(`\nsecilen esikte: ustteki ${secilen.ustHesap} hesap okuma aninda toplaniyor, ` +
  `akis istegi basina ${b(secilen.okuma / akisTepe, 3)} ek kaynak, toplam is ${b(secilen.yazma + secilen.okuma)}/s`);
console.log(`esiksiz tasarimda en buyuk tek gonderi ${b(sirali[VH.kullanici - 1] / PENCERE)} kutu yazmasi/s istiyor = ` +
  `kararli hizin ${b(sirali[VH.kullanici - 1] / PENCERE / tamYazma.yazma)} kati`);

// Dagitim tuketicisi yavaslarsa: birikim / kapasite, G2 penceresini ne zaman asar.
console.log(`\n${"tuketici kapasitesi".padEnd(21)}${"birikim/s".padStart(11)}${"G2'yi asma ani".padStart(16)}`);
for (const k of [1200, 1000, 700]) {
  const birikim = secilen.yazma - k;
  console.log(`${`${k} kutu yazmasi/s`.padEnd(21)}${b(birikim).padStart(11)}${`${b(PENCERE * k / birikim)} s`.padStart(16)}`);
}
console.log(`ortalama takipci ${b(ortalama)}; esigin ustundeki baglanti payi ${b(secilen.okuma / akisTepe / ortalama, 4)}`);
```

```
kararli yazma hizi = 1414.09 kutu yazmasi/s, kapasite 4242.28/s, tek gonderiye kalan 2828.19/s -> 60 s penceresinde esik = 169.691 takipci

     esik  ustteki hesap   yazma is/s   okuma is/s   toplam is/s  en buyuk patlama/s
    1.000          19203       700.05     28561.87      29261.92               16.67
   10.000           1308      1000.84     16530.11      17530.95              166.52
   84.846            115      1193.70      8815.60      10009.30             1393.05
  169.691             52      1247.71      6655.38       7903.09             2820.88
1.000.000              0      1414.09         0.00       1414.09            16666.65

secilen esikte: ustteki 52 hesap okuma aninda toplaniyor, akis istegi basina 23.959 ek kaynak, toplam is 7903.09/s
esiksiz tasarimda en buyuk tek gonderi 16666.65 kutu yazmasi/s istiyor = kararli hizin 11.79 kati

tuketici kapasitesi    birikim/s  G2'yi asma ani
1200 kutu yazmasi/s        47.71       1509.13 s
1000 kutu yazmasi/s       247.71        242.22 s
700 kutu yazmasi/s        547.71         76.68 s
ortalama takipci 203.63; esigin ustundeki baglanti payi 0.1177
```

Tablonun son satırı ilk bakışta tartışmayı bitiriyor: eşiksiz yazmada dağıtma toplam işi 1414,09/s
ile en aza indiriyor ve her eşik bu sayıyı büyütüyor. Eşiği 1000'e çekmek toplam işi 29.261,92'ye,
yirmi katına yakın çıkarıyor. Nedeni değişmiyor — eşiğin üstüne taşınan her bağlantı, kırk kat daha sık
koşan tarafta yeniden sayılıyor.

Eşiği koyan şey toplam iş değil, **son sütundur**. Eşiksiz tasarımda en büyük hesabın tek bir
gönderisi, 60 saniyelik G2 penceresi içinde saniyede 16.666,65 kutu yazması istiyor: kararlı hızın
**11,79 katı**. Bu talep ortalamayla yapılan hesapta görünmez, çünkü ortalama 203,63'tür ve tek bir
kaydın büyüklüğü hakkında hiçbir şey söylemez.

Eşik buradan **hesaplanır**. Dağıtım kapasitesi kararlı hızın üç katına kurulursa (4242,28/s) tek
bir gönderiye 2828,19 yazma/s kalır; 60 saniyelik pencerede bu **169.691 takipçi** eder. Eşik budur
ve iki girdisi vardır: pencere ve kapasite. Seçilen eşikte 52 hesap okuma tarafına geçiyor, akış
isteği başına 23,959 ek kaynak okunuyor ve toplam iş 7903,09/s oluyor — eşiksiz tasarımın 5,59 katı.
Bu, tek bir gönderinin bütün dağıtım kapasitesini kaçırmasını önlemek için ödenen bedeldir.

Eşiğin üstündeki 52 hesap bağlantıların yalnızca 0,1177'sini tutuyor. Karma modelin çalışmasının
nedeni budur: kuyruğun ucundaki elli iki hesap bağlantıların yalnızca bu payını taşıyor ama
patlamanın tamamını üretiyor.

## Tasarım

- **Somutlaştırılmış görünüm** (Veri Katmanı Ölçekleme, Somutlaştırılmış Görünümler). Akış kutusu bir
  izdüşümdür; parametre kutu başına **400 girdi** ve girdi başına **32 bayttır**, toplam 12,80 GB.
- **Komut ve sorgu sorumluluğu ayrımı** (Veri Katmanı Ölçekleme, Komut ve Sorgu Ayrımı). Yazma yolu
  gönderi deposuna, okuma yolu kutuya bakar; parametre, kutunun gönderi metnini değil kimliğini
  tutmasıdır.
- **Mesaj kuyruğu ve rekabet eden tüketiciler** (Uygulama Katmanı, Mesaj Kuyrukları; Rekabet Eden
  Tüketiciler). Dağıtım işleri kuyruğa düşer; parametre kapasitedir: kararlı 1414,09/s'nin üç katı,
  4242,28 kutu yazması/s.
- **Parçalama** (Veri Dağıtımı, Parçalama). Kutu deposu kullanıcı kimliğine göre parçalanır;
  parametre, akış isteğinin **tek düğüme** dokunmasıdır — dağıt–topla yalnız eşiğin üstündeki 52
  hesap için oluşur.
- **Geri basınç** (Dayanıklılık ve Güvenilirlik, Geri Basınç). Kuyruk birikince yayımlama yoluna
  sinyal gider; parametre, G2'nin 60 saniyelik penceresidir.

**Bilerek kullanılmayan iki kalıp.** Kenar önbelleği (Trafik Katmanı, İçerik Dağıtım Ağları)
kullanılmıyor: akış kişiye özeldir, iki kullanıcı aynı yanıtı almaz ve paylaşılan önbellek isabet
üretmez. Sıralı konvoy (Uygulama Katmanı, Sıralı Konvoy) kullanılmıyor: dağıtım işlerinin sırası
önemsizdir, çünkü akış kutuda zaman damgasına göre sıralanır.

## Elenen Alternatif: Saf Okumada Toplama

Alternatif tasarım kutuyu hiç kurmaz; akış istendiğinde takip edilen hesapların son gönderileri
birleştirilir. Kazandığı iki şey ölçüldü: kutu deposu 12,80 GB'den sıfıra iner ve G2 penceresi
ortadan kalkar — gönderi yayımlandığı anda görünür, çünkü görünmesi için taşınması gerekmez. Takip
bırakma da anında yansır.

Eleme sayısı iş miktarındadır: tepede 56.570,71 iş/s, yazmada dağıtmanın 33,44 katı. Dahası bu sayı
okuma hacmine bağlıdır; VH3 ikiye katlandığında 113.127,53'e çıkarken yazmada dağıtma 1414,09'da
kalır. Alternatif hangi kısıt değişirse kazanır: okuma/yazma oranı 40'tan 1'e yaklaşırsa iki modelin
işi eşitlenir ve kutu tutmanın gerekçesi kalmaz. Bu, gönderi başına takipçi sayısının değil, **akış
isteğinin gönderiye oranının** kararı belirlediği anlamına gelir.

## Arıza Davranışı ve Feda Edilen

**Dağıtım tüketicisi yavaşlarsa** (Dayanıklılık ve Güvenilirlik, Arıza Kipleri) kuyruk birikir ve
görünme gecikmesi büyür. Tablo aşılma anını veriyor: kapasite 1200 kutu yazması/s'ye düşerse birikim
saniyede 47,71 olur ve G2'nin 60 saniyelik penceresi **1509,13 saniyede** aşılır; 1000'e düşerse
242,22 saniyede, 700'e düşerse 76,68 saniyede. Kısmi yavaşlama akışı durdurmaz, **geciktirir**; bu
yüzden arıza belirtisi hata değil, tazeliğin kaymasıdır.

**Kutu deposunun bir parçası düşerse** o parçadaki kullanıcıların akışı boş döner. Zarif bozulma
(Dayanıklılık ve Güvenilirlik, Zarif Bozulma) burada okumada toplamaya geçmektir: eşiğin üstündeki
52 hesap için zaten kurulmuş olan yol, düşen parçadaki kullanıcılar için geçici olarak bütün takip
edilenlere açılır — pahalıdır ama boş akıştan iyidir.

**Feda edilen yazma amplifikasyonudur.** Her gönderi ortalama 203,63 kutuya yazılıyor ve bu iş,
okuma hiç gelmese bile yapılıyor. Tasarım okumayı ucuzlatmak için yazmayı iki yüz katına yakın çoğalttı;
kararın tamamı okuma/yazma oranının 40 olmasına dayanıyor.

## Özet

- Aynı akış yazmada dağıtmayla tepede 1691,87, okumada toplamayla 56.570,71 iş/s istiyor: 33,44 kat.
  Fark okuma/yazma oranının kendisidir.
- Yazmada dağıtma okuma hacminden bağımsız: akış isteği ikiye katlandığında okumada toplama
  113.127,53'e çıkarken yazmada dağıtma 1414,09'da kalıyor.
- Takipçi dağılımının ortalaması 203,63 ama ortancası 60, p99,9 değeri 12.474; en üstteki binde
  birlik dilim bağlantıların 0,2753'ünü tutuyor.
- Eşiği toplam iş koymuyor — eşiksiz tasarım 1414,09/s ile en ucuzu. Eşiği koyan, en büyük hesabın
  tek gönderisinin 60 saniyelik pencerede istediği 16.666,65 yazma/s, yani kararlı hızın 11,79 katı.
- Eşik pencere ile kapasiteden hesaplanıyor: kapasite kararlı hızın üç katıysa eşik 169.691 takipçi,
  52 hesap okuma tarafına geçiyor ve toplam iş 7903,09/s oluyor.
- Tüketici kapasitesi 1200/1000/700'e düştüğünde G2 penceresi 1509,13 / 242,22 / 76,68 saniyede
  aşılıyor; feda edilen, gönderi başına 203,63 kutu yazmasıdır.

## Sonraki Adım

Bu vakada okumanın maliyeti derlemeydi ve derleme yazma anına kaydırılarak ucuzlatıldı. Kaydırmayı
mümkün kılan bir özellik vardı: yanıtın **kimin için** hazırlanacağı yazma anında biliniyordu, çünkü
takipçi listesi yazıldığı anda bellidir. Bir sonraki vakada bu özellik kaybolur. Kullanıcı bir metin
yazmaya başlar ve her tuş vuruşunda bir öneri listesi ister; sorgunun ne olacağı önceden bilinmez ve
olası sorgu sayısı bir kullanıcı listesi gibi sonlu değildir. Yanıt yazma anında hazırlanamıyorsa
okuma anında hazırlanmak zorundadır — ve bu kez okuma eşiği 200 milisaniye değil, tuş vuruşları
arasına sığacak kadar küçüktür. Soru, hangi veri yapısının bu eşiği tutabildiğine ve tazeliğin ne
kadarının feda edileceğine döner.
