---
title: 'Kenar Oluşturma'
source: 'https://academia.sh/tr/kurslar/olusturma-stratejileri/kenar-olusturma'
course: 'Oluşturma Stratejileri ve Altyapı'
language: tr
updated: '2026-08-17T18:09:30+00:00'
license: 'CC BY-SA 4.0'
---

# Kenar Oluşturma

Oluşturmanın kullanıcıya coğrafi olarak yaklaştırılması; mesafenin gecikmeye çevrimi, kenar düğümünün aktarma, birleştirme ve tam üretim biçimleri, kenar çalışma zamanının kısıtları ve verinin nerede durduğu sorusu.

Önceki iki teknik yanıtın gönderim biçimini ve etkileşimin kazanılma anını değiştirdi;
sunucu ile kullanıcı arasındaki mesafeyi olduğu gibi bıraktı. İlk dersteki zincir hesabında
ağ turu 60 milisaniye varsayılmış ve bu kalemin kod değişikliğiyle azalmadığı
söylenmişti: sinyalin kat edeceği yol kısalmadıkça süre kısalmaz.

Bu ders yolu kısaltmayı ele alır: oluşturmanın bir bölümünün ya da tamamının, kullanıcıya
yakın duran bir düğüme taşınması.

## Mesafe Bir Alt Sınır Koyar

Işık cam lifte boşluktakinden yavaş, yaklaşık 200.000 kilometre/saniye hızla ilerler.
Bu, hiçbir yazılımın aşamayacağı bir alt sınır verir.

```js
// mesafe.mjs — cografi uzakligin gecikmeye cevrimi ve kenarin kazandirdigi turlar
// Isik cam lifte yaklasik 200.000 km/s ile ilerler: bu bir alt sinirdir,
// gercek yollar duz cizgi degildir ve her atlamada isleme suresi eklenir.
const HIZ = 200000; // km/s
const tur = (km) => (2 * km / HIZ) * 1000; // ms, gidis-donus

console.log("mesafe (km)".padStart(12) + "tek yon (ms)".padStart(14) + "tur (ms)".padStart(11));
for (const km of [50, 500, 2500, 9000, 16000]) {
  console.log(String(km).padStart(12) + (tur(km) / 2).toFixed(1).padStart(14) +
    tur(km).toFixed(1).padStart(11));
}

// Bir sayfanin ilk gorunume kadar odedigi tur sayisi:
// 1 tasima el sikismasi + 1 sifreleme el sikismasi + 1 belge istegi + 1 alt kaynak turu.
const TUR_SAYISI = 4;
const SUNUCU_ISI = 40;   // ms, veri kaynagi + sablon
const KENAR_ISI = 2;     // ms, kenar dugumunun kendi isi

const KULLANICI_KENAR = 50;    // km
const KULLANICI_KAYNAK = 9000; // km

const yalnizKaynak = TUR_SAYISI * tur(KULLANICI_KAYNAK) + SUNUCU_ISI;
const kenarIsabet = TUR_SAYISI * tur(KULLANICI_KENAR) + KENAR_ISI;
const kenarIska = kenarIsabet + tur(KULLANICI_KAYNAK - KULLANICI_KENAR) + SUNUCU_ISI;

console.log("\nsenaryo".padEnd(34) + "sure (ms)".padStart(11) + "kaynaga gore".padStart(14));
for (const [ad, sure] of [
  ["yalniz kaynak sunucu", yalnizKaynak],
  ["kenar, kopyasi var", kenarIsabet],
  ["kenar, kaynaga sormasi gerekti", kenarIska],
]) {
  console.log(ad.padEnd(34) + sure.toFixed(1).padStart(11) +
    (sure / yalnizKaynak).toFixed(2).padStart(14));
}
```

```
 mesafe (km)  tek yon (ms)   tur (ms)
          50           0.3        0.5
         500           2.5        5.0
        2500          12.5       25.0
        9000          45.0       90.0
       16000          80.0      160.0

senaryo                            sure (ms)  kaynaga gore
yalniz kaynak sunucu                    400.0          1.00
kenar, kopyasi var                        4.0          0.01
kenar, kaynaga sormasi gerekti          133.5          0.33
```

Üst tablo tek başına bir tasarım kısıtıdır: dokuz bin kilometre uzaktaki bir sunucuya tek
bir gidiş-dönüş 90 milisaniyeden aşağı inemez. Bu sayı iyimserdir; gerçek yollar düz çizgi
değildir ve her ara düğümde işleme süresi eklenir.

Alt tablo turların **çarpan** etkisini gösterir. Sayfanın görünmesi dört tur istiyorsa
uzak sunucuda bu 360 milisaniyeye çıkar ve veri kaynağının 40 milisaniyelik işi toplamın
onda birinden azına düşer. Sunucunun işini hızlandırmak burada boşa çabadır; azaltılması
gereken şey turların uzunluğudur.

Üçüncü satır kenarın sınırını da söyler: kenar düğümü isteği karşılayamayıp kaynağa
sormak zorunda kalırsa el sıkışmalar yakınlaşır ama içerik yine uzaktan gelir ve süre
kaynağın üçte birine iner, yüzde birine değil.

## Kenar Düğümünün Üç İş Biçimi

Kenarda bir düğüm bulunması tek başına bir şey söylemez; belirleyici olan o düğümün ne
yaptığıdır. Üç biçim ayrı ayrı ölçülebilir. Aşağıdaki kaynak sunucuda coğrafi uzaklık,
yanıttan önce eklenen sabit bir gecikmeyle modellenmiştir; gerçek bir ağ ölçümü değildir.

```js
// kaynak-sunucu.mjs — uzaktaki kaynak sunucu
// Cografi uzaklik, yanittan once eklenen sabit bir gecikmeyle modellenmistir.
import { createServer } from "node:http";

const UZAKLIK = 80;  // ms, kaynaga gidip donmenin bedeli
const VERI_ISI = 40; // ms, veri kaynagindan okuma

const bekle = (ms) => new Promise((c) => setTimeout(c, ms));

const KABUK_ICI = '<h1>Kuzey Yamac Olcum Istasyonu</h1>' +
  '<ul><li>06:00 -4.2 C</li><li>07:00 -3.8 C</li><li>08:00 -2.1 C</li></ul>';

const gonder = (yanit, govde) => {
  yanit.setHeader("Content-Type", "text/html; charset=utf-8");
  yanit.setHeader("Content-Length", Buffer.byteLength(govde));
  yanit.writeHead(200).end(govde);
};

createServer(async (istek, yanit) => {
  yanit.sendDate = false;
  await bekle(UZAKLIK);
  if (istek.url === "/sayfa") {
    await bekle(VERI_ISI);
    gonder(yanit, `<!doctype html><html lang="tr"><body>${KABUK_ICI}` +
      `<p>Sorumlu: (kaynakta uretildi)</p></body></html>\n`);
  } else if (istek.url === "/parca/kisisel") {
    await bekle(5); // kucuk, kisiye ozel parca
    gonder(yanit, "<p>Sorumlu: A. Yilmaz</p>");
  } else if (istek.url === "/veri/olcumler") {
    await bekle(VERI_ISI);
    yanit.setHeader("Content-Type", "application/json");
    const govde = JSON.stringify([
      { zaman: "06:00", sicaklik: -4.2 },
      { zaman: "07:00", sicaklik: -3.8 },
      { zaman: "08:00", sicaklik: -2.1 },
    ]);
    yanit.setHeader("Content-Length", Buffer.byteLength(govde));
    yanit.writeHead(200).end(govde);
  } else {
    yanit.writeHead(404).end();
  }
}).listen(8176, "127.0.0.1", () => console.log("kaynak: 127.0.0.1:8176"));
```

```js
// kenar-sunucu.mjs — kullaniciya yakin, kod calistirabilen kenar dugumu
// Kaynak sunucuya erisim 8176 uzerinden; kullaniciya olan uzaklik ihmal edilir.
import { createServer } from "node:http";

const KAYNAK = "http://127.0.0.1:8176";

// Kenarin elindeki kopyalar: kabuk derleme ciktisindan, olcumler kaynaktan gelir.
const KABUK = (icerik, kisisel) =>
  `<!doctype html><html lang="tr"><body>${icerik}${kisisel}</body></html>\n`;
const BASLIK = "<h1>Kuzey Yamac Olcum Istasyonu</h1>";
let olcumKopyasi = null;

const gonder = (yanit, govde) => {
  yanit.setHeader("Content-Type", "text/html; charset=utf-8");
  yanit.setHeader("Content-Length", Buffer.byteLength(govde));
  yanit.writeHead(200).end(govde);
};

const liste = (olcumler) =>
  "<ul>" + olcumler.map((o) => `<li>${o.zaman} ${o.sicaklik} C</li>`).join("") + "</ul>";

createServer(async (istek, yanit) => {
  yanit.sendDate = false;
  if (istek.url === "/gecis") {
    // Kenar yalnizca aktarir: butun is kaynakta yapilir.
    const kaynakYaniti = await fetch(`${KAYNAK}/sayfa`);
    gonder(yanit, await kaynakYaniti.text());
  } else if (istek.url === "/birlestir") {
    // Kabuk kenarda hazir; yalnizca kisiye ozel kucuk parca kaynaktan istenir.
    const parca = await (await fetch(`${KAYNAK}/parca/kisisel`)).text();
    gonder(yanit, KABUK(BASLIK + liste(olcumKopyasi ?? []), parca));
  } else if (istek.url === "/kenarda") {
    // Sayfanin tamami kenardaki kopyadan uretilir; kaynak hic sorulmaz.
    gonder(yanit, KABUK(BASLIK + liste(olcumKopyasi ?? []), "<p>Sorumlu: (genel)</p>"));
  } else if (istek.url === "/tazele") {
    // Kenarin veri kopyasini kaynaktan yeniler.
    olcumKopyasi = await (await fetch(`${KAYNAK}/veri/olcumler`)).json();
    gonder(yanit, `<p>${olcumKopyasi.length} olcum alindi</p>\n`);
  } else {
    yanit.writeHead(404).end();
  }
}).listen(8177, "127.0.0.1", () => console.log("kenar: 127.0.0.1:8177"));
```

Aşağıdaki betik bu iki dosyayla aynı dizinde çalıştırılır. Bağlantı noktaları 8176 ve 8177
keyfîdir ve boş olmalıdır; kullanımdaysa üç dosyada da değiştirilir.

```bash
#!/usr/bin/env bash
# Iki sunucuyu baslatir, uc is bolumunu olcer, sonra durdurur.
node kaynak-sunucu.mjs > /dev/null &
kaynak=$!
node kenar-sunucu.mjs > /dev/null &
kenar=$!
sleep 1

BICIM='ilk bayt %{time_starttransfer} s   govde %{size_download} B\n'

printf '%-38s' "0) kenarin kopyasini tazelemesi"
curl -sS -o /dev/null -w "$BICIM" http://127.0.0.1:8177/tazele

printf '%-38s' "1) dogrudan kaynak sunucu"
curl -sS -o /dev/null -w "$BICIM" http://127.0.0.1:8176/sayfa

printf '%-38s' "2) kenar yalnizca aktariyor"
curl -sS -o /dev/null -w "$BICIM" http://127.0.0.1:8177/gecis

printf '%-38s' "3) kenar birlestiriyor"
curl -sS -o /dev/null -w "$BICIM" http://127.0.0.1:8177/birlestir

printf '%-38s' "4) kenar tumuyle kendisi uretiyor"
curl -sS -o /dev/null -w "$BICIM" http://127.0.0.1:8177/kenarda

echo "--- kenarda uretilen govde ---"
curl -sS http://127.0.0.1:8177/kenarda

kill "$kaynak" "$kenar"
```

```
0) kenarin kopyasini tazelemesi       ilk bayt 0.154206 s   govde 22 B
1) dogrudan kaynak sunucu             ilk bayt 0.124900 s   govde 195 B
2) kenar yalnizca aktariyor           ilk bayt 0.129912 s   govde 195 B
3) kenar birlestiriyor                ilk bayt 0.094019 s   govde 185 B
4) kenar tumuyle kendisi uretiyor     ilk bayt 0.000815 s   govde 183 B
```

Sıfırıncı satır ölçüme girmez; kenarın veri kopyasını doldurduğu hazırlık adımıdır. Süre
alanları makineye bağlıdır ve yorumu oranlar taşır.

**İkinci satır kenarın yanlış kullanımıdır.** Yalnızca aktaran bir düğüm, kaynağın süresine
kendi işini ekler ve doğrudan erişimden **yavaştır** — ölçülen çalıştırmada yaklaşık yüzde
dört. Farkın büyüklüğü çalıştırmaya göre değişir, işareti değişmez: araya bir düğüm koymanın
tek başına bir kazancı yoktur; kazanç, o düğümün üstlendiği işten gelir.

**Üçüncü satır iş bölümüdür.** Kabuk ve ölçüm listesi kenarda hazırdır; kaynaktan yalnızca
kişiye özel küçük parça istenir. Süre, doğrudan erişimin yaklaşık dörtte üçüne iner. Kazanç
kaynağa hiç gitmemekten değil, kaynaktan **az şey** istemekten gelir.

**Dördüncü satır tam kenarda üretimdir.** Kaynak hiç sorulmaz; süre iki mertebe kısalır —
ölçülen çalıştırmada yaklaşık yüz elli kat. Bunun koşulu, sayfayı üretmek için gereken her
şeyin kenarda bulunmasıdır.

## Kenar Çalışma Zamanının Kısıtları

Kenarda kod çalıştırmak, kaynak sunucuda kod çalıştırmakla aynı şey değildir. Kısıtlar
kenarın tanımından doğar: çok sayıda düğümde, her düğümde az kaynakla, çok sayıda kiracı
yan yana çalışır.

**Süreç uzun yaşamaz.** İstek dışında ayakta duran bir bellek durumu varsayılamaz; bir
düğümde tutulan sayaç başka bir düğümde yoktur. Durum, ya isteğin kendisinde ya paylaşımlı
bir depoda tutulur.

**İşlem ve bellek bütçesi dardır.** Ağır bir şablon işleme, büyük bir bağımlılık ağacı ya
da uzun süren bir hesap kenara uygun değildir. Kenarda çalışacak kod, kaynak sunucuda
çalışan koddan küçüktür ve bu bir tercih değil bir sınırdır.

**İlk çağrının maliyeti ayrıdır.** Uzun süre çağrılmamış bir kod parçası yeniden
yüklenirken bir başlatma süresi doğar. Kenarın kazandırdığı milisaniyeler bu süreyle aynı
mertebede olabilir; bu yüzden nadiren çağrılan yollar kenara taşınarak hızlanmaz.

**Ortam düğümden düğüme aynı değildir.** Kenarda çalışan kod, kaynak sunucudakinin tüm
yeteneklerine sahip olmayabilir. Dosya sistemi, uzun ömürlü bağlantılar ve kimi
kitaplıklar bulunmayabilir; kod bu varsayımla yazılır.

## Asıl Soru Verinin Nerede Olduğudur

Ölçümün dördüncü satırındaki kazanç, kenarın ölçüm listesinin bir kopyasını taşımasından
doğdu. Bu kopya sıfırıncı adımda kaynaktan alınmıştı ve alındığı andan itibaren eskimeye
başlar.

Buradan kenar oluşturmanın gerçek kuralı çıkar: **oluşturma, verisinin yanına taşınabildiği
kadar taşınabilir.** Kenara taşınan kod, kaynaktaki veriyi her istekte soruyorsa mesafe
yeniden ödenir; üçüncü satır bu durumun ölçüsüdür. Kazancın tamamı ancak veri de kenarda
olduğunda alınır.

Verinin kenara taşınması üç biçimde olur ve üçü de bir bedel taşır. Nadiren değişen veri
kopyalanır; bedeli tazeliktir ve artımlı yeniden üretim dersindeki pencere hesabı burada da
geçerlidir. Kullanıcıya bağlı küçük veri isteğin kendisinde taşınır; bedeli, bu verinin
kurcalanamayacak biçimde imzalanması gereğidir. Geri kalan her şey kaynakta kalır; bedeli,
o bölümler için mesafenin ödenmesidir.

Bu üçlü ayrım, sayfanın bölümlere ayrılmasını gerektirir. İstasyon sayfasında kabuk ve
ölçüm listesi kopyalanabilir, sorumlu adı istekte taşınabilir, düzenleme yetkileri kaynakta
sınanır. Sayfanın tek parça olduğu bir tasarımda bu ayrım yapılamaz ve sayfanın tamamı en
kısıtlayıcı bölümün kuralına uyar.

## Özet

- Coğrafi mesafe gecikmeye bir alt sınır koyar: dokuz bin kilometre için tek gidiş-dönüş
  90 milisaniyeden aşağı inmez ve sayfa başına ödenen tur sayısıyla çarpılır.
- Kenarda bir düğüm bulunması tek başına kazanç değildir; yalnızca aktaran bir düğüm
  doğrudan erişimden yavaştır.
- Kaynaktan yalnızca küçük bir parça isteyen kenar, süreyi doğrudan erişimin dörtte üçüne;
  hiç sormayan kenar ise yüzde birinin altına indirir.
- Kenar çalışma zamanı uzun ömürlü bellek durumu varsaymaz, dar bir işlem ve bellek
  bütçesiyle çalışır, ilk çağrıda bir başlatma süresi doğurur ve yetenekleri kaynak
  sunucununkinden dardır.
- Oluşturma ancak verisinin taşınabildiği kadar kenara taşınabilir; sayfanın bölümlere
  ayrılmadığı bir tasarımda tamamı en kısıtlayıcı bölümün kuralına uyar.

## Sonraki Adım

Altı model ayrı ayrı ölçüldü ve her biri belirli bir durumda üstün çıktı. Geriye bu
ölçümleri tek bir karara bağlamak kalıyor. Kuzey Yamaç sitesinde yedi ayrı sayfa türü
vardır ve hepsinin aynı modelle üretilmesi için hiçbir neden yoktur: tanıtım sayfası
değişmez, ölçüm listesi dakikada bir değişir, arşiv sayfaları binlercedir, panel kişiye
özeldir. Sonraki ders bu envanteri üç eksene — içerik tazeliği, kişiselleştirme ve ölçek —
oturtur ve her sayfa için modeli bu eksenlerden türeten bir karar kuralı kurar.
