---
title: Kümeleme
source: 'https://academia.sh/tr/kurslar/bellek-ici-depolar/kumeleme'
course: 'Bellek İçi Depolar ve Önbellek Sistemleri'
language: tr
updated: '2026-08-17T18:08:57+00:00'
license: 'CC BY-SA 4.0'
---

# Kümeleme

Anahtar alanının bölümlenmesi: anahtarın karma yoluyla yuvaya, yuvanın düğüme eşlenmesinin kendi yazılmış karma işleviyle gösterilmesi, çok anahtarlı işlemin küme kısıtının dört düğüm sayısında ölçülüp tek düğüme düşme oranının bire bölü n üzeri k eksi bir formülüyle karşılaştırılması, anahtarları etiketle aynı bölüme toplamanın işlemleri yüzde yüze çıkarırken kullanılan yuva sayısını altıya düşürmesi ve etiketin taneliğine göre tutulan baytın çoğalmasıyla düğüm başına yükün dengesizleşmesinin sayılması.

Önceki iki ders veri kümesinin tamamının tek düğüme sığdığını varsaydı. Çoğaltma o kümenin
kopyalarını çıkardı, devralma kopyalardan birini göreve aldı; ikisi de saklanan baytı
çarptı, hiçbiri bölmedi. Katalog ve ödünç kayıtları bir düğümün bellek bütçesini aştığında geriye
tek yol kalır: anahtar alanını bölmek ve her düğüme yalnız bir payı vermek.

Bu ders o bölmeyi ele alır. Parçalama ve parça anahtarı seçimi İleri Veri Ölçekleme ve NoSQL
kurslarında ölçüldü; burada tekrarlanmaz. Buranın sorusu farklıdır: bölme kararı bellek içi
deponun **işlem** semantiğini nasıl kısıtlar, ve o kısıtı kaldırmanın bellek bütçesindeki
karşılığı nedir.

## Anahtardan Düğüme

Bölümleme iki adımdır. Anahtar bir **karma** işlevinden geçirilir ve sabit sayıdaki **yuvadan**
birine düşer; yuva aralıkları düğümlere dağıtılır. Aradaki yuva katmanı, düğüm eklendiğinde
yalnız yuva aralıklarının taşınmasını sağlar — anahtarların yeniden karmalanması gerekmez.
Aşağıdaki düzenekte 16.384 yuva vardır ve karma işlevi kendi yazılmıştır.

Bunun doğrudan sonucu şudur: **iki anahtarın hangi düğüme düşeceği birbirinden bağımsızdır.**
Bir ödünç işlemi katalog girişine, ödünç sayacına ve bekleme kuyruğuna birlikte dokunuyorsa,
bu üç anahtarın aynı düğümde olması bir tasarım kararı değil, bir rastlantıdır. Aynı düğümde
olmadıklarında işlem tek bir düğümde yürütülemez — **çok anahtarlı işlemin küme kısıtı** budur.

## Düzenek

Düzenek bir **modeldir**: gerçek küme, ağ ya da düğüm kurulmaz; düğüm bir sayıdır ve anahtarın
hangi düğüme düştüğü karmadan hesaplanır.

**BK6 — şube payları eşit değildir: altı şube ödünçlerin yüzde 34, 24, 16, 12, 9 ve 5'ini
taşır.** Gerekçe: kütüphane şubeleri eşit büyüklükte değildir ve etiketleme kararının bedeli
tam olarak bu eşitsizlikte görünür. **BK7 — iki işlem biçimi ölçülür: T1 katalog girişi, ödünç
sayacı ve bekleme kuyruğuna dokunur; T2 buna şubenin eşzamanlı ödünç sayacını ekler.** Gerekçe:
sınır denetimi olmayan bir ödünç ile şube sınırını denetleyen bir ödünç farklı sayıda anahtara
dokunur ve küme kısıtı anahtar sayısına üstel bağlıdır.

```js
// kumeleme/model.mjs — anahtar alani bolumlemesi SUREC ICI MODELDIR. Gercek kume, ag ya da
// dugum kurulmaz; dugum bir sayidir ve anahtarin hangi dugume dustugu karmadan hesaplanir.
// Karma islevi (FNV-1a, 32 bit) burada kendi yazilmistir.
export const YUVA = 16384, KATALOG_BAYT = 240, ODUNC_BAYT = 96, KUYRUK_BAYT = 128, SAYAC_BAYT = 64;

export function karma(s) {
  let h = 0x811c9dc5;
  for (let i = 0; i < s.length; i += 1) { h ^= s.charCodeAt(i); h = Math.imul(h, 0x01000193) >>> 0; }
  return h >>> 0;
}
export function yuvaNo(anahtar) {          // anahtarda etiket varsa YALNIZ etiket karmalanir
  const a = anahtar.indexOf("{"), b = anahtar.indexOf("}");
  return karma(a >= 0 && b > a + 1 ? anahtar.slice(a + 1, b) : anahtar) % YUVA;
}
export const dugumu = (yuva, n) => Math.floor(yuva * n / YUVA);   // esit yuva araligi

export function uretec(tohum) {            // dogrusal esleskli uretec; tohum gorunurdur
  let s = tohum >>> 0;
  return () => { s = (Math.imul(s, 1103515245) + 12345) >>> 0; return s / 4294967296; };
}

// Sube paylari esit degildir: buyuk sube odunclerin ucte birini tasir.
export const PAY = [0.34, 0.24, 0.16, 0.12, 0.09, 0.05];

export function veri({ kitap = 3000, odunc = 12000, kuyrukPay = 0.25, tohum = 20260731 }) {
  const rnd = uretec(tohum), kayit = [], kuyruk = new Set();
  const esik = PAY.map((p, i) => PAY.slice(0, i + 1).reduce((a, b) => a + b, 0));
  for (let i = 0; i < odunc; i += 1) {
    const x = rnd(), s = esik.findIndex((e) => x < e);
    kayit.push([s < 0 ? PAY.length - 1 : s, Math.floor(rnd() * kitap)]);
  }
  for (let k = 0; k < kitap; k += 1) if (rnd() < kuyrukPay) kuyruk.add(k);
  return { kitap, kayit, kuyruk };
}

// Uc etiketleme semasi. Etiket, anahtarin hangi parcasinin karmalanacagini belirler.
export const SEMA = {
  yok: { katalog: (k) => `katalog:${k}`, odunc: (s, k) => `odunc:${s}:${k}`,
         kuyruk: (k) => `kuyruk:${k}`, sayac: (s) => `sube:${s}:acikOdunc` },
  sube: { katalog: (k, s) => `{sube:${s}}katalog:${k}`, odunc: (s, k) => `{sube:${s}}odunc:${k}`,
          kuyruk: (k, s) => `{sube:${s}}kuyruk:${k}`, sayac: (s) => `{sube:${s}}acikOdunc` },
  kitap: { katalog: (k) => `{kitap:${k}}katalog:${k}`, odunc: (s, k) => `{kitap:${k}}odunc:${s}`,
           kuyruk: (k) => `{kitap:${k}}kuyruk:${k}`, sayac: (s) => `sube:${s}:acikOdunc` },
};

export function kosum({ sema, dugum, d }) {
  const S = SEMA[sema], bayt = new Map(), yuvalar = new Set();
  const ekle = (anahtar, b) => { bayt.set(anahtar, b); yuvalar.add(yuvaNo(anahtar)); };
  let t1 = 0, t2 = 0;
  for (const [s, k] of d.kayit) {
    ekle(S.katalog(k, s), KATALOG_BAYT);                 // etiket sube ise katalog girisi COGALIR
    ekle(S.odunc(s, k), ODUNC_BAYT);
    if (d.kuyruk.has(k)) ekle(S.kuyruk(k, s), KUYRUK_BAYT);
    ekle(S.sayac(s), SAYAC_BAYT);
    const g = [S.katalog(k, s), S.odunc(s, k), S.kuyruk(k, s)].map((a) => dugumu(yuvaNo(a), dugum));
    if (g.every((x) => x === g[0])) t1 += 1;              // T1: katalog + odunc + kuyruk
    if (g.every((x) => x === g[0]) && dugumu(yuvaNo(S.sayac(s)), dugum) === g[0]) t2 += 1;
  }
  const yuk = Array(dugum).fill(0), sayi = Array(dugum).fill(0);
  for (const [anahtar, b] of bayt) {
    const n = dugumu(yuvaNo(anahtar), dugum);
    yuk[n] += b; sayi[n] += 1;
  }
  const toplam = yuk.reduce((a, b) => a + b, 0);
  return { yuvalar: yuvalar.size, anahtar: bayt.size, toplam, yuk, sayi,
           enYuklu: Math.max(...yuk), dengesizlik: Math.max(...yuk) / (toplam / dugum),
           t1: t1 / d.kayit.length, t2: t2 / d.kayit.length };
}
```

```js
// kumeleme/olc.mjs — ayni veri kumesi: once dugum sayisi, sonra uc etiketleme semasi
import { veri, kosum, yuvaNo, dugumu, YUVA } from "./model.mjs";

const s = (x, n) => String(x).padStart(n);
const kib = (b, n = 8) => s((b / 1024).toFixed(1), n);
const yuz = (x, n = 7) => s((x * 100).toFixed(2) + "%", n);
const d = veri({});

console.log("3.000 kitap, 6 sube, 12.000 odunc kaydi (tohum 20260731). Katalog girisi 240,");
console.log("odunc 96, kuyruk 128, sube sayaci 64 bayt. " + YUVA + " yuva, dugume esit araliklarla.");
console.log("T1 = katalog + odunc + kuyruk; T2 = T1 + sube sayaci. Etiket yok:\n");
console.log("dugum | anahtar | toplam bayt | en yuklu dugum | dengesizlik | T1 tek dugumde | T2");
console.log("------|---------|-------------|----------------|-------------|----------------|--------");
for (const n of [3, 4, 6, 8]) {
  const r = kosum({ sema: "yok", dugum: n, d });
  console.log(`${s(n, 5)} | ${s(r.anahtar, 7)} | ${kib(r.toplam, 7)} KiB | ${kib(r.enYuklu, 10)} KiB | ` +
    `${s(r.dengesizlik.toFixed(3), 11)} | ${yuz(r.t1, 14)} | ${yuz(r.t2)}`);
}

console.log("\n6 dugum sabit; etiketleme semasi degisiyor:");
console.log("sema  | kullanilan yuva | anahtar | toplam bayt | en yuklu | dengesizlik | T1     | T2");
console.log("------|-----------------|---------|-------------|----------|-------------|--------|--------");
for (const sema of ["yok", "sube", "kitap"]) {
  const r = kosum({ sema, dugum: 6, d });
  console.log(`${sema.padEnd(5)} | ${s(r.yuvalar, 15)} | ${s(r.anahtar, 7)} | ${kib(r.toplam, 7)} KiB | ` +
    `${kib(r.enYuklu, 6)} K | ${s(r.dengesizlik.toFixed(3), 11)} | ${yuz(r.t1)} | ${yuz(r.t2)}`);
}

console.log("\n6 dugum, etiket = sube. Dugum basina yuk (sube paylari 34/24/16/12/9/5):");
const b = kosum({ sema: "sube", dugum: 6, d });
console.log("dugum   : " + b.yuk.map((_, i) => s("d" + i, 9)).join(""));
console.log("anahtar : " + b.sayi.map((x) => s(x, 9)).join(""));
console.log("KiB     : " + b.yuk.map((x) => s((x / 1024).toFixed(1), 9)).join(""));

console.log("\nkosumdan bagimsiz nicelikler:");
console.log("  K anahtarli islemin tek dugume dusme olasiligi = (1/n)^(K-1), etiket yokken");
console.log("  n       : " + [3, 4, 6, 8].map((n) => s(n, 8)).join(""));
console.log("  K=3     : " + [3, 4, 6, 8].map((n) => s((100 / n ** 2).toFixed(2) + "%", 8)).join(""));
console.log("  K=4     : " + [3, 4, 6, 8].map((n) => s((100 / n ** 3).toFixed(2) + "%", 8)).join(""));
console.log("  etiket = sube  -> kullanilabilir yuva sayisi = sube sayisi = 6");
console.log("  etiket = kitap -> kullanilabilir yuva sayisi = kitap sayisi = 3000");
console.log("  ornek yuva no  : sube:0 -> " + yuvaNo("{sube:0}katalog:7") +
  ", kitap:7 -> " + yuvaNo("{kitap:7}katalog:7") + ", etiketsiz katalog:7 -> " + yuvaNo("katalog:7"));
console.log("  6 dugumde bu yuvalarin dugumleri: " + [
  dugumu(yuvaNo("{sube:0}katalog:7"), 6), dugumu(yuvaNo("{kitap:7}katalog:7"), 6),
  dugumu(yuvaNo("katalog:7"), 6)].join(", "));
```

```
3.000 kitap, 6 sube, 12.000 odunc kaydi (tohum 20260731). Katalog girisi 240,
odunc 96, kuyruk 128, sube sayaci 64 bayt. 16384 yuva, dugume esit araliklarla.
T1 = katalog + odunc + kuyruk; T2 = T1 + sube sayaci. Etiket yok:

dugum | anahtar | toplam bayt | en yuklu dugum | dengesizlik | T1 tek dugumde | T2
------|---------|-------------|----------------|-------------|----------------|--------
    3 |   11758 |  1539.6 KiB |      553.0 KiB |       1.078 |         11.43% |   3.15%
    4 |   11758 |  1539.6 KiB |      408.4 KiB |       1.061 |          5.97% |   1.09%
    6 |   11758 |  1539.6 KiB |      284.4 KiB |       1.108 |          2.32% |   0.30%
    8 |   11758 |  1539.6 KiB |      210.6 KiB |       1.094 |          1.22% |   0.13%

6 dugum sabit; etiketleme semasi degisiyor:
sema  | kullanilan yuva | anahtar | toplam bayt | en yuklu | dengesizlik | T1     | T2
------|-----------------|---------|-------------|----------|-------------|--------|--------
yok   |            8709 |   11758 |  1539.6 KiB |  284.4 K |       1.108 |   2.32% |   0.30%
sube  |               6 |   18151 |  2899.0 KiB | 1452.5 K |       3.006 | 100.00% | 100.00%
kitap |            2813 |   11758 |  1539.6 KiB |  266.0 K |       1.036 | 100.00% |  16.83%

6 dugum, etiket = sube. Dugum basina yuk (sube paylari 34/24/16/12/9/5):
dugum   :        d0       d1       d2       d3       d4       d5
anahtar :         0        0        0     9052     9099        0
KiB     :       0.0      0.0      0.0   1446.6   1452.5      0.0

kosumdan bagimsiz nicelikler:
  K anahtarli islemin tek dugume dusme olasiligi = (1/n)^(K-1), etiket yokken
  n       :        3       4       6       8
  K=3     :   11.11%   6.25%   2.78%   1.56%
  K=4     :    3.70%   1.56%   0.46%   0.20%
  etiket = sube  -> kullanilabilir yuva sayisi = sube sayisi = 6
  etiket = kitap -> kullanilabilir yuva sayisi = kitap sayisi = 3000
  ornek yuva no  : sube:0 -> 11178, kitap:7 -> 8777, etiketsiz katalog:7 -> 15851
  6 dugumde bu yuvalarin dugumleri: 4, 3, 5
```

## Küme Kısıtının Büyüklüğü

**Bölmek dengelidir; kısıtlayan şey denge değildir.** İlk tablonun dengesizlik sütunu dört
düğüm sayısında da 1,06 ile 1,11 arasındadır: en yüklü düğüm ortalamanın yüzde on bir üstündedir.
Karma dağıtımı işini yapıyor ve tutulan bayt gerçekten bölünüyor — üç düğümde en yüklü düğüm
553,0 KiB, sekiz düğümde 210,6 KiB tutuyor. Bu, çoğaltmanın yapamadığı şeydir.

**Kaybedilen şey işlemdir.** Aynı tablonun son iki sütunu bunu sayıyor: üç düğümlü kümede
T1 işlemlerinin yüzde 11,43'ü, T2 işlemlerinin yüzde 3,15'i tek düğüme düşüyor. Sekiz düğümde
oranlar yüzde 1,22 ve yüzde 0,13'e iniyor. Beklenen değer koşumdan bağımsız satırlarda:
`(1/n)^(K-1)`. Ölçülen sayılar bu beklentinin yakınındadır — ödünç kayıtları bağımsız değildir,
aynı kitap–şube çifti birden çok kez geçer, bu yüzden sapma vardır — ama eğilim aynıdır:
**düğüm eklemek işlemin tek düğümde kalma şansını üstel olarak düşürür** ve dokunulan anahtar
sayısı üsttedir. T2, T1'e tek bir anahtar ekliyor ve oranı sekiz düğümde dokuz kat düşürüyor.

Bu, kümeye geçişin gerçek bedelidir. Şube sınırını denetleyen bir ödünç işlemi bin denemesinden
birinde tek düğümde yürütülebiliyorsa, o işlem küme kurulumunda uygulama tarafından yürütülmek
zorundadır ve atomikliği kalmaz.

## Etiketin Taneliği

İkinci tablo kısıtı kaldırmanın üç yolunu karşılaştırıyor. **Etiket**, anahtarın yalnız belirli
bir parçasının karmalanmasıdır; aynı etiketi taşıyan bütün anahtarlar aynı yuvaya, dolayısıyla
aynı düğüme düşer.

**Etiket şube olduğunda küme kısıtı tamamen kalkar ve bölümleme de kalkar.** T1 ve T2 yüzde
100'e çıkıyor. Karşılığında kullanılan yuva sayısı 8.709'dan **6'ya** iniyor: altı şube, altı
yuva. Üçüncü blok sonucu açıkça gösteriyor — altı düğümün dördü tamamen boştur, bütün veri iki
düğümde toplanmıştır ve dengesizlik 3,006'dır. Bellek sınırına çarpacak düğüm bellidir.

İkinci bir kalem daha var ve doğrudan bellek bütçesindendir: toplam tutulan bayt 1.539,6 KiB'den
**2.899,0 KiB'ye** çıkıyor, anahtar sayısı 11.758'den 18.151'e. Nedeni, katalog girişinin artık
şube etiketiyle yazılmasıdır — aynı kitabın kaydı, o kitabın ödünç verildiği her şubede ayrıca
durur. Etiketleme yalnız yeri değil, **kopya sayısını** da belirler.

**Etiket kitap olduğunda ölçüler tersine döner.** Kullanılan yuva 2.813'e çıkar, dengesizlik
1,036'ya iner — etiketsiz dağıtımdan bile daha dengelidir — ve toplam bayt hiç büyümez, çünkü
katalog girişi çoğalmaz. T1 yüzde 100'dür: bir kitabın katalog girişi, ödünç kaydı ve bekleme
kuyruğu her zaman aynı düğümdedir. T2 ise yüzde 16,83'te kalır, çünkü şubenin eşzamanlı ödünç
sayacı kitap etiketini taşımaz ve altı düğümden birine rastgele düşer.

Buradan çıkan kural, etiketin kendisiyle değil işlemle ilgilidir: **etiket bir işlemi tek düğüme
sığdırmaz, işlemin kapsamını belirler.** Şube sayacını da aynı düğüme çekmek için ya sayacı
kitap etiketine bağlamak — ki o zaman şube başına tek bir sayaç kalmaz — ya da sınır denetimini
işlemin dışına çıkarmak gerekir. Küme kurulumunda hangi işlemlerin atomik kalacağına anahtar
adlandırması karar verir.

## Özet

- Anahtar önce karmayla 16.384 yuvadan birine, yuva sonra düğüme eşlenir; iki anahtarın aynı
  düğüme düşmesi bir tasarım kararı değil, rastlantıdır.
- Etiketsiz bölümleme dengelidir (dengesizlik 1,06–1,11) ve tutulan baytı gerçekten böler:
  en yüklü düğüm üç düğümde 553,0 KiB, sekiz düğümde 210,6 KiB.
- Çok anahtarlı işlemin tek düğüme düşme oranı `(1/n)^(K-1)`'e uyar: T1 için yüzde 11,43'ten
  yüzde 1,22'ye, T2 için yüzde 3,15'ten yüzde 0,13'e iner.
- Etiket şube olduğunda T1 ve T2 yüzde 100'e çıkar; bedeli kullanılan yuvanın 6'ya inmesi, altı
  düğümün dördünün boş kalması ve dengesizliğin 3,006 olmasıdır.
- Şube etiketi katalog girişini şube başına çoğalttığı için toplam tutulan bayt 1.539,6 KiB'den
  2.899,0 KiB'ye, anahtar sayısı 11.758'den 18.151'e çıktı.
- Kitap etiketi dengeyi 1,036'ya çeker ve baytı hiç büyütmez ama yalnız T1'i yüzde 100 yapar;
  şube sayacını içeren T2 yüzde 16,83'te kalır — etiket, işlemin kapsamını belirler.

## Sonraki Adım

Bu ders bir işlemin bütün anahtarlarının aynı düğümde toplanabildiğini gösterdi, ama toplandıktan
sonra ne olacağını hiç sormadı. Bir ödünç işlemi şubenin eşzamanlı ödünç sayacını okur, sınırı
aşıp aşmadığına bakar ve ancak öyle artırır; okuma ile artırma arasında geçen sürede başka bir
şube görevlisi aynı sayacı değiştirmiş olabilir. Bellek içi depoda bu boşluğu kapatmanın yolu
kilit almak değil, anahtarı **izlemek** ve değiştiyse işlemi düşürüp yeniden denemektir. Sonraki
ders bu izleme tabanlı denetimi eşzamanlılık altında ölçer: çakışma oranı, işlem başına yeniden
deneme sayısı, izlenen anahtarın tuttuğu üstveri ve işlem yürürken bütün istemcilerin bekletildiği
turlar.
