---
title: 'Yatay ve Dikey Ölçekleme'
source: 'https://academia.sh/tr/kurslar/sistem-tasarimina-giris/yatay-ve-dikey-olcekleme'
course: 'Sistem Tasarımına Giriş'
language: tr
updated: '2026-08-17T18:10:57+00:00'
license: 'CC BY-SA 4.0'
---

# Yatay ve Dikey Ölçekleme

Kaynağı değiştirmenin iki yolu ve her birinin sert sınırı: aynı işin bir işçiden on altı işçiye bölünmesiyle hızlanmanın ve verimliliğin ölçülmesi, bölümleme kararının seri payı ve üst sınırı nasıl değiştirdiğinin sayılması, çekirdek sayısının dikey ölçeklemeye koyduğu sınırın ölçülmesi ve iki yolun maliyet eğrilerinin aynı hedef altında karşılaştırılması.

Önceki ders yükü değiştirdi ve kaynağı sabit tuttu; bütün ölçümler tek bir işçiyle alındı.
Kapasite hesabı da bu varsayımla geçerliydi. Kaynak ise değiştirilebilir bir büyüklüktür ve
değiştirilmesinin iki yolu vardır: aynı birimi büyütmek ya da birim sayısını artırmak. Bu ders
iki yolu ayırır, ikisinin de nerede durduğunu ölçer ve maliyetlerini aynı hedef altında
karşılaştırır.

Ayrımın adları katalogda geçtiği gibidir. **Dikey ölçekleme** (vertical scaling) ölçekleme
biriminin kendisini büyütmektir: aynı birime daha çok işlemci, daha çok bellek. **Yatay
ölçekleme** (horizontal scaling) birim sayısını artırmaktır. Sunucu Tarafı Temelleri kursunda
ölçekleme biriminin süreç olduğu ve süreçlerin bellek paylaşmadığı kurulmuştu; bu ders o
kuralın sonucunu bir ölçüye çevirir.

## Aynı İş, Artan İşçi Sayısı

Ölçülen iş gün sonu ücretlendirmesidir: otuz günü kapsayan 12 milyon kayıt fiyatlanır ve her
fatura satırı için bir denetim izi üretilir. Önceki derste kurulan gruplama birimi geçerlidir —
bir **bölüm** bir satıcının bir günüdür, dolayısıyla otuz günlük taramada 120 000 bölüm vardır
(4000 satıcı çarpı 30 gün). İş bir işçiden on altı işçiye kadar bölünür ve her düzeyde toplam
süre ölçülür. Kayıtlar okunmaz, deterministik olarak üretilir; ölçülen şey hesap payının
paralelleşmesidir, girdi-çıktı değildir.

```js
// olcek/isci.mjs — bir isci: kendi payindaki kalemleri fiyatlar, imzalar ve bolum toplamlarini dondurur
import { parentPort, workerData } from "node:worker_threads";

const TARIFE = { kademe: [[1, 3000], [5, 4800], [20, 9600]], bolge: { "34": 100, "06": 115, "35": 125 }, asgari: 2500 };
const BOLGE = ["34", "06", "35"];

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

function imza(metin) {              // fatura satirinin denetim izi
  let h = 2166136261;
  for (let i = 0; i < metin.length; i += 1) h = Math.imul(h ^ metin.charCodeAt(i), 16777619) >>> 0;
  return h;
}

function pay({ bas, bit, adim, bolum }) {
  const toplam = new Map();
  for (let i = bas; i < bit; i += adim) {
    const b = i % bolum;
    const deger = net((i % 20) + 1, BOLGE[i % 3], (i % 5) / 20);
    const iz = imza(`G${i};${BOLGE[i % 3]};${deger}`);
    const onceki = toplam.get(b) ?? { net: 0, iz: 0 };
    toplam.set(b, { net: onceki.net + deger, iz: (onceki.iz ^ iz) >>> 0 });
  }
  return [...toplam];
}

if (workerData === null) console.log("bu dosya olcek/kos.mjs tarafindan isci olarak calistirilir");
else parentPort.postMessage(pay(workerData));
```

```
bu dosya olcek/kos.mjs tarafindan isci olarak calistirilir
```

Kalem sayısı V3 ile V11'in çarpımıdır ve Kabaca Büyüklük Hesabı dersindeki tablodan gelir; bu
ders kendi hacim sayısını seçmez. Bölüm sayısı V13'ten türetilir: fatura satırına yüz
kalem toplandığına göre on iki milyon kalem 120 000 bölüme düşer. Bölüm sayısı
satıcı sayısı değildir — 4000 satıcının otuz günü 120 000 satıcı-gün eder.

Sürücü işi iki farklı biçimde böler. **İndis** bölümlemesi kalemleri bitişik bloklara ayırır;
bir bölümün kalemleri bütün işçilere dağılır. **Anahtar** bölümlemesi adımlı ilerler; her bölüm
tek bir işçiye düşer. İkisi de aynı sayıda kalem işler ve aynı sonucu üretmelidir.

```js
// olcek/kos.mjs — ayni is 1..16 isciye bolunur; hizlanma, verimlilik ve birlestirme payi olculur
import { Worker } from "node:worker_threads";
import { availableParallelism } from "node:os";

const KALEM = 12_000_000;          // V3 x V11: otuz gunu kapsayan kayit sayisi
const BOLUM = KALEM / 100;         // varsayim: bir fatura satirina 100 kalem -> 4000 satici x 30 gun
const ISCI = [1, 2, 4, 8, 12, 16];

function isci(veri) {
  return new Promise((coz, sap) => {
    const w = new Worker(new URL("./isci.mjs", import.meta.url), { workerData: veri });
    w.on("message", coz);
    w.on("error", sap);
  });
}

function bolumler(n, kip) {        // "indis": bitisik blok, "anahtar": adimli
  return kip === "indis"
    ? Array.from({ length: n }, (_, s) => ({ bas: Math.floor((s * KALEM) / n), bit: Math.floor(((s + 1) * KALEM) / n), adim: 1, bolum: BOLUM }))
    : Array.from({ length: n }, (_, s) => ({ bas: s, bit: KALEM, adim: n, bolum: BOLUM }));
}

async function kos(n, kip) {
  const bas = performance.now();
  const paylar = await Promise.all(bolumler(n, kip).map(isci));
  const paralel = performance.now() - bas;
  const birlesikBas = performance.now();
  const fatura = new Map();
  let cakisma = 0;
  for (const pay of paylar) {
    for (const [b, v] of pay) {
      const onceki = fatura.get(b);
      if (onceki === undefined) fatura.set(b, { ...v });
      else { onceki.net += v.net; onceki.iz = (onceki.iz ^ v.iz) >>> 0; cakisma += 1; }
    }
  }
  const birlestirme = performance.now() - birlesikBas;
  const imza = [...fatura].reduce((a, [, v]) => (a ^ v.iz) >>> 0, 0);
  return { paralel, birlestirme, toplam: paralel + birlestirme, bolum: fatura.size, cakisma, imza };
}

console.log(`cekirdek = ${availableParallelism()}, kalem = ${KALEM}, bolum = ${BOLUM}`);
for (const kip of ["indis", "anahtar"]) {
  console.log(`\nbolumleme = ${kip}`);
  console.log("isci   paralel(ms)  birlestirme(ms)  toplam(ms)  hizlanma  verimlilik  cakisan kayit  imza");
  let taban = 0;
  for (const n of ISCI) {
    const r = await kos(n, kip);
    if (n === 1) taban = r.toplam;
    console.log(`${String(n).padStart(4)}  ${r.paralel.toFixed(0).padStart(11)}  ${r.birlestirme.toFixed(1).padStart(15)}  ` +
      `${r.toplam.toFixed(0).padStart(10)}  ${(taban / r.toplam).toFixed(2).padStart(8)}  ` +
      `${(taban / r.toplam / n).toFixed(2).padStart(10)}  ${String(r.cakisma).padStart(13)}  ${r.imza}`);
  }
}
```

```
cekirdek = 12, kalem = 12000000, bolum = 120000

bolumleme = indis
isci   paralel(ms)  birlestirme(ms)  toplam(ms)  hizlanma  verimlilik  cakisan kayit  imza
   1         1674              8.4        1683      1.00        1.00              0  799471432
   2          941             13.3         954      1.76        0.88         120000  799471432
   4          602             24.6         626      2.69        0.67         360000  799471432
   8          580             42.9         622      2.70        0.34         840000  799471432
  12          883             70.6         953      1.76        0.15        1320000  799471432
  16          882             68.3         950      1.77        0.11        1800000  799471432

bolumleme = anahtar
isci   paralel(ms)  birlestirme(ms)  toplam(ms)  hizlanma  verimlilik  cakisan kayit  imza
   1         1662              9.9        1672      1.00        1.00              0  799471432
   2          879              5.6         885      1.89        0.94              0  799471432
   4          549              5.5         554      3.02        0.75              0  799471432
   8          321              6.8         328      5.11        0.64              0  799471432
  12          284              5.5         289      5.79        0.48              0  799471432
  16          364              6.9         370      4.51        0.28              0  799471432
```

Bu sayılar ölçümdür ve bu makinede alınmıştır; çekirdek sayısı 12'dir ve başka bir makinede
tablonun kırılma noktası başka yerdedir. İmza sütunu on iki koşumda da aynı değeri veriyor
(799471432), yani bütün bölümlemeler aynı faturayı üretti; farklı sonuç veren koşumların
süreleri karşılaştırılamaz. Tek işçili iki taban süresi 1683 ve 1672 milisaniyedir; aradaki
fark ölçüm gürültüsüdür ve bu yüzden hızlanma her kipin kendi tabanına göre okunur.

## Bir Sert Sınır

Anahtar bölümlemesinde hızlanma 1'den 12 işçiye kadar büyüyor: 1,89, 3,02, 5,11 ve 5,79. On altı
işçide **düşüyor**: 4,51. Bu düşüş ölçüm hatası değil, dikey ölçeklemenin sınırının ta kendisi.
Makinede 12 çekirdek var; on altı işçi on iki çekirdeği paylaşmak zorundadır ve paylaşımın
kendisi bir maliyettir. Birimi büyütmenin bir noktada duracağı sezgisel bir iddia değil,
tabloda okunan bir sayıdır.

Verimlilik sütunu aynı şeyi başka açıdan söylüyor. **Paralel verimlilik** (parallel efficiency)
işçi başına elde edilen hızlanma payıdır, yani hızlanmanın işçi sayısına bölümü; Kalite
Nitelikleri dersinin başarım verimliliği ailesiyle karıştırılmamalıdır, o bir nitelik ailesinin
adıdır. Ölçümde iki işçide 0,94, dört işçide 0,75, sekiz işçide 0,64, on iki işçide 0,48.
**Her eklenen işçi öncekinden az getirir.** Değerin 1'in altına düşmesi bir kusur değil, paralel
işin doğasıdır; kararı ilgilendiren şey ne kadar hızlı düştüğüdür.

## Yatay Ölçeklemenin Koşulu

İki bölümlemenin farkı dersin ikinci sonucudur. Aynı iş, aynı işçi sayısı, aynı makine — sekiz
işçide hızlanma anahtar bölümlemesinde 5,11, indis bölümlemesinde 2,70. Neredeyse iki katı fark
yalnızca **işin nasıl bölündüğünden** geliyor.

Farkın kaynağı çakışan kayıt sütununda. İndis bölümlemesinde on altı işçi 1 800 000 çakışan
kayıt üretti: bir bölümün toplamı birden çok işçide parça parça durduğu için her parça
birleştirme adımında toplanmak zorunda. Anahtar bölümlemesinde bu sayı sıfırdır. Birleştirme
süresi de buna göre ayrışıyor: on altı işçide 68,3 milisaniyeye karşı 6,9 milisaniye.

Sunucu Tarafı Temelleri kursunda durumsuz süreç kuralı konmuştu: istekler arasında yaşaması
gereken durum süreç dışına taşınır. Buradaki ölçüm o kuralın ölçekleme tarafındaki karşılığıdır.
Yatay ölçekleme birim sayısını artırmakla olmaz; **işin, birimler arasında paylaşılan durum
gerektirmeyecek biçimde bölünebilmesiyle** olur. Bölümleme anahtarının seçimi bu yüzden bir
ayrıntı değil, ölçeklenebilirlik kararının kendisidir. Bölüm ve bölümleme terimleri İleri SQL
kursunda tablo bölümleme bağlamında kurulmuştu; buradaki bağlam işin işçilere bölünmesidir,
verinin diske değil.

## Seri Pay, Üst Sınır ve Maliyet

Ölçülen hızlanmadan bir sayı daha çıkarılabilir. İşin bir kısmı bölünemez — işçilerin
başlatılması, payların toplanması, sonucun yazılması. Bu **seri pay** $s$ ise, $n$ işçiyle en
iyi hızlanma şudur:

$$
S(n) = \frac{1}{s + \dfrac{1 - s}{n}}
$$

Bağıntı tersten çözülünce ölçülen bir hızlanmadan seri pay çıkar, ve $n$ sonsuza giderken
hızlanma $1/s$ ile sınırlanır. Aşağıdaki hesap bunu iki bölümleme için yapar, sonra bir hedefi
karşılamanın iki yoldaki maliyetini karşılaştırır. Dikey maliyet için bir **varsayım** gerekir:
birimin gücü iki katına çıktığında birim maliyeti kaç katına çıkar. Üç değer birlikte veriliyor
çünkü sonuç bu varsayıma duyarlıdır.

```js
// hesap/maliyet.mjs — olculen hizlanmadan seri pay, ust sinir ve iki yolun maliyeti
const OLCUM = { anahtar: { isci: 8, hizlanma: 5.11 }, indis: { isci: 8, hizlanma: 2.70 } };
const MAKINE_SINIRI = 5.79;        // olculen: bu makinede tek birimin en yuksek hizlanmasi (12 cekirdek)

const seriPay = (n, S) => (1 / S - 1 / n) / (1 - 1 / n);
const amdahl = (s, n) => 1 / (s + (1 - s) / n);
const gerekenBirim = (s, K) => (1 - s) / (1 / K - s);

console.log("bolumleme   olculen(isci/hizlanma)   seri pay   ust sinir(1/s)");
for (const [ad, o] of Object.entries(OLCUM)) {
  const s = seriPay(o.isci, o.hizlanma);
  console.log(`${ad.padEnd(12)}${`${o.isci} / ${o.hizlanma.toFixed(2)}`.padStart(21)}${(s * 100).toFixed(1).padStart(11)}%` +
    `${(1 / s).toFixed(1).padStart(17)}`);
}

const s = seriPay(OLCUM.anahtar.isci, OLCUM.anahtar.hizlanma);
console.log("\nhedef  yatay birim   yatay maliyet   dikey x2.0   dikey x2.5   dikey x3.0   dikey ulasilir");
for (const K of [2, 4, 8, 16]) {
  const birim = gerekenBirim(s, K);
  const dikey = (c) => c ** Math.log2(K);
  console.log(`${`x${K}`.padStart(5)}${(birim > 0 ? birim.toFixed(1) : "ulasilmaz").padStart(13)}` +
    `${(birim > 0 ? birim.toFixed(1) : "-").padStart(16)}${dikey(2.0).toFixed(1).padStart(13)}` +
    `${dikey(2.5).toFixed(1).padStart(13)}${dikey(3.0).toFixed(1).padStart(13)}` +
    `${String(K <= MAKINE_SINIRI).padStart(15)}`);
}

console.log(`\n16 isciye kadar amdahl ongorusu (anahtar bolumlemesi, s = ${(s * 100).toFixed(1)}%):`);
console.log([1, 2, 4, 8, 12, 16].map((n) => `${n}:${amdahl(s, n).toFixed(2)}`).join("  "));
```

```
bolumleme   olculen(isci/hizlanma)   seri pay   ust sinir(1/s)
anahtar                  8 / 5.11        8.1%             12.4
indis                    8 / 2.70       28.0%              3.6

hedef  yatay birim   yatay maliyet   dikey x2.0   dikey x2.5   dikey x3.0   dikey ulasilir
   x2          2.2             2.2          2.0          2.5          3.0           true
   x4          5.4             5.4          4.0          6.3          9.0           true
   x8         20.8            20.8          8.0         15.6         27.0          false
  x16    ulasilmaz               -         16.0         39.1         81.0          false

16 isciye kadar amdahl ongorusu (anahtar bolumlemesi, s = 8.1%):
1:1.00  2:1.85  4:3.22  8:5.11  12:6.35  16:7.23
```

Seri pay satırları bölümleme kararının bedelini tek sayıya indiriyor: anahtar bölümlemesinde
%8,1 ve üst sınır 12,4; indis bölümlemesinde %28,0 ve üst sınır 3,6. Aynı iş, aynı donanım —
üst sınır üç kattan fazla ayrışıyor. İndis bölümlemesi seçilmiş bir sistemde on altı yerine bin
birim eklense hızlanma 3,6'yı geçmez.

Maliyet tablosu iki eğrinin biçimini gösteriyor. Yatay maliyet birim sayısıyla doğrusal ödenir
ama gereken birim sayısı doğrusal değildir: iki kat için 2,2 birim, dört kat için 5,4, sekiz kat
için 20,8. On altı kat satırında sayı yerine "ulaşılmaz" yazıyor, çünkü hedef seri payın koyduğu
12,4 üst sınırının üstündedir — o hedefe kaç birim eklenirse eklensin varılamaz. Dikey maliyet
ise varsayıma tamamen bağlı: çarpan 2,0 ise sekiz kat için 8,0 birim — yataydan ucuz; çarpan
3,0 ise 27,0 birim — yataydan pahalı.

Son sütun tartışmayı bitiriyor. Dikey yolun sekiz katına çıkması bu makinede **mümkün değil**,
çünkü ölçülen en yüksek hızlanma 5,79'dur. Dikey ölçeklemenin asıl sorunu maliyet eğrisi değil,
eğrinin bir yerde bitmesidir. Yatay yol pahalıdır ama sınırı seri paydan gelir, donanımdan
değil — ve seri pay bir tasarım kararıdır, ölçüm tablosunun ilk satırı bunu gösteriyor.

Son satır modelin kendi sınırını da gösteriyor. Bağıntı on iki işçi için 6,35, on altı işçi için
7,23 hızlanma öngörüyor; ölçülen değerler 5,79 ve 4,51'dir. Model çekirdek sayısını bilmez ve
hiç düşmez. **Bir modelin öngörüsü ölçümden ayrıldığında düzeltilecek olan ölçüm değil, modelin
varsayımıdır** — burada eksik varsayım işçi başına bir çekirdeğin bulunmasıdır.

## Özet

- Dikey ölçekleme ölçekleme birimini büyütmek, yatay ölçekleme birim sayısını artırmaktır;
  ikisi farklı sınırlara çarpar.
- Anahtar bölümlemesinde hızlanma 12 işçide 5,79'a çıktı, 16 işçide 4,51'e düştü: çekirdek
  sayısı dikey yolun ölçülen sert sınırıdır.
- Paralel verimlilik her eklenen işçiyle düşüyor: 2 işçide 0,94, 8 işçide 0,64, 12 işçide 0,48.
- İşin bölünme biçimi hızlanmayı neredeyse iki katı değiştirdi: sekiz işçide 5,11'e karşı 2,70.
  İndis bölümlemesi 16 işçide 1 800 000 çakışan kayıt ve 68,3 ms birleştirme üretti, anahtar
  bölümlemesi 0 ve 6,9 ms.
- Ölçülen hızlanmadan çıkan seri pay anahtar bölümlemesinde %8,1 (üst sınır 12,4), indis
  bölümlemesinde %28,0 (üst sınır 3,6); bölümleme anahtarı bir ölçeklenebilirlik kararıdır.
- Hedefi sekiz katına çıkarmak yatay yolda 20,8 birim ister, dikey yolda bu makinede
  ulaşılamaz; on altı kat yatay yolda da ulaşılmazdır, çünkü seri pay üst sınırı 12,4'te tutar.

## Sonraki Adım

Buraya kadarki üç ders sistemin **çalıştığı** varsayımıyla ölçüm yaptı. Yük, kapasite, hızlanma
ve maliyet — hepsi ayakta bir sistemin sayılarıdır. Ölçeklemenin gerekçesi de tek başına yük
değildir: on iki milyon kaydı 289 milisaniyede tarayan bir düzenek zaten yeterken birim sayısını
artırmanın başka bir nedeni olmalıdır. O neden birimlerin ayakta kalmamasıdır. Bir birim durduğunda
sistemin ne kadarı durur, ne kadar süre durur ve bu süre kabul edilebilir midir? Üçüncü soru bir
yüzdeyle yanıtlanır ve yüzde tek başına hiçbir şey söylemez: yüzde doksan dokuz ile yüzde doksan
dokuz virgül dokuz arasındaki fark, dakika olarak yazılana kadar görünmez. Sonraki ders hizmet
erişilebilirliğini bir kesinti bütçesine çevirir ve bileşenlerin birleştirilmesinin bu bütçeye ne
yaptığını hesaplar.
