---
title: 'Meşgul Ön Yüz'
source: 'https://academia.sh/tr/kurslar/basarim-ve-izleme/mesgul-on-yuz'
course: 'Başarım Karşıt Kalıpları ve İzleme'
language: tr
updated: '2026-08-17T18:10:58+00:00'
license: 'CC BY-SA 4.0'
---

# Meşgul Ön Yüz

Sunucunun gönderdiği yükün istemcideki işi büyütmesi: sunucu yanıt süresi değişmezken kullanıcıya görünen sürenin büyümesi, aynı belirtiyi veren yük büyümesi ile istemci kodu büyümesinin kayıt başına iş ölçüsüyle ayrılması, sıralamayı sunucuya taşımanın 26,8 katlık kazancı ve biçimlendirmeyi taşımanın önbellek anahtarına ödettiği bedel.

Sınır oranı işin hangi katmanda yapılacağını depo ile uygulama arasında çözdü. Zincirin bir ucu
daha var ve orada takas kural değiştirir: uygulama katmanında iş düğüm eklenerek dağıtılır,
istemcide dağıtılacak düğüm yoktur. Bu ders o üçüncü katmanı ele alır ve aynı üç adımı yürütür —
belirti bir sayıdır, iki neden bir ölçümle ayrılır, düzeltmenin karşılığında büyüyen sayılır.

Ana iş parçacığı, uzun görev ve kullanıcı merkezli ölçütler Frontend Kalitesi kursunda tanımlandı
ve ölçüldü; burada yeniden tanımlanmaz. Buradaki soru sistem tasarımı sorusudur: **sunucunun
gönderdiği yük, istemcideki işi hangi çarpanla büyütür ve bu çarpan hangi ölçümle görülür.**

## Belirti: Sunucu Sakin, Kullanıcı Bekliyor

Satıcı panelinde açık gönderi listesi açılıyor. Kullanıcıya görünen süre son iki sürümde büyüdü.
Sunucu tarafındaki yanıt süresi ölçütü değişmedi; uç, K01'in tepe yükünü aynı sayılarla
karşılıyor. Yanıtın baytı da denetlendi ve aktarımın payı değişmemiş. Belirti şu hâle geliyor:
**işin tamamı istemciye geçtikten sonra büyüyor.**

Bu noktada iki neden vardır ve ikisi de sunucu ölçütlerinde görünmez.

**Neden A — sunucu gönderdiği kayıt sayısını artırdı.** İstemci kodu değişmedi, ama yük büyüdü;
aynı kod daha çok kayıt üzerinde koşuyor.

**Neden B — istemci kayıt başına iş ekledi.** Yük aynı, ama yeni sürüm her kayıtta iki adım
fazla yapıyor.

Ölçmeden verilen yanıt tahmindir ve tahminin iki yönü de vardır: "sunucu çok veri gönderiyor"
ile "ön yüz ağırlaştı" cümleleri aynı belirtiden çıkarılır ve biri yanlıştır.

## Ölçüm Düzeneği

Aşağıdaki koşum bir **modeldir**. Tarayıcı süresi ölçülmüyor ve uydurulmuyor; sayılan şey
istemcinin tek bir iş parçacığında yapmak zorunda olduğu adımlardır: ayrıştırılan alan, dönüşüm
adımı ve sıralama karşılaştırması. Üçü de gerçekten koşuyor, sayaçlar gerçek çağrıları sayıyor
ve sıralamanın girdisi tohumlu bir üreteçten geliyor.

**KK2 — panelde bir ekranda görünen satır: 25.** Gerekçe: liste görünümü sayfa boyu kadar satır
gösterir, kalanı kaydırmayla gelir. Duyarlılığı bir sonraki derste çağrı sayısına dönüşür.

```js
// onyuz/isparcacigi.mjs — sunucunun gonderdigi yukun on yuzdeki isi nasil buyuttugu.
// MODELDIR: is birimi soyut bir adimdir, sure olculmez; sayilan sey ayristirilan alan,
// donusum adimi ve siralama karsilastirmasidir. Ucu de gercekten kosar.
const OLAY = 7, GORUNEN = 25, BOLGE = 12, ROTA = 40;      // K01 V4 = 7 durum olayi; KK2 = 25 satir

function uret(N) {                                        // sunucunun elindeki tam veri
  let s = 20260801 % 2147483647;                          // tohum gorunur; siralama sirasi belirlenimli
  const rast = () => (s = (s * 48271) % 2147483647) % 100000;
  const g = [];
  for (let i = 0; i < N; i += 1) {
    const olaylar = [];
    for (let j = 0; j < OLAY; j += 1)
      olaylar.push({ kod: (i * 3 + j) % 5, ts: rast(),
        bolge: (i + j) % BOLGE, rota: `R-${(i + j) % ROTA}`, tasiyici: (i + j) % 6 });
    g.push({ no: `TR-${i}`, satici: i % 20, agirlik: 1 + (i % 30), guncelleme: rast(), olaylar });
  }
  return g;
}

const AD = ["kabul", "aktarma", "dagitimda", "teslim", "bekliyor"];

function sunucu(N, plan) {                                // uctan cikan yuk
  const g = uret(N);
  if (plan === "ham") return g;
  const ust = [...g].sort((a, b) => b.guncelleme - a.guncelleme).slice(0, GORUNEN);
  return ust.map((x) => ({ no: x.no, guncelleme: x.guncelleme,
    olaylar: [...x.olaylar].sort((a, b) => b.ts - a.ts).slice(0, 3)
      .map((o) => (plan === "bicimli"
        ? { satir: `${AD[o.kod]} / ${o.rota} / ${o.ts}` }
        : { kod: o.kod, ts: o.ts, rota: o.rota })) }));
}

const alanSay = (x) => Array.isArray(x) ? x.reduce((a, y) => a + alanSay(y), 0)
  : (x && typeof x === "object") ? Object.values(x).reduce((a, y) => a + alanSay(y), 0) : 1;

function istemci(metin, { donusum, sirala }) {
  const s = { ayristirma: 0, donusum: 0, karsilastirma: 0, cizim: 0 };
  const veri = JSON.parse(metin);
  s.ayristirma = alanSay(veri);
  let liste = veri;
  if (sirala) {                                           // gonderi listesi: N log N
    liste = [...veri].sort((a, b) => { s.karsilastirma += 1; return b.guncelleme - a.guncelleme; });
    for (const x of liste) [...x.olaylar].sort((a, b) => { s.karsilastirma += 1; return b.ts - a.ts; });
  }
  if (donusum > 0) for (const x of veri) for (const o of x.olaylar) {   // once bicimlendir, sonra dilimle
    s.donusum += donusum;
    void [AD[o.kod] ?? "", String(o.ts).padStart(6, "0"), `${o.rota}`, `${o.bolge ?? 0}`,
      `${o.tasiyici ?? 0}`, `${o.kod ?? 0}`].slice(0, donusum);
  }
  for (const x of liste.slice(0, GORUNEN)) { s.cizim += 3; void x.no; }
  s.toplam = s.ayristirma + s.donusum + s.karsilastirma + s.cizim;
  return s;
}

const DURUM = [
  ["ham yuk, istemci s1", 200, "ham", { donusum: 4, sirala: true }],
  ["ham yuk, istemci s1", 400, "ham", { donusum: 4, sirala: true }],
  ["ham yuk, istemci s2", 200, "ham", { donusum: 6, sirala: true }],
  ["sirali yuk, istemci s1", 200, "sirali", { donusum: 4, sirala: false }],
  ["bicimli yuk", 200, "bicimli", { donusum: 0, sirala: false }],
];
const say = (x) => x.toLocaleString("tr-TR");
console.log(`model: bir gonderi ${OLAY} durum olayi tasiyor (K01 V4), ekranda ${GORUNEN} satir ` +
  `gorunuyor (KK2); is birimi soyut bir adimdir, sure olculmez`);
console.log(`\n${"durum".padEnd(24)}${"N".padStart(6)}${"gecen kayit".padStart(13)}` +
  `${"ayristirma".padStart(12)}${"donusum".padStart(10)}${"karsilastirma".padStart(15)}` +
  `${"toplam is".padStart(12)}${"kayit basina".padStart(14)}${"gorunen satir basina".padStart(22)}`);
const r = {};
for (const [ad, N, plan, ist] of DURUM) {
  const yuk = sunucu(N, plan), metin = JSON.stringify(yuk);
  const s = istemci(metin, ist);
  r[`${ad}|${N}`] = { ...s, gecen: yuk.length, bayt: Buffer.byteLength(metin) };
  console.log(ad.padEnd(24) + String(N).padStart(6) + say(yuk.length).padStart(13) +
    say(s.ayristirma).padStart(12) + say(s.donusum).padStart(10) + say(s.karsilastirma).padStart(15) +
    say(s.toplam).padStart(12) + (s.toplam / yuk.length).toFixed(2).padStart(14) +
    (s.toplam / GORUNEN).toFixed(1).padStart(22));
}

console.log(`\nolcekleme (ham yuk, istemci s1): N iki katina cikarken toplam is kac kat`);
console.log(`${"N".padStart(6)}${"toplam is".padStart(12)}${"kat".padStart(8)}` +
  `${"kayit basina".padStart(14)}${"karsilastirma/N".padStart(17)}`);
let onceki = 0;
for (const N of [50, 100, 200, 400, 800]) {
  const s = istemci(JSON.stringify(sunucu(N, "ham")), { donusum: 4, sirala: true });
  console.log(String(N).padStart(6) + say(s.toplam).padStart(12) +
    (onceki ? (s.toplam / onceki).toFixed(3) : "-").padStart(8) +
    (s.toplam / N).toFixed(2).padStart(14) + (s.karsilastirma / N).toFixed(2).padStart(17));
  onceki = s.toplam;
}

const a = r["ham yuk, istemci s1|200"], b = r["ham yuk, istemci s1|400"];
const c = r["ham yuk, istemci s2|200"], d = r["sirali yuk, istemci s1|200"], e = r["bicimli yuk|200"];
console.log(`\nayirt eden olcum — kayit basina is: A (sunucu N'i 200 -> 400) ` +
  `${(a.toplam / a.gecen).toFixed(2)} -> ${(b.toplam / b.gecen).toFixed(2)}, ` +
  `B (istemci s1 -> s2, N sabit) ${(a.toplam / a.gecen).toFixed(2)} -> ${(c.toplam / c.gecen).toFixed(2)}`);
console.log(`duzeltme: sirali yukta toplam is ${say(a.toplam)} -> ${say(d.toplam)} ` +
  `(${(a.toplam / d.toplam).toFixed(1)} kat), bicimli yukta ${say(e.toplam)} ` +
  `(${(a.toplam / e.toplam).toFixed(1)} kat); gecen bayt ${say(a.bayt)} -> ${say(d.bayt)} -> ${say(e.bayt)}`);

const UC = 513.89, ISABET = 0.9;                          // K01 tepe uctaki istek/s, K02 onbellek isabeti
console.log(`\nisi sunucuya tasimanin kosulu: onbelleklenebilir is ${(UC * (1 - ISABET)).toFixed(2)} kez/s, ` +
  `onbelleklenemez is ${UC.toFixed(2)} kez/s kosar (oran ${(1 / (1 - ISABET)).toFixed(2)}); ` +
  `istemcide her iki durumda da kullanici basina 1 kez`);
```

```
model: bir gonderi 7 durum olayi tasiyor (K01 V4), ekranda 25 satir gorunuyor (KK2); is birimi soyut bir adimdir, sure olculmez

durum                        N  gecen kayit  ayristirma   donusum  karsilastirma   toplam is  kayit basina  gorunen satir basina
ham yuk, istemci s1        200          200       7.800     5.600          3.920      17.395         86.97                 695.8
ham yuk, istemci s1        400          400      15.600    11.200          8.243      35.118         87.80                1404.7
ham yuk, istemci s2        200          200       7.800     8.400          3.920      20.195        100.97                 807.8
sirali yuk, istemci s1     200           25         275       300              0         650         26.00                  26.0
bicimli yuk                200           25         125         0              0         200          8.00                   8.0

olcekleme (ham yuk, istemci s1): N iki katina cikarken toplam is kac kat
     N   toplam is     kat  kayit basina  karsilastirma/N
    50       4.321       -         86.42            17.92
   100       8.649   2.002         86.49            18.74
   200      17.395   2.011         86.97            19.60
   400      35.118   2.019         87.80            20.61
   800      70.963   2.021         88.70            21.61

ayirt eden olcum — kayit basina is: A (sunucu N'i 200 -> 400) 86.97 -> 87.80, B (istemci s1 -> s2, N sabit) 86.97 -> 100.97
duzeltme: sirali yukta toplam is 17.395 -> 650 (26.8 kat), bicimli yukta 200 (87.0 kat); gecen bayt 95.028 -> 3.771 -> 3.775

isi sunucuya tasimanin kosulu: onbelleklenebilir is 51.39 kez/s, onbelleklenemez is 513.89 kez/s kosar (oran 10.00); istemcide her iki durumda da kullanici basina 1 kez
```

## Kayıt Başına İş Nedeni Ayırıyor

Ayırt eden ölçüm **kayıt başına iş birimidir**: toplam işin, sunucunun gönderdiği kayıt sayısına
bölümü. İki neden bu tek sayıda ayrışıyor.

Neden A'da sunucu 200 kayıttan 400'e çıkıyor. Toplam iş 17.395'ten 35.118'e gidiyor — kullanıcı
belirtiyi hisseder. Ama kayıt başına iş 86,97'den 87,80'e çıkıyor; yüzde 0,95. İstemci kodu
değişmemiştir ve ölçüm bunu söylüyor.

Neden B'de gönderilen kayıt 200'de kalıyor, toplam iş 17.395'ten 20.195'e çıkıyor. Kayıt başına
iş 86,97'den 100,97'ye gidiyor; yüzde 16,1. Yük değişmemiştir, kod değişmiştir.

**Aynı belirti, aynı yönde büyüyen toplam, ters yönde işaret eden bölüm.** Toplam işe bakmak
tanı vermiyor; bölmek veriyor.

Ölçekleme tablosu üçüncü bir şey söylüyor. N iki katına çıktığında toplam iş 2,002'den 2,021'e
tırmanan bir katsayıyla büyüyor ve kayıt başına iş 86,42'den 88,70'e çıkıyor. Bu, kodun değiştiği
anlamına gelmez; karşılaştırma sütunu nedeni veriyor: kayıt başına karşılaştırma 17,92'den
21,61'e çıkıyor. İstemci listeyi kendi sıralıyor ve sıralama kayıt sayısıyla doğrusal büyümüyor.
Yani yük büyümesi, kayıt başına işi de bir miktar büyütür — bu payın **logaritmik**, kod
değişikliğinin payının **basamaklı** olduğu bilinirse iki neden yine ayrılabilir.

## İki Düzeltme, Bir Farkla

Belirtinin asıl büyüklüğü son sütunda. Ham yükte görünen satır başına ana iş parçacığı işi
695,8 birim; ekranda 25 satır var ve istemci 200 kaydın hepsini ayrıştırıp biçimlendiriyor,
sonra dilimliyor. Bu, karşıt kalıbın kendisidir: **iş, gösterilecek olanla değil, gönderilenle
ölçekleniyor.**

Sunucu sıralamayı ve seçmeyi üstlendiğinde toplam iş 17.395'ten 650'ye iniyor — **26,8 kat**.
Görünen satır başına iş 695,8'den 26,0'a düşüyor. Sunucu ayrıca biçimlendirmeyi de üstlenirse iş
200'e iniyor; ham yüke göre 87,0 kat, sıralı yüke göre 3,25 kat.

İki düzeltme aynı şey değil ve son satır farkı veriyor. Sıralı yüke geçiş sınırdan geçen baytı
95.028'den 3.771'e indiriyor. Biçimli yüke geçiş baytı 3.771'den 3.775'e **çıkarıyor** —
biçimlendirme sunucuda yapıldığında yanıt küçülmüyor. Yani ikinci adım yalnız iş birimi
kazandırıyor, üçüncü bir maliyeti var ve o maliyet bir sonraki bölümdedir.

## İşi İstemcide Bırakmanın Doğru Olduğu Koşul

İstemcide iş yapmak bir hata değildir; sunucuya taşımanın da bir fiyatı vardır ve fiyat sayıyla
yazılabilir. İstemcide bir iş kullanıcı başına **bir kez** koşar ve kullanıcının kendi
donanımında koşar. Sunucuya taşındığında aynı iş K01'in tepe yükünde saniyede 513,89 kez koşar —
tek bir kaynak havuzunda.

Koşulu belirleyen şey işin **önbelleklenebilir** olmasıdır. K02'nin kenar önbelleği okumaların
onda dokuzunu karşılıyor; sunucuya taşınan iş önbelleklenebiliyorsa saniyede 51,39 kez koşar,
önbelleklenemiyorsa 513,89 kez. Oran 10,00. Sıralama ile seçme kullanıcıya özel değildir; aynı
satıcının aynı listesi herkes için aynıdır, önbelleklenebilir, taşınmalıdır. Biçimlendirme
kullanıcının yerel ayarına bağlıdır; taşınırsa yanıt kullanıcıya özelleşir ve önbellek anahtarı
o boyut sayısı kadar parçaya bölünür. Aynı isabeti korumak için önbellek o kat kadar büyütülür.

Bu yüzden ölçüm iki düzeltmeyi ayırıyor: **26,8 katlık kazanç alınır, 3,25 katlık kazanç
alınmaz.** İkincisinin karşılığında büyüyen şey ölçülebilir ve büyük; birincisinin karşılığı
yalnız sunucuda 51,39 kez/s koşan bir sıralamadır.

## Karşılığında Büyüyen

Sıralamanın ve seçmenin sunucuya taşınmasının üç karşılığı var. Sunucu artık saniyede 51,39 kez
sıralama yapıyor — önbellek arkasında, K01'in depoya ulaşan 138,89 istek/s'lik yükünün üstüne
biner. İkincisi, hangi 25 kaydın gösterileceği kararı sunucuya geçti; kullanıcı listede
ilerledikçe bu karar yeni bir istek doğurur. Üçüncüsü, istemcinin elinde artık tam liste yok:
yerel bir süzme ya da yeniden sıralama da sunucuya gitmek zorunda.

Son iki karşılık aynı yöne bakıyor ve bir sonraki dersin konusudur.

## Özet

- Belirti sunucu ölçütlerinde görünmez: yanıt süresi ve bayt sabitken kullanıcıya görünen süre
  büyür. Aynı belirtiyi yük büyümesi de istemci kodu büyümesi de verir.
- Ayırt eden ölçüm kayıt başına iş birimidir: yük 200'den 400'e çıkarken 86,97 → 87,80 (%0,95),
  kod s1'den s2'ye geçerken 86,97 → 100,97 (%16,1).
- Yük büyümesi kayıt başına işi de bir miktar büyütür ama logaritmik olarak: kayıt başına
  karşılaştırma 17,92'den 21,61'e çıkıyor, çünkü sıralama istemcide yapılıyor.
- Karşıt kalıbın ölçüsü görünen satır başına iştir: ham yükte 695,8 birim, oysa ekranda 25 satır
  var. Sıralama ve seçme sunucuya taşındığında toplam iş 26,8 kat düşüyor.
- Biçimlendirmenin de taşınması 3,25 kat daha kazandırır ama baytı 3.771'den 3.775'e çıkarır ve
  yanıtı kullanıcıya özelleştirir; önbellek anahtarı bölünür.
- Koşul önbelleklenebilirliktir: sunucuya taşınan iş önbelleklenebiliyorsa 51,39 kez/s, değilse
  513,89 kez/s koşar (oran 10,00); istemcide her iki durumda da kullanıcı başına bir kez.

## Sonraki Adım

Sunucu artık 200 kayıt yerine 25 kayıt gönderiyor ve hangi 25 kaydın gösterileceğine kendisi
karar veriyor. Kullanıcı listede ilerledikçe bu karar yenilenmek zorunda: her kaydırma bir istek,
her süzme bir istek, satır açıldığında ayrıntı için bir istek daha. Yük küçüldü, **çağrı sayısı**
büyüdü ve bu sayı hiç ölçülmedi. Sonraki ders o sayıyı ele alır: çağrı sayısı ile taşınan bayt
arasındaki ödünleşim, sabit çağrı maliyetinin hangi kayıt sayısında taşınan bayta baskın geldiği
ve tek büyük çağrının ne zaman çok sayıda küçük çağrıdan daha kötü olduğu.
