---
title: 'Mesaj Sistemleri'
source: 'https://academia.sh/tr/kurslar/veri-hatlari/mesaj-sistemleri'
course: 'Veri Hatları ve Orkestrasyon'
language: tr
updated: '2026-08-17T18:08:49+00:00'
license: 'CC BY-SA 4.0'
---

# Mesaj Sistemleri

Bölüm sayısının tüketici grubuna dağıttığı iş ile bölüm başına sıra korunumunun yan yana sayılması: dört tüketicili bir grupta tek bölüm üç tüketiciyi boşta bırakıyor, dört bölüm hepsini çalıştırıyor. Abone anahtarıyla bölümlenen konuda hiçbir abone dağılmıyor ve tüketim her bölüm sayısında 2200 satır kalıyor, ama yük 708 ile 492 arasında eğriliyor. En dengeli anahtar olan kayıt anahtarı yükü 621 ile 583 arasına sıkıştırıyor ve 200 abonenin hepsini dağıtıyor: tüketim dört bölümde 527 satıra düşüyor, sunum her bölgede 616 ile 977 arasında kayıyor. Dönem anahtarı ise 2200 satırın 2000'ini kaybederken sunumu yalnız −15,29 ile +16,15 arasında oynatıyor.

Önceki iki ders alma işini **çekme** üzerinden ele aldı: hat kaynağa gitti, ne isteyeceğine kendi
karar verdi ve kotasını kendi harcadı. Kaynağın veriyi kendiliğinden **ittiği** düzenek bu
dengeyi tersine çevirir. Kayıtlar bir **konuya** (topic) yazılır, konu **bölümlere** ayrılır ve
bölümleri bir **tüketici grubu** (consumer group) okur. Kuyruk, yayımla–abone ol düzeni, konum ve
teslim semantiği Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunda ölçüldü; yordam burada
tekrarlanmaz.

Bu dersin ölçüsü iki sayıdır: **bölüm sayısının tüketiciye dağıttığı iş** ve **bölüm başına sıra
korunumu**. İkisi aynı ayarın iki yüzüdür. Bölüm sayısı arttıkça paralellik artar; ama aynı
abonenin kayıtları farklı bölümlere düştüğünde, tüketim hesabının dayandığı sıra kırılır ve hat
satır kaybeder.

- **VA17.** Kod **kurgudur**; gerçek bir mesaj sistemi, akış işleyici ya da orkestratör
  çağrılmaz. Kaynak yine 200 abone, 12 dönem, 2400 satır, tohum 20260218.
- **VA18.** Konuya yazım sırası dönem dönemdir; bir dönemin bütün abone kayıtları yazıldıktan
  sonra sonraki dönem başlar.
- **VA19.** Bir kayıt **bölüm anahtarına** göre tek bir bölüme düşer ve aynı anahtar her zaman
  aynı bölüme gider. Bölüm içindeki **konum** (offset) yazım sırasını korur; bölümler arasında
  böyle bir sıra yoktur.
- **VA20.** Bir bölümü grup içinde **tek bir tüketici** okur. Bölüm sayısı bu yüzden aynı gruptaki
  etkin tüketici sayısının tavanıdır. Grupta dört tüketici vardır.
- **VA21.** Üç bölüm anahtarı sınanır: `abone`, `kayit` (abone ile dönemin birleşimi) ve `donem`.
  Üçü de kaynağın kendi alanlarıdır; hiçbiri uydurma değildir.
- **VA22.** Her tüketici tüketim hesabını **yalnız kendi bölümündeki kayıtlarla** yapar; bir
  abonenin önceki dönemi başka bir bölümdeyse o satır hesaplanamaz ve düşer.
- **VA23.** Taban çizgisi orkestrasyonsuz koşumdur; sağlam hatta tüketim 2200 satırdır ve sunum
  sapması boştur.
- **VA24.** Bölüm sayısı ve boşta tüketici tam sayıdır, oran basılmaz. Satır oranının adımı
  1/2400, yani 0,0004; sunum üzerinde oran basılmaz.

## Konu, Bölüm ve Tüketici Grubu

Aşağıdaki blok ortak tanımı kurar ve üzerine bölümlü bir konu ile onu okuyan bir tüketici grubu
ekler. Her kurulum için beş sayı basılıyor: en çok ve en az yüklenen tüketicinin satır sayısı,
boşta kalan tüketici sayısı, birden çok bölüme dağılmış abone sayısı ve bölümlerden toplanan
tüketim satırı.

```python
# KURGUDUR. Gercek bir mesaj sistemi, akis isleyici ya da orkestrator
# cagrilmaz; olcum aginin sayac okumalari kurgudur, tohum 20260218.
TOHUM, M32 = 20260218, 0xFFFFFFFF


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
DONEM = [f"2026-{a:02d}" for a in range(1, 13)]
ABONE = {}
for i in range(200):
    r = uretec(TOHUM + 37 * i)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "baslangic": 10000 + int(r() * 60000)}


def kaynak_uret():                                  # her donem her abone icin bir okuma
    kayit = []
    for i, (ab, a) in enumerate(ABONE.items()):
        e = a["baslangic"]
        for d in DONEM:
            r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d))
            e += 4 + int(r() * 46)
            kayit.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                          "endeks": e, "birim": "m3"})
    return kayit


# ---- HAT: bes asama, her asama kendi dusurdugu satiri sayar.
def a1_ayikla(kayit):
    ZOR = ("abone", "donem", "bolge", "endeks", "birim")
    tut = [k for k in kayit if all(a in k for a in ZOR)]
    return tut, len(kayit) - len(tut)


def a2_tekille(kayit):
    gor, tut = set(), []
    for k in kayit:
        ad = (k["abone"], k["donem"])
        if ad in gor:
            continue
        gor.add(ad)
        tut.append(k)
    return tut, len(kayit) - len(tut)


def a3_tuketim(kayit):
    tablo = {(k["abone"], k["donem"]): k for k in kayit}
    cikti, dusen = [], 0
    for k in kayit:
        i = DONEM.index(k["donem"])
        if i == 0:
            continue
        onceki = tablo.get((k["abone"], DONEM[i - 1]))
        if onceki is None:
            dusen += 1
            continue
        try:
            f = int(k["endeks"]) - int(onceki["endeks"])
        except (TypeError, ValueError):
            dusen += 1
            continue
        cikti.append(dict(k, m3=f))
    return cikti, dusen


def a4_ozet(kayit):
    top = {}
    for k in kayit:
        ad = (k["bolge"], k["donem"])
        top[ad] = top.get(ad, 0) + k["m3"]
    return top, 0


def a5_sun(ozet):                                   # bolge basina donem ortalamasi
    bolge = {}
    for (b, d), v in ozet.items():
        bolge.setdefault(b, []).append(v)
    return {b: round(sum(v) / len(v), 2) for b, v in bolge.items()}, 0


def okuma_sonucu(kayitlar):
    v, _ = a1_ayikla(kayitlar)
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    oz, _ = a4_ozet(v)
    sun, _ = a5_sun(oz)
    return sun, len(v)


# ---- KURGU konu: bolumler , bolum anahtari , tuketici grubu.
def dagit(anahtar, p):
    """Anahtardan bolum numarasi. Ayni anahtar her zaman ayni bolume duser."""
    x = 0
    for c in anahtar:
        x = (x * 131 + ord(c)) & M32
    return int(uretec(TOHUM + x)() * p)


def bolumle(kayitlar, p, anahtar):
    """Konuya yazim sirasi donem donem ; her kayit anahtarina gore bir bolume yazilir.
    Bolum icindeki konum yazim sirasini korur."""
    bolum = {b: [] for b in range(p)}
    for k in sorted(kayitlar, key=lambda k: (k["donem"], k["abone"])):
        ad = {"abone": k["abone"], "kayit": k["abone"] + k["donem"],
              "donem": k["donem"]}[anahtar]
        b = dagit(ad, p)
        bolum[b].append(dict(k, konum=len(bolum[b])))
    return bolum


def tuketici_grubu(bolum, c):
    """Bir bolumu grup icinde tek bir tuketici okur ; bolum sayisi tavandir."""
    atama = {t: [] for t in range(c)}
    for b in bolum:
        atama[b % c].append(b)
    return atama


ham = kaynak_uret()
dogru_sun, dogru_n = okuma_sonucu(ham)
print("tuketici grubu 4 tuketici , tuketim saglam hatta", dogru_n, "satir")
print("anahtar  bolum  en cok  en az  bosta  dagilan abone  hesaplanan tuketim")
for anahtar in ("abone", "kayit", "donem"):
    for p in (1, 2, 4, 8):
        bl = bolumle(ham, p, anahtar)
        at = tuketici_grubu(bl, 4)
        yuk = [sum(len(bl[b]) for b in at[t]) for t in at]
        yer = {}
        for b in bl:
            for k in bl[b]:
                yer.setdefault(k["abone"], set()).add(b)
        tk = sum(len(a3_tuketim(bl[b])[0]) for b in bl)
        print(f"{anahtar:<8} {p:>6} {max(yuk):>7} {min(yuk):>6} "
              f"{sum(1 for y in yuk if y == 0):>6} "
              f"{sum(1 for v in yer.values() if len(v) > 1):>14} {tk:>19}")
```

```
tuketici grubu 4 tuketici , tuketim saglam hatta 2200 satir
anahtar  bolum  en cok  en az  bosta  dagilan abone  hesaplanan tuketim
abone         1    2400      0      3              0                2200
abone         2    1200      0      2              0                2200
abone         4     708    492      0              0                2200
abone         8     696    528      0              0                2200
kayit         1    2400      0      3              0                2200
kayit         2    1211      0      2            200                1076
kayit         4     621    583      0            200                 527
kayit         8     624    572      0            200                 268
donem         1    2400      0      3              0                2200
donem         2    1600      0      2            200                1000
donem         4     800    400      0            200                 200
donem         8    1000    200      0            200                 200
```

## Bölüm Sayısının Dağıttığı İş

İlk sütun çifti anahtardan bağımsız bir gerçeği yazıyor: tek bölümlü bir konuda dört tüketicinin
**üçü boşta** durur, iki bölümde ikisi boşta durur, dörde çıkıldığında hiçbiri boşta kalmaz. Bölüm
sayısı bir tercih değil bir **tavandır**; gruba tüketici eklemek bölüm sayısını aşan noktada
hiçbir şey kazandırmaz. Sekiz bölümde de dört tüketici çalışır, ama her biri iki bölüm okur.

İkinci gözlem yükün nasıl bölündüğüdür. Abone anahtarında dört bölüm 708 ile 492 satır arasında
eğriliyor, yani en yüklü tüketici en boş olanın 1,44 katı iş yapıyor. Kayıt anahtarında aynı
kurulum 621 ile 583 arasına sıkışıyor: bu üç anahtarın **en dengelisidir**, çünkü abone ile dönemi
birleştiren anahtar 2400 farklı değer üretir ve bölümlere neredeyse eşit yayılır. Dönem anahtarı en
kötüsüdür; on iki farklı değeri dört bölüme dağıtınca yük 800 ile 400 arasında, sekiz bölümde 1000
ile 200 arasında açılır. Yalnız bu üç satıra bakan biri kayıt anahtarını seçerdi.

## Bölüm Başına Sıra Korunumu

Son iki sütun seçimi tersine çeviriyor. Abone anahtarında **hiçbir abone dağılmıyor** ve tüketim
her bölüm sayısında **2200 satır** kalıyor. Kayıt anahtarında **200 abonenin hepsi** dağılıyor ve
tüketim dört bölümde 527, sekiz bölümde 268 satıra iniyor. Mekanizma tek cümledir: bir bölüm
kendi içinde sırayı korur, bölümler arasında sıra yoktur, ve tüketim bir abonenin **ardışık iki
döneminin farkıdır**. İki dönem farklı bölümlere düşerse o satırı hesaplayacak tüketici yoktur.

```python
print("anahtar  bolum  hesaplanan tuketim  sunum sapmasi")
for anahtar, p in (("abone", 4), ("kayit", 4), ("donem", 2), ("donem", 4)):
    bl = bolumle(ham, p, anahtar)
    oz, tk = {}, 0
    for b in bl:                                    # her tuketici kendi bolumunu okur
        v, _ = a3_tuketim(bl[b])
        tk += len(v)
        o, _ = a4_ozet(v)
        for ad, s in o.items():
            oz[ad] = oz.get(ad, 0) + s
    s, _ = a5_sun(oz)
    print(f"{anahtar:<8} {p:>6} {tk:>18}  ",
          {b: round(s.get(b, 0) - dogru_sun[b], 2) for b in dogru_sun})

bl = bolumle(ham, 4, "abone")
print()
print("abone anahtarli bolum 0 :", len(bl[0]), "kayit , son konum", bl[0][-1]["konum"])
print("ilk uc kayit :", [(k["abone"], k["donem"], k["konum"]) for k in bl[0][:3]])
ab = bl[0][0]["abone"]
print(ab, "kayitlarinin bolumleri :",
      sorted(set(b for b in bl for k in bl[b] if k["abone"] == ab)))
kl = bolumle(ham, 4, "kayit")
print(ab, "kayit anahtarinda :", sorted(set(b for b in kl for k in kl[b] if k["abone"] == ab)))
```

```
anahtar  bolum  hesaplanan tuketim  sunum sapmasi
abone         4               2200   {'merkez': 0.0, 'kuzey': 0.0, 'dogu': 0.0, 'bati': 0.0, 'guney': 0.0}
kayit         4                527   {'merkez': -977.27, 'kuzey': -960.55, 'dogu': -686.91, 'bati': -616.0, 'guney': -801.1}
donem         2               1000   {'merkez': 16.15, 'kuzey': -7.35, 'dogu': 12.84, 'bati': -15.29, 'guney': 4.65}
donem         4                200   {'merkez': 180.55, 'kuzey': 57.45, 'dogu': 124.64, 'bati': -24.09, 'guney': 25.45}

abone anahtarli bolum 0 : 492 kayit , son konum 491
ilk uc kayit : [('A005', '2026-01', 0), ('A007', '2026-01', 1), ('A014', '2026-01', 2)]
A005 kayitlarinin bolumleri : [0]
A005 kayit anahtarinda : [0, 1, 2, 3]
```

Son dört satır düzeneği tek bir abone üzerinde gösteriyor. Abone anahtarında A005'in on iki
kaydının hepsi bölüm 0'dadır ve o bölümü okuyan tüketici on ikisini de sırayla görür. Kayıt
anahtarında aynı abonenin kayıtları dört bölüme birden dağılmıştır; hiçbir tüketici o abonenin
ardışık iki dönemini birlikte görmez. Bölümün içindeki konum kusursuz artmaya devam eder — bölüm 0
kendi 492 kaydını 0'dan 491'e sıralar. Sıra bozulmamıştır; **yanlış yerde korunmuştur**.

Konumun ikinci işi kursun kuralına dokunur. Bir tüketici grubu bölüm başına tek bir sayı tutar: o
bölümde nereye kadar okuduğunu. Grup düştüğünde ya da yeniden kurulduğunda okumaya o konumdan
devam eder, ve konum geriye alındığında aynı kayıtlar **yeniden** okunur. Alma adımının yeniden
koşturulabilir olmasının dayanağı budur; çekmeli bir bağlayıcıda aynı şeyi yapabilmek için
kaynağın eski satırları hâlâ veriyor olması gerekir. Bölüm 0'ın son konumu 491 olduğuna göre o
bölümü baştan okumak 492 kaydı yeniden getirir, ve hedef yazımı yinelemeye dayanıklı olduğu sürece
ikinci koşum ilkiyle aynı sonucu verir.

Buradan çıkan kural, en dengeli anahtarın en yanlış anahtar olabileceğidir. Bölüm anahtarı bir yük
dağıtma ayarı gibi görünür, oysa **tüketicinin hangi kayıtları birlikte görebileceğini** belirler.
Doğru anahtar, hesabın gruplama alanıdır: tüketim abone başına hesaplandığı için anahtar abone
olmalıdır. Bunun bedeli 1,44 katlık yük eğriliğidir ve 2200 satırın tamamı karşılığında ucuzdur.

## Sunulan Sayının Yanıltması

Dönem anahtarının iki satırı dersin en sessiz sonucudur. İki bölümde tüketim 2200'den **1000
satıra** düşüyor, yani 1200 satır kayboluyor, ama sunum sapması **−15,29 ile +16,15** arasında
kalıyor: bin küsur birimlik değerler üzerinde yüzde ikiye bile varmayan bir oynama. Kayıt
anahtarının dört bölümlü kurulumu ise daha az satır kaybediyor gibi durmaz — 527 satırla daha
fazla kaybeder — ve sunumu **−616 ile −977** arasında yıkar.

Fark kayıp miktarında değil kaybın **şeklindedir**. Özet katmanı her bölge ve dönem çifti için
toplam alır, sunum katmanı bu toplamların dönem ortalamasını alır. Dönem anahtarı bütün bir dönemi
birden düşürür: o dönemin hücresi hiç oluşmaz ve ortalama kalan dönemler üzerinden alınır, her biri
kendi içinde doğrudur. Kayıt anahtarı ise her dönemin içinden rastgele satır düşürür: hücreler
oluşur ama eksik toplarlar ve ortalama topluca aşağı iner. Aynı düzeneğin daha büyük kaybı daha
küçük bir sapma üretebilir. Bir bölümleme kararının doğruluğu sunulan sayıya bakarak ölçülemez;
ölçüsü hesaplanan tüketim satırıdır.

## Özet

- Bölüm sayısı aynı gruptaki etkin tüketici sayısının tavanıdır: tek bölümde dört tüketicinin üçü,
  iki bölümde ikisi boşta kalır; dört bölümde hepsi çalışır.
- Bölüm anahtarı bir yük dağıtma ayarı değil, tüketicinin hangi kayıtları birlikte görebileceğini
  belirleyen bir karardır. Bölüm kendi içinde sırayı korur, bölümler arasında sıra yoktur.
- Abone anahtarı hiçbir aboneyi dağıtmaz ve tüketimi her bölüm sayısında 2200 satırda tutar;
  bedeli 708 ile 492 arasında, yani 1,44 katlık bir yük eğriliğidir.
- En dengeli anahtar en yanlış anahtar olabilir: kayıt anahtarı yükü 621 ile 583 arasına sıkıştırır
  ama 200 abonenin hepsini dağıtır ve dört bölümde tüketimi 527 satıra indirir.
- Dönem anahtarı 2200 satırın 2000'ini kaybederken sunumu yalnız −15,29 ile +16,15 arasında
  oynatır, çünkü tam dönem düşürmek ortalamayı bozmaz. Bölümleme kararının ölçüsü sunulan sayı
  değil hesaplanan tüketim satırıdır.

## Sonraki Adım

Bu üç derste veri hatta **alındı**: yöntem seçildi, kaynağın kısıtı sayıldı, konu bölümlendi ve
tüketici grubuna dağıtıldı. Her üçünde de dönem kapalı bir kutu gibi ele alındı — bir dönemin
bütün kayıtları o dönem işlenirken elde sayıldı. Bir kayıt kendi dönemi kapandıktan **sonra**
gelebilir, ve o zaman sonucu hangi pencerenin sahipleneceği bir karar hâline gelir. Sonraki ders
akış işlemeyi bu soruyla ölçer: pencere kararı geç gelen kayıtta sonucu nasıl değiştiriyor ve
pencereler arasında **durum taşımanın** bedeli nedir. Kalan derslerin ortak sorusu ise burada
hiç sorulmadı: veri hatta alınırken **kaybolup kaybolmadığı**.
