---
title: Federasyon
source: 'https://academia.sh/tr/kurslar/veri-olcekleme/federasyon'
course: 'Veri Katmanı Ölçekleme'
language: tr
updated: '2026-08-17T18:11:02+00:00'
license: 'CC BY-SA 4.0'
---

# Federasyon

Verinin anahtara göre değil işleve göre bölünmesi: ücretlendirme ile teslimat operasyonu bağlamlarının kendi depolarına ayrılması, iki bağlama birden dokunan sorgunun dokunduğu depo ve depolar arasında taşınan anahtar sayısının gerçek bir motorda ölçülmesi, ortak alanların yinelenmesinin saklanan veriye eklediği payın hesaplanması ve toplu taramanın çevrimiçi depodan çıkarılması.

Çoğaltma okumayı böldü ama her düğüme aynı 194,44 yazmayı bıraktı ve saklanan veriyi kopya
sayısıyla çarptı. İki sınır da aynı yerden geliyor: **bütün veri her yerde duruyor.** Oysa deponun
taşıdığı veri tek bir bütün değil. Ücretlendirmenin sorduğu sorularla teslimat operasyonunun
sorduğu sorular farklı kayıtlara dokunuyor; 01. dersin tarama ölçümü bunu göstermişti — dönem
taraması olay ayrıntısına hiç ihtiyaç duymadan 21.000 kayıttan 3000 kayda inmişti.

**Federasyon** (federation), veriyi anahtara göre değil **işleve göre** bölmektir: her bağlam kendi
deposunu alır ve o depo yalnız o bağlamın sorularına hizmet eder. Ayrım anahtarla ilgili değildir
— aynı takip numarası iki depoda da geçebilir; ayrım, o numaranın hangi soruyla sorulduğuyla
ilgilidir.

## İki Bağlam, İki Depo

Gönderi takip ve ücretlendirme servisinde iki bağlam vardır. **Teslimat operasyonu** P1 ile P2'yi
taşır: takip numarasına göre tekil okuma ve taşıyıcıdan gelen durum olayı yazması. **Ücretlendirme**
P3'ü taşır: satıcıya göre dönemsel toplu tarama, tarife, sözleşme ve fatura satırı.

Bölme kusursuz değildir, çünkü iki bağlam bazı kayıtlara birlikte ihtiyaç duyar. Ücretlendirme
gönderinin ne zaman kabul edildiğini ve ne zaman teslim edildiğini bilmek zorundadır, ama aradaki
rota adımlarını bilmesi gerekmez.

**VD4 — ücretlendirmeyi ilgilendiren olay oranı 2/7.** Gerekçe: fatura kabul ve teslim zamanına
bağlıdır; V4'ün yedi olayından yalnız ikisi ücreti etkiler. Duyarlılığı aşağıda 3/7 ile verilir.

**VD5 — gönderi kaydı iki bağlama bölündüğünde payları 500 ve 600 bayttır.** Gerekçe: V7'nin 900
baytlık kaydında ağırlık, hacim, sözleşme ve tarife ücretlendirmeye, bölge ve rota alanları
operasyona gider; takip numarası, satıcı kimliği ve dönem etiketi ise iki depoda da durmak zorunda
olduğu için toplam 1100 bayta çıkar, yinelenen pay 200 bayttır. Duyarlılığı aşağıda 400 bayt
yinelenme ile verilir.

İki varsayım da K01'in tablosuna eklenmez.

## Bölünen Sorgu Kaç Depoya Dokunuyor

Aşağıdaki düzenek üç depoyu bellek içinde kurar — federasyonsuz tek depo ile iki federe depo — ve
aynı soruları her ikisine sorar. Ölçülen şey **dokunulan depo sayısı**, **işlenen kayıt** ve
federe düzende **depolar arasında taşınan anahtar** sayısıdır.

```js
// federasyon/capraz.mjs — ayni sorgularin tek depoda ve iki federe depoda dokundugu depo,
// isledigi kayit ve depolar arasinda tasidigi anahtar. node:sqlite ile gercek bir motor kosar.
import { DatabaseSync } from "node:sqlite";

const SATICI = 20, GUN = 30, GUNLUK = 100, OLAY = 7, SON = OLAY - 1;   // model olcegi
const [tek, ucret, ops] = [0, 1, 2].map(() => new DatabaseSync(":memory:"));
tek.exec(`CREATE TABLE gonderi(no TEXT PRIMARY KEY, satici INT, gun INT, tarife INT, bolge INT);
CREATE INDEX g_satici ON gonderi(satici, gun);
CREATE TABLE olay(no TEXT, sira INT, durum TEXT); CREATE INDEX o_no ON olay(no);`);
ucret.exec(`CREATE TABLE gonderi(no TEXT PRIMARY KEY, satici INT, gun INT, tarife INT);
CREATE INDEX g_satici ON gonderi(satici, gun);
CREATE TABLE olay(no TEXT, sira INT, durum TEXT); CREATE INDEX o_no ON olay(no);`);
ops.exec(`CREATE TABLE gonderi(no TEXT PRIMARY KEY, satici INT, bolge INT);
CREATE TABLE olay(no TEXT, sira INT, durum TEXT); CREATE INDEX o_no ON olay(no);`);

const sayac = { tek: 0, ucret: 0, ops: 0 };
for (const [ad, db] of [["tek", tek], ["ucret", ucret], ["ops", ops]])
  db.function("say", { deterministic: false }, (x) => { sayac[ad] += 1; return x; });
const toplam = () => sayac.tek + sayac.ucret + sayac.ops;

const gT = tek.prepare("INSERT INTO gonderi VALUES(?,?,?,?,?)"), oT = tek.prepare("INSERT INTO olay VALUES(?,?,?)");
const gU = ucret.prepare("INSERT INTO gonderi VALUES(?,?,?,?)"), oU = ucret.prepare("INSERT INTO olay VALUES(?,?,?)");
const gO = ops.prepare("INSERT INTO gonderi VALUES(?,?,?)"), oO = ops.prepare("INSERT INTO olay VALUES(?,?,?)");
for (const d of [tek, ucret, ops]) d.exec("BEGIN");
for (let s = 0; s < SATICI; s += 1) for (let d = 0; d < GUN; d += 1) for (let k = 0; k < GUNLUK; k += 1) {
  const no = `TR-${s}-${d}-${k}`;
  gT.run(no, s, d, 100 + s, d % 5); gU.run(no, s, d, 100 + s); gO.run(no, s, d % 5);
  for (let i = 0; i < OLAY; i += 1) {
    oT.run(no, i, `durum${i}`); oO.run(no, i, `durum${i}`);
    if (i === 0 || i === SON) oU.run(no, i, `durum${i}`);      // VD4: yalniz kabul ve teslim
  }
}
for (const d of [tek, ucret, ops]) d.exec("COMMIT");
const adet = (db, t) => db.prepare(`SELECT count(*) c FROM ${t}`).get().c;
console.log(`model: ${adet(tek, "gonderi")} gonderi; olay kaydi -> tek depo ${adet(tek, "olay")}, ` +
  `teslimat ${adet(ops, "olay")}, ucretlendirme ${adet(ucret, "olay")}`);

const capraz = () => {                                          // anahtarlari tasiyip ikinci depoya sormak
  const a = ucret.prepare("SELECT say(no) AS no FROM gonderi WHERE satici = ?").all(10).map((r) => r.no);
  const q = ops.prepare(`SELECT say(no) FROM olay WHERE no = ? AND sira = ${SON}`);
  for (const k of a) q.all(k);
  return a.length;
};
const IS = [
  ["P1 tekil okuma / federe", 1, () =>
    (ops.prepare("SELECT say(no) FROM olay WHERE no = ? ORDER BY sira DESC LIMIT 3").all("TR-10-15-50"), 0)],
  ["P3 donem taramasi / federe", 1, () =>
    (ucret.prepare("SELECT say(no) FROM gonderi WHERE satici = ? AND gun BETWEEN 0 AND 29").all(10), 0)],
  ["S4 son rota adimi / tek depo", 1, () => (tek.prepare(
    `SELECT say(g.no), o.durum FROM gonderi g JOIN olay o ON o.no = g.no WHERE g.satici = ? AND o.sira = ${SON}`).all(10), 0)],
  ["S4 son rota adimi / federe", 2, capraz],
  ["S5 teslim tarihine gore ucret / federe", 1, () => (ucret.prepare(
    `SELECT say(g.no), g.tarife FROM gonderi g JOIN olay o ON o.no = g.no WHERE g.satici = ? AND o.sira = ${SON}`).all(10), 0)],
  ["S5 teslim olayi kopyalanmasaydi", 2, capraz],
];
console.log(`\n${"sorgu / duzen".padEnd(40)}${"depo".padStart(6)}${"islenen kayit".padStart(15)}${"tasinan anahtar".padStart(17)}`);
for (const [ad, depo, calis] of IS) {
  sayac.tek = 0; sayac.ucret = 0; sayac.ops = 0;
  const anahtar = calis();
  console.log(`${ad.padEnd(40)}${String(depo).padStart(6)}${String(toplam()).padStart(15)}${String(anahtar).padStart(17)}`);
}
const bayt = Buffer.byteLength("TR-10-15-50");
console.log(`\nanahtar ${bayt} bayt: federe duzende S4 icin depolar arasinda ` +
  `${(3000 * bayt) / 1000} kB tasiniyor, tek depoda 0`);
```

```
model: 60000 gonderi; olay kaydi -> tek depo 420000, teslimat 420000, ucretlendirme 120000

sorgu / duzen                             depo  islenen kayit  tasinan anahtar
P1 tekil okuma / federe                      1              7                0
P3 donem taramasi / federe                   1           3000                0
S4 son rota adimi / tek depo                 1           3000                0
S4 son rota adimi / federe                   2           6000             3000
S5 teslim tarihine gore ucret / federe       1           3000                0
S5 teslim olayi kopyalanmasaydi              2           6000             3000

anahtar 11 bayt: federe duzende S4 icin depolar arasinda 33 kB tasiniyor, tek depoda 0
```

Bu sayılar **ölçüm** sınıfındadır; bu makinede koşan bir motordan gelirler ve belirlenimlidirler.

İlk iki satır iyi haberi veriyor: bağlamın kendi soruları kendi deposunda kalıyor ve tek depodaki
maliyetleriyle aynı. Federasyon bu sorulara ne kazandırıyor ne kaybettiriyor.

Dört ve beşinci satırlar asıl bilgiyi taşıyor. **S4 — bir satıcının dönemindeki gönderilerin son
rota adımı** iki bağlamın kesişiminde duruyor: satıcı ve dönem ücretlendirmenin, rota adımı
operasyonun alanıdır. Tek depoda bu tek bir sorgudur, motor birleştirmeyi kendi içinde yapar ve
3000 kayıt işler. Federe düzende sorgu ikiye bölünüyor: ücretlendirmeden 3000 anahtar okunuyor,
uygulama bunları taşıyıp teslimat deposuna soruyor ve toplam işlenen kayıt 6000'e çıkıyor. Kaybolan
şey birleştirmenin kendisidir; yerine geçen şey **depolar arasında taşınan 3000 anahtar**, yani 33
kilobayttır. Federasyonun uygulamaya asıl dayattığı bedel budur — motorun bedava yaptığı işi
uygulama kodu para vererek yapar.

Son iki satır VD4'ün gerekçesini ölçüyor. **S5 — teslim tarihine göre ücret**, teslim olayının
kopyası ücretlendirme deposunda olduğu için tek depoda kalıyor ve 3000 kayıtla bitiyor. Kopya
olmasaydı aynı soru S4 ile aynı biçime düşer: 2 depo, 6000 kayıt, 3000 taşınan anahtar. Yani
**yinelenen 2/7 olay, bir çapraz sorguyu tek depoya indiriyor.** Bir bağlam sınırının doğru çizilip
çizilmediğinin ölçüsü budur: sınırın doğru yerde olması, çapraz soru sayısının küçük olmasıdır.

## Hesaba Geri Dönüş

Yinelemenin bedeli K01'in iki büyüme satırında toplanıyor.

```js
// federasyon/hesap.mjs — iki baglama bolunen deponun K01 satirlarindaki karsiligi
const V3 = 400_000, V4 = 7, V6 = 220, V7 = 900, V8 = 3, V12 = 730;   // K01 varsayimlari
const OKUMA = 41.67, OLAY_YAZMA = 97.22, TARAMA = 833.33;            // K01 hesaplari
const ARTIS = 976, SAKLAMA = 712.48;                                  // K01 hesaplari
const BELGE = 194.44;          // 01. ders: durum olayi teslimat tarafinda 2 hedefe yaziliyor
const VD4 = 2 / 7;             // varsayim: ucretlendirmeyi ilgilendiren olay orani
const VD5 = [500, 600];        // varsayim: bolunen gonderi kaydinin paylari (ucret, ops) bayt
const GONDERI_YAZMA = 13.89;   // K01 turevi: (V3 / 86.400) x V8 = gonderi olusturma, tepe kayit/s
const b = (x, n = 2) => x.toFixed(n);

const ops = GONDERI_YAZMA + BELGE + OKUMA;
const uc = GONDERI_YAZMA + OLAY_YAZMA * VD4;
console.log(`${"depo".padEnd(24)}${"istek+islem/s".padStart(14)}${"tarama kayit/s".padStart(16)}` +
  `${"gunluk MB".padStart(11)}${"saklanan GB".padStart(13)}`);
const opsMB = (V3 * VD5[1] + V3 * V4 * V6) / 1e6, ucMB = (V3 * VD5[0] + V3 * V4 * VD4 * V6) / 1e6;
console.log(`${"teslimat operasyonu".padEnd(24)}${b(ops).padStart(14)}${"0".padStart(16)}` +
  `${b(opsMB).padStart(11)}${b((opsMB * V12) / 1000).padStart(13)}`);
console.log(`${"ucretlendirme".padEnd(24)}${b(uc).padStart(14)}${b(TARAMA).padStart(16)}` +
  `${b(ucMB).padStart(11)}${b((ucMB * V12) / 1000).padStart(13)}`);
console.log(`${"tek depo (federasyonsuz)".padEnd(24)}${b(GONDERI_YAZMA + BELGE + OKUMA).padStart(14)}` +
  `${b(TARAMA).padStart(16)}${b(ARTIS).padStart(11)}${b(SAKLAMA).padStart(13)}`);

const toplamMB = opsMB + ucMB;
console.log(`\ntoplam islem ${b(ops + uc)} /s = tek deponun ${b((ops + uc) / (GONDERI_YAZMA + BELGE + OKUMA))} kati`);
console.log(`gunluk yazilan ${b(toplamMB)} MB (K01: ${ARTIS}) = ${b(toplamMB / ARTIS)} kat`);
console.log(`saklanan ${b((toplamMB * V12) / 1000)} GB (K01: ${SAKLAMA}) = ${b((toplamMB * V12) / 1000 / SAKLAMA)} kat`);
const yol = (GONDERI_YAZMA * 2 + OLAY_YAZMA * (1 + VD4)) / (GONDERI_YAZMA + OLAY_YAZMA);
console.log(`yazma yolunun uzunlugu = ${b(yol, 3)} depo (gonderi 2, durum olayi ${b(1 + VD4, 3)})`);

const duyarli = (vd4, yin) => ((V3 * (V7 + yin) + V3 * V4 * V6 * (1 + vd4)) / 1e6);
console.log(`\nduyarlilik: VD4 = 3/7 -> gunluk ${b(duyarli(3 / 7, 200))} MB, ` +
  `saklanan ${b((duyarli(3 / 7, 200) * V12) / 1000)} GB`);
console.log(`            yinelenen kimlik 400 bayt -> gunluk ${b(duyarli(VD4, 400))} MB, ` +
  `saklanan ${b((duyarli(VD4, 400) * V12) / 1000)} GB`);
console.log(`ucu birden: 01'in belge deposu 5,76 GB eklenir, 02'nin uc kopyasiyla ` +
  `${b(3 * ((toplamMB * V12) / 1000 + 5.76))} GB`);
```

```
depo                     istek+islem/s  tarama kayit/s  gunluk MB  saklanan GB
teslimat operasyonu             250.00               0     856.00       624.88
ucretlendirme                    41.67          833.33     376.00       274.48
tek depo (federasyonsuz)        250.00          833.33     976.00       712.48

toplam islem 291.67 /s = tek deponun 1.17 kati
gunluk yazilan 1232.00 MB (K01: 976) = 1.26 kat
saklanan 899.36 GB (K01: 712.48) = 1.26 kat
yazma yolunun uzunlugu = 1.375 depo (gonderi 2, durum olayi 1.286)

duyarlilik: VD4 = 3/7 -> gunluk 1320.00 MB, saklanan 963.60 GB
            yinelenen kimlik 400 bayt -> gunluk 1312.00 MB, saklanan 957.76 GB
ucu birden: 01'in belge deposu 5,76 GB eklenir, 02'nin uc kopyasiyla 2715.36 GB
```

Bu satırlar **hesap** sınıfındadır.

**Toplu tarama çevrimiçi depodan çıkıyor.** Teslimat operasyonu deposunun tarama sütunu sıfırdır;
saniyede 833,33 kayıt okuyan dört saatlik iş artık takip sorgusuyla aynı diski, aynı belleği ve aynı
kilit yöneticisini paylaşmıyor. Federasyonun ölçekleme gerekçesi buradadır ve tek bir sayıyla
söylenebilir: **çevrimiçi yolun gördüğü kayıt hızı 833,33'ten sıfıra iniyor.**

**Toplam işlem 1,17 katına çıkıyor.** 250,00 işlem/s'lik tek depo, 250,00 ve 41,67'ye bölünüyor;
fazla olan 41,67 ücretlendirmenin kendi kopyalarını yazmasıdır. Yazma yolunun uzunluğu 1,375 depoya
çıkıyor: gönderi oluşturma iki depoya, durum olayı ortalama 1,286 depoya yazılıyor. Yazma yolunun
uzaması bir dayanıklılık sorusu doğurur — iki depodan biri yazmayı kabul etmezse ne olur — ama o
soru bu kursun konusu değildir.

**`gunluk veri artisi MB` ve `saklanan veri GB` birlikte 1,26 katına çıkıyor.** 976 MB 1232 MB
oluyor, 712,48 GB 899,36 GB oluyor. Artışın kaynağı ikidir ve ayrı ayrı okunabilir: yinelenen
kimlik alanları gönderi kaydını 900 bayttan 1100 bayta çıkarıyor, yinelenen kabul ve teslim
olayları günde 176 MB ekliyor. VD4 üçte bire çıkarsa saklanan veri 963,60 GB, yinelenen kimlik 400
bayta çıkarsa 957,76 GB olur; iki varsayım da aynı büyüklükte etkilidir.

Son satır üç kararın birleşimini veriyor. 01. dersin belge deposu, bu dersin federasyonu ve 02.
dersin üç kopyası birlikte uygulandığında saklanan veri 2715,36 GB'dir — K01'in 712,48 GB'sinin
3,81 katı. **Veri katmanı kararlarının ortak yönü budur: hepsi aynı sayıyı büyütür ve etkileri
çarpışır, toplanmaz.**

## Özet

- Federasyon veriyi anahtara göre değil işleve göre böler; sınır bağlamın sorularıyla çizilir, aynı
  takip numarası iki depoda da geçebilir.
- Bağlamın kendi soruları kendi deposunda kalıyor, ama iki bağlamın kesişimindeki S4 sorusu 1
  depodan 2 depoya, 3000 kayıttan 6000 kayda çıkıyor ve depolar arasında 3000 anahtar (33 kB)
  taşınıyor.
- Yinelenen 2/7 olay bir çapraz soruyu (S5) tek depoya indiriyor; sınırın doğruluğunun ölçüsü
  çapraz soru sayısıdır.
- Toplu tarama çevrimiçi depodan çıkıyor: teslimat operasyonu deposunun gördüğü tarama hızı
  833,33 kayıt/s'den sıfıra iniyor.
- Toplam işlem 250,00'den 291,67 işlem/s'ye (1,17 kat), yazma yolu 1,375 depoya uzuyor.
- Yineleme K01'in iki büyüme satırını 1,26 katına çıkarıyor (976 → 1232 MB, 712,48 → 899,36 GB);
  01 ve 02'nin kararlarıyla birlikte saklanan veri 2715,36 GB olur.

## Sonraki Adım

Federasyon deponun işini böldü ama her bağlamın kendi verisi hâlâ bütün olarak tek bir düğümde
duruyor. Teslimat operasyonu deposu 624,88 GB taşıyor ve saniyede 250,00 işlem alıyor; bu sayılar
bağlam bölünerek küçülmez, çünkü artık bölünecek bağlam kalmadı. Kalan tek yol veriyi **kendi
içinde** bölmektir: aynı bağlamın kayıtlarını bir anahtara göre bağımsız düğümlere dağıtmak.
Sonraki ders bu kararı ele alır — anahtar nasıl seçilir, seçim üç erişim örüntüsünün her birinin
dokunduğu düğüm sayısını nasıl değiştirir, en yüklü düğüm ötekilerin kaç katını taşır ve düğüm
sayısı değiştiğinde kaç bayt yer değiştirir.
