---
title: 'Sunucusuz Mimari'
source: 'https://academia.sh/tr/kurslar/mimari-bicemler/sunucusuz-mimari'
course: 'Mimari Biçemler'
language: tr
updated: '2026-08-17T18:10:36+00:00'
license: 'CC BY-SA 4.0'
---

# Sunucusuz Mimari

Koşum sorumluluğunun uygulamadan çıkması: işlev dosyalarında kalan koşum satırının sayılması, bileşimin bildirime taşınmasının düzenlenen dosya sayısıyla ölçülmesi, soğuk koşumda modül durumunun ürettiği sonuç sapmasının ve durumu dışarı taşımanın bedelinin ölçülmesi, soğuk başlatmanın kurulum sayısıyla sayılıp süresinin bir modele bırakılması.

Buraya kadarki dört biçemin ortak bir örtük varsayımı vardı: istek gelmeden önce ayakta olan bir
süreç. Tek parça düzende bir süreç, mikroservis düzeninde üç süreç elle başlatıldı ve elle
durduruldu; olay güdümlü düzende veriyolunun da bir yerde koşması gerekiyordu. Süreci ayakta
tutmak, dinlemek ve isteği doğru birime yönlendirmek uygulamanın taşıdığı koddu.

**Sunucusuz mimari** (serverless architecture) bu kodu uygulamadan alır. Dağıtım birimi bir süreç
değil, bir olay ya da istek geldiğinde çağrılan bir işlevdir; süreci açmak, bekletmek, çoğaltmak ve
kapatmak çalıştırıcının işidir. Ad sunucunun yokluğunu anlatmaz — sunucu vardır, ama uygulamanın
sorumluluk alanında değildir. Bu ders o kaydırmanın iki yüzünü sayar: uygulamadan çıkan koşum
satırını ve karşılığında kısıta dönüşen varsayımları.

## Kısıta Dönüşen İlke

Sunucu Tarafı Temelleri kursunun On İki Etmen Uygulama İlkeleri dersinde süreçlerin durumsuz ve
paylaşımsız tutulması bir ilke olarak sayılmıştı; aynı kursun Uygulama Çalışma Zamanı dersi
ölçekleme biriminin süreç olduğunu ölçtü. Sunucusuz biçemde **durumsuz süreç** bir tercih olmaktan
çıkar: çalıştırıcı işlevin örneğini istediği anda açıp kapatabildiği için iki çağrının aynı bellek
alanını göreceği garanti edilemez. İlkenin ihlali burada bir üslup kusuru değil, ölçülebilir bir
sonuç sapmasıdır.

İkinci kısıt bileşimle ilgilidir. İşlev kendisini bir yola bağlamaz, komşusunu ithal etmez, çağrı
sırasını bilmez. Bileşim işlevlerin dışına, çalıştırıcının okuduğu bir **bildirime** (deployment
manifest) taşınır.

## Üç İşlev ve Bir Bildirim

Kurulum işinin kaç kez yapıldığını saymak için işlev modülleri paylaşılan bir ize bir satır bırakır.
Bu iz ölçüm içindir; işlevin işiyle ilgisi yoktur.

```js
// sunucusuz/sayac.mjs — kurulum izi: her islev modulunun ilk yuklenisi buraya bir iz birakir
export const kurulum = [];
```

Ücretlendirme bağlamının fiyat işlevi tek bir dışa açılım taşır. Sunucu, dinleme, yol çözümleme ve
bağlantı noktası kodu yoktur.

```js
// sunucusuz/ucret.mjs — fiyat islevi: sunucu, dinleme ve yol kodu yok; disa yalniz ele acilir
import { kurulum } from "./sayac.mjs";

const TARIFE = { kademe: [[1, 3000], [5, 4800], [20, 9600]], bolge: { "34": 100, "06": 115, "35": 125 }, asgari: 2500 };
kurulum.push("fiyat");                     // modul yuklenisinde bir kez calisir: kurulum isi

export function ele(olay) {
  const kademe = TARIFE.kademe.find(([k]) => olay.agirlik <= k) ?? [0, 9600];
  const taban = Math.max(TARIFE.asgari, Math.round((kademe[1] * TARIFE.bolge[olay.bolge]) / 100));
  return { id: olay.id, net: taban - Math.round(taban * Math.min(olay.oran, 0.4)) };
}
```

Teslimat operasyonunun plan işlevi aynı biçimdedir; ayrı bir dağıtım birimi olduğu tek kanıtı ayrı
bir dosya olmasıdır.

```js
// sunucusuz/operasyon.mjs — plan islevi: ayri dagitim birimi, ayni cagri bicimi
import { kurulum } from "./sayac.mjs";

const AGAC = { "34": ["34"], "06": ["34", "06"], "35": ["34", "41", "35"] };
kurulum.push("plan");

export function ele(olay) {
  const rota = AGAC[olay.bolge] ?? ["34"];
  return { rota, gun: rota.length, tasiyici: rota.length > 2 ? "MT" : "AN" };
}
```

Üçüncü işlev hacim indirimi için sözleşme başına ağırlık toplar. Toplama işi doğası gereği çağrılar
arasında bir şey hatırlar; aşağıda aynı işin iki tasarımı yan yana durur. Birinci tasarım toplamı
modül düzeyinde tutar, ikincisi çalıştırıcının verdiği depoya yazar.

```js
// sunucusuz/hacim.mjs — hacim indirimi islevi: ayni isin modul durumlu ve depo durumlu tasarimi
import { kurulum } from "./sayac.mjs";

const toplam = new Map();                  // MODUL DURUMU: modul yeniden yuklendiginde bosalir
kurulum.push("hacim");

export function ele(olay) {
  toplam.set(olay.sozlesmeNo, (toplam.get(olay.sozlesmeNo) ?? 0) + olay.agirlik);
  return { sozlesme: toplam.size, hacim: [...toplam.values()].reduce((t, a) => t + a, 0) };
}

export function eleDepolu(olay, depo) {
  const anahtar = `hacim:${olay.sozlesmeNo}`;
  depo.yaz(anahtar, (depo.oku(anahtar) ?? 0) + olay.agirlik);
  const liste = depo.anahtarlar();
  return { sozlesme: liste.length, hacim: liste.reduce((t, k) => t + depo.oku(k), 0) };
}
```

Bildirim iki eşlemeden oluşur: hangi adın hangi dosyanın hangi dışa açılımına karşılık geldiği ve
hangi yolun hangi işlev dizisini çalıştırdığı. Bu dosyada tek bir alan kuralı yoktur; yalnız
bileşim vardır.

```js
// sunucusuz/yol.mjs — bildirim: hangi ad hangi dosyanin hangi disa acilimi, hangi yol hangi dizi
export const bildirim = {
  islev: {
    fiyat: "./ucret.mjs#ele",
    plan: "./operasyon.mjs#ele",
    hacim: "./hacim.mjs#ele",
    "hacim-depolu": "./hacim.mjs#eleDepolu",
  },
  yol: {
    "/teklif": ["fiyat", "plan"],
    "/kayit": ["fiyat", "hacim"],
    "/kayit-depolu": ["fiyat", "hacim-depolu"],
  },
};
```

## Çalıştırıcının Yerel Durağı

Çalıştırıcı bu derste yerel bir durakla modellenir. Yaptığı iş üç adımdır: bildirimden işlevin
yerini bulmak, modülü yüklemek ve gövdeyi serileştirip çözerek işleve vermek. **Kap** (container)
burada işlevin içinde koştuğu, çalıştırıcının açıp kapattığı örnektir. `soguk` seçeneği kap
kararını taklit eder: kapalıyken modül kap ömrü boyunca bir kez kurulur, açıkken her çağrıda
yeniden kurulur. Sorgu eki modülün yeniden kurulmasını sağlar; gerçek bir çalıştırıcıda bunun
karşılığı yeni bir kap açmaktır.

```js
// sunucusuz/calistirici.mjs — islev calistiricisinin yerel duragi: bildirimi okur, islevleri cagirir
let sira = 0;                              // surec boyunca artan yukleme numarasi

export function calistirici(bildirim, kayit, { soguk = false } = {}) {
  const kap = ++sira;                      // bu ornek bir kap: sicak kosumda modul bir kez kurulur
  const bellek = new Map();
  const ham = new Map();
  const depo = {
    oku(k) { kayit.depo += 1; return ham.get(k); },
    yaz(k, v) { kayit.depo += 1; ham.set(k, v); },
    anahtarlar() { kayit.depo += 1; return [...ham.keys()]; },
  };
  return {
    async cagir(yolAdi, olay) {
      const sonuc = {};
      for (const ad of bildirim.yol[yolAdi]) {
        const [dosya, disa] = bildirim.islev[ad].split("#");
        if (soguk || bellek.has(ad) === false) {
          bellek.set(ad, await import(`${dosya}?k=${soguk ? ++sira : kap}`));
        }
        const metin = JSON.stringify(olay);
        kayit.donusum += 2;
        kayit.bayt += metin.length;
        kayit.gecis.push(`${yolAdi} -> ${ad}`);
        sonuc[ad] = bellek.get(ad)[disa](JSON.parse(metin), depo);
      }
      return sonuc;
    },
  };
}
```

Birleştirici bir işlev yoktur. Yanıt nesnesini çalıştırıcı kurar: yolun dizisindeki her adın sonucu
kendi adıyla toplanır.

## Beş Ölçüm

Sürücü betik beş soruyu yanıtlar: işlev dosyalarında kaç koşum satırı kalmıştır; bir isteğin
dokunduğu işlev ve sınırdan geçen bayt kaçtır; aynı üç gönderi sıcak ve soğuk koşumda hangi sonucu
verir; durumu depoya taşımanın satır ve erişim bedeli nedir; bileşime bir işlev eklemek kaç işlev
dosyası düzenletir.

```js
// sunucusuz/olc.mjs — kosum satiri, dokunulan islev, kurulum sayisi, durum sapmasi, bildirim maliyeti
import { readFileSync, writeFileSync } from "node:fs";
import { createHash } from "node:crypto";
import { kurulum } from "./sayac.mjs";
import { calistirici } from "./calistirici.mjs";
import { bildirim } from "./yol.mjs";

const GONDERI = [
  { id: "G1", agirlik: 4, bolge: "35", sozlesmeNo: "S7", oran: 0.15 },
  { id: "G2", agirlik: 1, bolge: "34", sozlesmeNo: "S7", oran: 0 },
  { id: "G3", agirlik: 12, bolge: "06", sozlesmeNo: "S9", oran: 0.25 },
];
const ISLEV = ["sunucusuz/ucret.mjs", "sunucusuz/operasyon.mjs", "sunucusuz/hacim.mjs"];
const KOSUM = /createServer|\.listen\(|writeHead|yanit\.end|process\.argv/;
const CAGIRMA = /await import|bildirim\.|JSON\.(stringify|parse)/;
const ozet = (d) => createHash("sha256").update(readFileSync(d)).digest("hex").slice(0, 12);

for (const d of [...ISLEV, "sunucusuz/calistirici.mjs"]) {
  const s = readFileSync(d, "utf8").split("\n").filter((x) => x.trim() !== "");
  const say = (r) => s.filter((x) => r.test(x)).length;
  console.log(`${d.padEnd(26)} satir = ${String(s.length).padStart(2)}, kosum = ${say(KOSUM)}, cagirma = ${say(CAGIRMA)}`);
}

async function kos(harita, yolAdi, gonderiler, soguk) {
  const k = { gecis: [], donusum: 0, bayt: 0, depo: 0 };
  const oncesi = kurulum.length;
  const c = calistirici(harita, k, { soguk });
  let son;
  for (const g of gonderiler) son = await c.cagir(yolAdi, g);
  return { k, kurulum: kurulum.length - oncesi, son };
}

const bicim = (ad, r) => `${ad.padEnd(20)} sinir gecisi = ${r.k.gecis.length}, donusum = ${r.k.donusum}, bayt = ${r.k.bayt}, kurulum = ${r.kurulum}, depo erisimi = ${r.k.depo}`;

const t = await kos(bildirim, "/teklif", [GONDERI[0]], false);
console.log(bicim("/teklif sicak", t));
console.log(`  sonuc = ${JSON.stringify(t.son)}`);

const sicak = await kos(bildirim, "/kayit", GONDERI, false);
const soguk = await kos(bildirim, "/kayit", GONDERI, true);
const depolu = await kos(bildirim, "/kayit-depolu", GONDERI, true);
for (const [ad, r, anahtar] of [["/kayit sicak", sicak, "hacim"], ["/kayit soguk", soguk, "hacim"], ["/kayit-depolu soguk", depolu, "hacim-depolu"]]) {
  console.log(`${bicim(ad, r)}\n  ${anahtar} = ${JSON.stringify(r.son[anahtar])}`);
}
console.log(`modul durumunun sapmasi = ${sicak.son.hacim.hacim - soguk.son.hacim.hacim} birim agirlik, ${sicak.son.hacim.sozlesme - soguk.son.hacim.sozlesme} sozlesme`);
const kaynak = readFileSync("sunucusuz/hacim.mjs", "utf8");
const satir = (ad) => kaynak.split(`export function ${ad}(`)[1].split("\n}")[0].split("\n").filter((s) => s.trim() !== "").length;
console.log(`durumu disariya tasimanin bedeli = ${satir("eleDepolu") - satir("ele")} satir`);

const oncekiOzet = ISLEV.map(ozet);
const eski = readFileSync("sunucusuz/yol.mjs", "utf8");
writeFileSync("sunucusuz/yol.mjs", eski.replace('"plan"]', '"plan", "hacim"]'));
const yeni = readFileSync("sunucusuz/yol.mjs", "utf8").split("\n");
const degisen = eski.split("\n").filter((s, i) => s !== yeni[i]).length;
const { bildirim: genis } = await import("./yol.mjs?s=2");
const g = await kos(genis, "/teklif", [GONDERI[0]], false);
writeFileSync("sunucusuz/yol.mjs", eski);
console.log(`bildirime hacim eklendi: duzenlenen islev dosyasi = ${ISLEV.filter((d, i) => ozet(d) !== oncekiOzet[i]).length}, bildirimde degisen satir = ${degisen}`);
console.log(bicim("/teklif yeniden", g));
console.log(`  gecis = ${g.k.gecis.join(", ")}`);
```

```sh
node sunucusuz/olc.mjs
```

```
sunucusuz/ucret.mjs        satir =  9, kosum = 0, cagirma = 0
sunucusuz/operasyon.mjs    satir =  8, kosum = 0, cagirma = 0
sunucusuz/hacim.mjs        satir = 14, kosum = 0, cagirma = 0
sunucusuz/calistirici.mjs  satir = 29, kosum = 0, cagirma = 5
/teklif sicak        sinir gecisi = 2, donusum = 4, bayt = 132, kurulum = 2, depo erisimi = 0
  sonuc = {"fiyat":{"id":"G1","net":5100},"plan":{"rota":["34","41","35"],"gun":3,"tasiyici":"MT"}}
/kayit sicak         sinir gecisi = 6, donusum = 12, bayt = 392, kurulum = 2, depo erisimi = 0
  hacim = {"sozlesme":2,"hacim":17}
/kayit soguk         sinir gecisi = 6, donusum = 12, bayt = 392, kurulum = 6, depo erisimi = 0
  hacim = {"sozlesme":1,"hacim":12}
/kayit-depolu soguk  sinir gecisi = 6, donusum = 12, bayt = 392, kurulum = 6, depo erisimi = 13
  hacim-depolu = {"sozlesme":2,"hacim":17}
modul durumunun sapmasi = 5 birim agirlik, 1 sozlesme
durumu disariya tasimanin bedeli = 2 satir
bildirime hacim eklendi: duzenlenen islev dosyasi = 0, bildirimde degisen satir = 1
/teklif yeniden      sinir gecisi = 3, donusum = 6, bayt = 198, kurulum = 3, depo erisimi = 0
  gecis = /teklif -> fiyat, /teklif -> plan, /teklif -> hacim
```

## Sayıların Okunması

İlk dört satır uygulamadan çıkan kodu sayıyor. Üç işlev dosyasının hiçbirinde koşum satırı yok:
`createServer`, `listen`, `writeHead` ya da `process.argv` geçen satır sayısı 0. Mikroservis
dersinde aynı tarama her dağıtım biriminde 6, üç birimde toplam 18 satır bulmuştu. O satırlar
silinmedi, yer değiştirdi: çalıştırıcının yerel durağı 29 satırdır ve çağırma taraması onda 5 satır
buluyor — hangi işlevin çalışacağına karar veren, gövdeyi serileştiren ve çözen satırlar. Gerçek bir
çalıştırıcıda bu 29 satır uygulamanın deposunda hiç bulunmaz; burada yazılmasının nedeni ölçümün tek
komutla koşabilmesidir.

İkinci kazanç birleştiricinin yokluğudur. Mikroservis düzeninde teklif isteğini karşılayan üçüncü
bir dağıtım birimi vardı: kendi sunucusunu taşıyor, iki servisi adıyla biliyor ve yanıtı
birleştiriyordu. Burada `/teklif` yolunun karşılığı bildirimdeki tek satırdır ve sonuç nesnesini
çalıştırıcı kurar. Tek istek için sınır geçişi 2, dönüşüm noktası 4, sınırdan geçen 132 bayt —
gönderi başına 66 bayt, iki geçişte iki kez.

Son iki satır bileşimin bildirime taşınmasının bedelini veriyor. Teklif isteğinin hacim indirimini
de tetiklemesi istendiğinde bildirimde 1 satır değişti ve işlev dosyalarının özetleri değişmedi:
düzenlenen işlev dosyası 0. Olay güdümlü derste aynı ekleme bileşim kökünde 1 satır koda mal
olmuştu; burada o satır da koddan çıktı. Karşılığı aynı satırdadır: sınır geçişi 2'den 3'e, dönüşüm
4'ten 6'ya, bayt 132'den 198'e çıktı. Bir isteğin maliyeti artık kodda değil bildirimde okunur, ve
bildirim yanlış yazıldığında çözümleyici uyarmaz.

## Durumun Gidecek Yeri

Üç `/kayit` koşumu aynı üç gönderiyi aynı sırayla verdi; üçünde de sınır geçişi 6, dönüşüm 12 ve
bayt 392 çıktı. Çalıştırıcı tarafında hiçbir fark yok. Ayrılan tek şey sonuçtur. Sıcak koşumda hacim
indirimi işlevi `{"sozlesme":2,"hacim":17}` bildirdi; soğuk koşumda aynı işlev
`{"sozlesme":1,"hacim":12}` bildirdi. Sapma 5 birim ağırlık ve 1 sözleşmedir. Kaynağı `hacim.mjs`
dosyasının modül düzeyindeki `toplam` eşlemesidir: modül her çağrıda yeniden kurulduğu için eşleme
boşaldı ve yalnız son gönderi sayıldı.

Bu, biçemin en sessiz kusurudur. Kod doğru, sonuç yanlış ve hata iletisi yok. Sıcak koşumda aynı kod
doğru sonucu verdiği için kusur, çalıştırıcının kap kararına bağlı olarak görünür ya da görünmez —
sınama sıcak bir kapta koşuyorsa hiç görünmez.

Düzeltme durumu işlevin dışına almaktır. `eleDepolu` aynı toplamı çalıştırıcının verdiği depoya
yazar ve soğuk koşumda `{"sozlesme":2,"hacim":17}` döndürür; sapma 0. Bedeli iki sayıda ölçüldü:
gövde 2 satır uzadı ve üç istek 13 depo erişimi üretti. Modül durumlu tasarımda bu sayı 0'dı. Depo
burada yerel bir eşlemedir; ayrı bir dağıtım birimi olduğunda o 13 erişimin her biri bir sınır
geçişi olur ve mikroservis dersinde sayılan ağ çağrılarına eklenir.

## Soğuk Başlatma Bir Model

Kurulum sayısı gerçek bir sayıdır: sıcak koşumda üç istek 2 kurulum yaptı, soğuk koşumda 6. İki
işlevin her biri her istekte yeniden kuruldu. Kurulumun *süresi* ise ölçülmedi. Modülün yüklenme
süresi makineye, dosya sistemine ve çalıştırıcının kendi hazırlığına bağlıdır; bu yüzden aşağıdaki
anlatım bir modeldir, ölçüm değildir.

Bir çağrının süresi iki parçaya ayrılır: kurulum işi $B$ ve asıl iş $I$. Çağrıların $c$ oranı yeni
bir örnek üzerinde başlıyorsa ortalama süre

$$\bar{T} = I + c \cdot B$$

olur. Model iki şey söyler. Birincisi, $c$ uygulamanın değil trafiğin biçiminin sonucudur: yoğun ve
sürekli trafikte kap yeniden kullanılır, seyrek ve düzensiz trafikte $c$ 1'e yaklaşır. Ölçümdeki
soğuk koşum $c = 1$ durumunun karşılığıdır. İkincisi, $B$'yi küçültmenin tek yolu kurulum işini
küçültmektir. `ucret.mjs` modül düzeyinde yalnız bir tarife nesnesi kurar; aynı yerde büyük bir
tablo ya da bir bağlantı havuzu kurulsaydı $B$ büyürdü. Biçemin işlev başına taşınabilecek kurulum
işine koyduğu sınır budur.

Sayılar bir kalite niteliği ödünleşimi betimliyor. Kazanılan nitelik sürdürülebilirliktir:
uygulamanın taşıdığı koşum satırı 0, yeni bir bileşim için düzenlenen işlev dosyası 0. Bırakılan
nitelikler ikidir. Başarım verimliliğinde öngörülebilirlik gider: aynı istek, çalıştırıcının kap
kararına göre 2 ya da 6 kurulum işi yapar ve o kararı uygulama vermez. Güvenilirlikte ise bellekte
biriken her değer, ölçülen 5 birimlik sapmanın adayı olur. Bu yüzden biçem çağrı başına bağımsız iş
için yerindedir; biriktiren iş ancak durumu dışarı taşıyarak, yani 13 erişimi ödeyerek girer.

## Özet

- Sunucusuz mimaride dağıtım birimi bir süreç değil, çağrıldığında koşan bir işlevdir; süreci ayakta
  tutma ve yönlendirme işi uygulamanın dışına çıkar.
- Üç işlev dosyasında koşum satırı 0 ölçüldü; mikroservis dersinde aynı tarama birim başına 6,
  toplam 18 satır bulmuştu. O satırların yerel karşılığı 29 satırlık çalıştırıcı durağıdır.
- Birleştirici işlev yoktur: `/teklif` yolunun karşılığı bildirimdeki bir satırdır, sonuç nesnesini
  çalıştırıcı kurar; tek istek 2 sınır geçişi, 4 dönüşüm noktası ve 132 bayt üretti.
- Bileşime bir işlev eklemek 0 işlev dosyası düzenletti, bildirimde 1 satır değiştirdi; aynı istek
  3 sınır geçişine, 6 dönüşüm noktasına ve 198 bayta çıktı.
- Modül düzeyinde biriken durum soğuk koşumda 5 birim ağırlık ve 1 sözleşme saptı; durumu depoya
  taşımak sapmayı 0'a indirdi, bedeli 2 satır ve 13 depo erişimi oldu.
- Soğuk başlatmanın sayılan yüzü kurulum sayısıdır: üç istek sıcak koşumda 2, soğuk koşumda 6
  kurulum yaptı. Süre bir modelle anlatılır, ölçülmez.

## Sonraki Adım

Beş biçem beş ayrı ölçü kümesi bıraktı: birlikte yayınlanan dosya sayısı, sınır geçişi, sınırdan
geçen bayt, bir birim durduğunda ayakta kalan birim sayısı, yeni bir yetenek için düzenlenen dosya
sayısı. Hiçbir biçem bu ölçülerin hepsinde önde değildi; her kazanç bir başka sayıyı büyüttü. Bu
durumda seçim nasıl yapılır ve bir seçimin savunması neye dayanır. Sonraki ders ölçüleri kalite
niteliklerine bağlar, aynı kuralları iki sınır yerleşiminde ortak temelde ölçer ve bir biçem
kararının hangi eşik altında haklı çıktığını, hangi eşik değiştiğinde döndüğünü gösterir; kursta
ölçülen sayılar orada tek bir karar tablosunda toplanır.
