---
title: 'Ödeme Akışı'
source: 'https://academia.sh/tr/kurslar/vaka-calismalari/odeme-akisi'
course: 'Vaka Çalışmaları'
language: tr
updated: '2026-08-17T18:10:56+00:00'
license: 'CC BY-SA 4.0'
---

# Ödeme Akışı

İki tarafın kayıtlarının ayrıştığı vaka: mutabakat çevriminde eşleşmeyen kayıt sayısının kaynağına göre ayrılması, yoklamanın farkı binde 59,74'ten binde 9,76'ya indirmesi, geç gelen onayın kalan farkın çoğunu oluşturması, çevrim aralığının fark oranını düşürürken kapanma süresini uzatması ve denetim izinin yedi yıllık hacmi.

Önceki vakada rezervasyon bir söz verdi ve sözü tutan adım kapsam dışında bırakıldı: ödemenin
kendisi. O adım iki taraflıdır; kayıt hem bizde hem dış tarafta tutulur, ikisi birbirinin
defterini göremez ve aralarındaki tek bağ ileti alışverişidir.

Etkisizlik ve tekillik anahtarı Dayanıklılık ve Güvenilirlik kursunun Etkisiz İşlemler
dersinde kuruldu ve tekrarlanmaz; yeniden gönderilen bir istek ikinci bir işlem açmaz. Bu
dersin sorusu başkadır: iletiler kaybolduğunda ya da geç geldiğinde iki defter ne kadar
**ayrışır**, bu fark nasıl sayılır ve ne zaman kapanır.

## Kısıtlar ve Kapsam

İşlevsel gereksinimler: ödeme başlatmak, dış taraftan gelen durum bildirimini işlemek, durumu
sorgulamak, iade başlatmak ve her durum geçişini denetim izine yazmak.

Tasarlanmayan işler: kimlik doğrulama akışı, dolandırıcılık puanlama, muhasebe defterinin
kapanışı ve iade kurallarının kendisi.

İşlevsel olmayan gereksinimler eşikle ve kaynağıyla yazılır: bir işlemin iki taraftaki durumu
en geç **30 dakika** içinde eşleşir (kaynak: bir farkın elle araştırılmadan önce kendi kendine
kapanmasına bırakılan süre), bir mutabakat çevriminde eşleşmeyen kayıt oranı **binde 10'u**
geçmez (kaynak: bir çevrimde elle incelenebilecek kayıt sayısı), her durum geçişi denetim
izinde görünür ve iz kaydı sonradan değişmez (kaynak: bir işlemin geçmişinin yeniden
kurulabilmesi yükümlülüğü).

## Varsayımlar ve Ölçek

| Kod | Varsayım | Değer | Gerekçe |
|---|---|---|---|
| OD1 | günlük ödeme işlemi | 1.200.000 | tamamlanan ve reddedilen girişimlerin toplamı |
| OD2 | tepe çarpanı | 4 | akşam saatlerinin gün ortalamasına oranı |
| OD3 | bildirim gecikmesi | 0,92 / 0,06 / 0,02 | beş saniyeden, beş dakikadan ve daha uzun süreden sonra gelen bildirim payları |
| OD4 | bildirim kaybı | 0,03 | dış tarafın bildiriminin hiç ulaşmaması |
| OD5 | yoklama aralığı | 60 saniye | beklemede kalan işlemin sorulma sıklığı |
| OD6 | mutabakat çevrimi | 900 saniye | iki defterin karşılaştırılma sıklığı |
| OD7 | denetim izi | 5 geçiş × 260 bayt | işlem başına durum geçişi sayısı ve kayıt boyu |
| OD8 | saklama süresi | 2555 gün | uyuşmazlıkların yedi yıl geriye açılabilmesi |
| OD9 | dış tarafta sonuçlanma | 0,90 / 0,08 / 0,02 | 3, 3–60 ve 60–900 saniyede sonuçlanan işlem payları; dış tarafın kendi onay adımları kuyruk üretir |
| OD10 | eşzamanlı doğrulama bütçesi | 20 saniye | isteğin yanıt beklerken açık tutulabileceği üst süre |

```js
// odeme/olcek.mjs — OD varsayim tablosundan cikan kabaca buyukluk hesabi
const OD = { gunlukIslem: 1_200_000, tepeCarpani: 4, bildirimKaybi: 0.03, yoklama: 60,
  cevrim: 900, izKaydiBayt: 260, gecisSayisi: 5, saklamaGun: 2555 };   // OD1..OD8
const GUN = 86_400;

const tepe = (OD.gunlukIslem / GUN) * OD.tepeCarpani;
const izGunluk = OD.gunlukIslem * OD.gecisSayisi * OD.izKaydiBayt;
console.log(`tepe islem/s                   ${tepe.toFixed(2)}`);
console.log(`cevrimde karsilastirilan kayit ${Math.round(tepe * OD.cevrim)}`);
console.log(`gunluk kaybolan bildirim       ${OD.gunlukIslem * OD.bildirimKaybi}`);
console.log(`yoklamanin bulacagi kayit/s    ${(tepe * OD.bildirimKaybi).toFixed(2)}`);
console.log(`denetim izi gunluk GB          ${(izGunluk / 1e9).toFixed(2)}`);
console.log(`denetim izi ${OD.saklamaGun} gunde TB      ${((izGunluk * OD.saklamaGun) / 1e12).toFixed(2)}`);
console.log(`iz kaydi / islem kaydi orani   ${OD.gecisSayisi} (her gecis bir satir)`);

console.log(`\n${"mutabakat cevrimi".padStart(19)}${"tepe partide kayit".padStart(20)}` +
  `${"gunluk cevrim".padStart(15)}`);
for (const c of [300, OD.cevrim, 3600])
  console.log(`${`${c / 60} dk`.padStart(19)}${Math.round(tepe * c).toString().padStart(20)}` +
    `${(GUN / c).toFixed(0).padStart(15)}`);
console.log(`\ngunluk karsilastirilan kayit cevrimden bagimsiz: ${OD.gunlukIslem} ` +
  `(her kayit bir kez); cevrim yalnizca parti boyunu ve fark suresini degistirir`);
```

```
tepe islem/s                   55.56
cevrimde karsilastirilan kayit 50000
gunluk kaybolan bildirim       36000
yoklamanin bulacagi kayit/s    1.67
denetim izi gunluk GB          1.56
denetim izi 2555 gunde TB      3.99
iz kaydi / islem kaydi orani   5 (her gecis bir satir)

  mutabakat cevrimi  tepe partide kayit  gunluk cevrim
               5 dk               16667            288
              15 dk               50000             96
              60 dk              200000             24

gunluk karsilastirilan kayit cevrimden bagimsiz: 1200000 (her kayit bir kez); cevrim yalnizca parti boyunu ve fark suresini degistirir
```

Bu sayılar **hesap** sınıfındadır; OD9 ile OD10 yalnız elenen alternatifin modelinde kullanılır.
Üçü tasarımı belirliyor. Birincisi, tepe hız saniyede 55,56 işlemdir; bu vakanın hiçbir kararı
hacimle ilgili değildir. İkincisi, günde 36.000 bildirim hiç ulaşmaz ve bunları bulmanın
maliyeti saniyede 1,67 sorgudur — küçük bir yük, ama olmadığında o kayıtlar ayrışır. Üçüncüsü,
denetim izi asıl hacim kalemidir: günde 1,56 GB, yedi yılda 3,99 TB, işlem kaydının beş katı
satır.

## Farkın Ölçülmesi

Ölçüm süreç içi bir modeldir: gerçek dış taraf, ağ ya da depo yoktur; gecikme ve kayıp
parametredir, zaman model saatidir. Model bir çevrimin işlemlerini üretir, her biri için dış
tarafta sonuçlanma anıyla yerel tarafın bunu öğrendiği anı hesaplar ve çevrim bitince iki
durumu karşılaştırır. Fark üç kaynağa ayrılır: bildirimi kaybolan, bildirimi geç gelen ve dış
tarafta henüz sonuçlanmamış işlem — sonuncusu fark değildir, iki taraf da aynı şeyi söyler.

```js
// odeme/mutabakat.mjs — iki tarafin kayitlari arasindaki farkin surec ici modeli. Gercek dis
// taraf, ag ya da depo yoktur: gecikme ve kayip parametredir, zaman model saatidir (saniye).
const TEPE = 55.56, YOKLAMA = 60, KAYIP = 0.03;      // hesap; OD5, OD4
const SONUCLANMA = 3;                                 // dis tarafta islemin bitme suresi (s)

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

// OD3: bildirim gecikmesi uc dilimde - %92 hizli, %6 gecikmeli, %2 gec gelen
const gecikme = (r) => (r < 0.92 ? 5 * (r / 0.92)
  : r < 0.98 ? 5 + 295 * ((r - 0.92) / 0.06)
  : 300 + 1500 * ((r - 0.98) / 0.02));

export function kos({ cevrim, yoklamali, tohum }) {
  const rnd = uretec(tohum);
  const n = Math.round(TEPE * cevrim);
  const s = { islem: n, gecGelen: 0, kaybolan: 0, sonuclanmamis: 0 };
  for (let i = 0; i < n; i += 1) {
    const baslangic = (i / TEPE), biten = baslangic + SONUCLANMA;
    const kayipMi = rnd() < KAYIP, g = gecikme(rnd());
    const bildirim = kayipMi ? Infinity : biten + g;
    const yoklamaAni = yoklamali ? Math.ceil(biten / YOKLAMA) * YOKLAMA : Infinity;
    const bilinen = Math.min(bildirim, yoklamaAni);
    if (biten >= cevrim) { s.sonuclanmamis += 1; continue; }  // dis tarafta da bitmemis
    if (bilinen < cevrim) continue;                           // iki taraf da biliyor
    if (kayipMi) s.kaybolan += 1; else s.gecGelen += 1;
  }
  s.eslesmeyen = s.gecGelen + s.kaybolan;
  s.binde = (1000 * s.eslesmeyen) / s.islem;
  return s;
}

const yaz = (etiket, r) =>
  console.log(`${etiket.padEnd(26)}${String(r.islem).padStart(9)}${String(r.eslesmeyen).padStart(12)}` +
    `${String(r.gecGelen).padStart(11)}${String(r.kaybolan).padStart(10)}` +
    `${String(r.sonuclanmamis).padStart(15)}${r.binde.toFixed(2).padStart(9)}`);

console.log(`model: tepe ${TEPE} islem/s, bildirim kaybi ${KAYIP}, yoklama ${YOKLAMA} s, tohum 20260730`);
console.log(`\n${"duzen (cevrim 900 s)".padEnd(26)}${"islem".padStart(9)}${"eslesmeyen".padStart(12)}` +
  `${"gec gelen".padStart(11)}${"kaybolan".padStart(10)}${"sonuclanmamis".padStart(15)}${"binde".padStart(9)}`);
yaz("yalniz bildirim", kos({ cevrim: 900, yoklamali: false, tohum: 20260730 }));
yaz("bildirim + yoklama", kos({ cevrim: 900, yoklamali: true, tohum: 20260730 }));

console.log(`\n${"mutabakat cevrimi".padStart(19)}${"islem".padStart(9)}${"eslesmeyen".padStart(12)}` +
  `${"binde".padStart(9)}${"esik binde 10".padStart(15)}${"kapanma dk".padStart(12)}${"esik 30 dk".padStart(12)}`);
for (const c of [300, 900, 3600]) {
  const r = kos({ cevrim: c, yoklamali: true, tohum: 20260730 });
  console.log(`${`${c / 60} dk`.padStart(19)}${String(r.islem).padStart(9)}${String(r.eslesmeyen).padStart(12)}` +
    `${r.binde.toFixed(2).padStart(9)}${(r.binde <= 10 ? "gecer" : "gecmez").padStart(15)}` +
    `${String((2 * c) / 60).padStart(12)}${((2 * c) / 60 <= 30 ? "gecer" : "gecmez").padStart(12)}`);
}

const a = kos({ cevrim: 900, yoklamali: false, tohum: 20260730 });
const b = kos({ cevrim: 900, yoklamali: true, tohum: 20260730 });
const c60 = kos({ cevrim: 3600, yoklamali: true, tohum: 20260730 });
console.log(`\nyoklamanin kapattigi fark: ${a.eslesmeyen} -> ${b.eslesmeyen} kayit ` +
  `(binde ${a.binde.toFixed(2)} -> ${b.binde.toFixed(2)})`);
console.log(`kalan farkin ${b.gecGelen}/${b.eslesmeyen} tanesi gec gelen onaydir`);
console.log(`cevrim 15 dk -> 60 dk: eslesmeyen sayisi ${b.eslesmeyen} -> ${c60.eslesmeyen} (neredeyse ayni), ` +
  `binde ${b.binde.toFixed(2)} -> ${c60.binde.toFixed(2)}`);
```

```
model: tepe 55.56 islem/s, bildirim kaybi 0.03, yoklama 60 s, tohum 20260730

duzen (cevrim 900 s)          islem  eslesmeyen  gec gelen  kaybolan  sonuclanmamis    binde
yalniz bildirim               50004        2987       1437      1550            166    59.74
bildirim + yoklama            50004         488        369       119            166     9.76

  mutabakat cevrimi    islem  eslesmeyen    binde  esik binde 10  kapanma dk  esik 30 dk
               5 dk    16668         488    29.28         gecmez          10       gecer
              15 dk    50004         488     9.76          gecer          30       gecer
              60 dk   200016         482     2.41          gecer         120      gecmez

yoklamanin kapattigi fark: 2987 -> 488 kayit (binde 59.74 -> 9.76)
kalan farkin 369/488 tanesi gec gelen onaydir
cevrim 15 dk -> 60 dk: eslesmeyen sayisi 488 -> 482 (neredeyse ayni), binde 9.76 -> 2.41
```

Bu sayılar **ölçüm** sınıfındadır; tohum 20260730 ile yeniden üretilir.

İlk tablo yoklamanın payını ayırıyor. Yalnız bildirime dayanan düzende çevrim başına 2987 kayıt
eşleşmiyor, binde 59,74; eşik binde 10 olduğuna göre bu düzen tek başına geçmiyor. Yoklama
eklendiğinde fark 488'e, binde 9,76'ya iniyor: kaybolan bildirim 1550'den 119'a düşüyor, çünkü
en geç 60 saniye içinde sorgulamayla bulunuyor.

Kalan 488 kaydın 369'u **geç gelen onaydır** ve yoklama bunu kapatamaz: dış taraf işi bitirmiş,
bildirimi henüz göndermemiştir, yoklama da o anda "beklemede" yanıtı alır. Bu bir hata değil,
iki tarafın saatleri arasındaki gerçek bir aralıktır; mutabakatın işi onu **saymak** ve
kapanmasını beklemektir.

İkinci tablo çevrim aralığını seçiyor ve en öğretici satır sayının kendisidir: eşleşmeyen kayıt
5 dakikada 488, 15 dakikada 488, 60 dakikada 482 — neredeyse hiç değişmiyor. Fark bir sınır
olayıdır; çevrimin uzunluğuyla değil, **kenarındaki** işlem sayısıyla belirlenir. Çevrimi
uzatmak farkı çözmez, oranı binde 29,28'den binde 2,41'e seyreltir. Kapanma süresi ise iki
çevrim uzunluğundadır: 10, 30 ve 120 dakika. İki eşik iki yönden bastırıyor ve yalnız 15
dakika ikisini birden geçiyor.

## Tasarım

**Durum bildirimi ve yoklama.** Dış tarafın bildirimi Uygulama Katmanı ve Servis Etkileşimi
kursunun Eşzamansız İstek–Yanıt dersindeki yapıdır; yoklama ise bu konunun ilk vakasında
**elenmiş** kalıptır. Orada birincil teslim yolu olarak 140,63 kat istek ürettiği için
elenmişti; burada yalnız beklemede kalanı sorduğu için tepe yükü saniyede 1,67 sorgudur. Aynı
kalıp, farklı rol, farklı parametre.

**Denetim izi.** Veri Katmanı Ölçekleme kursunun Olay Kaynaklı Tasarım dersindeki eklemeli
kütük burada denetim izidir; parametre saklama süresi ve geçiş sayısıdır: işlem başına 5 satır,
260 bayt, yedi yılda 3,99 TB. İzin üzerine yazılmaz, yalnız eklenir; işlemin o anki durumu
izden türetilen bir izdüşümdür.

**Fark bulununca yapılan iş.** Eşleşmeyen kayıt Dayanıklılık ve Güvenilirlik kursunun Telafi
Edici İşlemler dersindeki adımı doğurur: yerel taraf "başarılı" derken dış taraf "reddedildi"
diyorsa yerel etki geri alınır. Parametre, telafinin yalnız **mutabakat** tarafından
tetiklenmesidir; hiçbir istek yolu kendi başına telafi başlatmaz.

**Bilerek kullanılmayan kalıp.** Ödeme durumu önbelleğe alınmaz (Veri Katmanı Ölçekleme,
Önbellek Mimarisi): bayat bir durum kullanıcıya kesinleşmiş gibi gösterilir — burada bayatlık
bir pencere değil, bir kusurdur.

## Elenen Alternatif: Eşzamanlı Doğrulama

Mutabakat çevrimini büsbütün ortadan kaldıran bir tasarım savunulabilir: her ödeme dış tarafa
senkron sorulur ve istek yanıtı bekler, yani ayrışacak iki defter hiç oluşmaz. Bu düzenin
duyarlı olduğu şey yük değil, dış tarafta **sonuçlanma süresidir**. Seçilen tasarımda o süre
uzadıkça işlemler yukarıdaki modelin üçüncü kaynağına, fark saymayan kovaya düşer; eşzamanlı
düzende ise doğrudan yanıtsız isteğe dönüşür. Alternatifin modeli bu yüzden sonuçlanmaya kendi
dağılımını (OD9) ve isteğe bir bekleme bütçesi (OD10) verir; senkron yanıt kayıpsız sayılır,
ölçü alternatife elverişlidir.

```js
// odeme/eszamanli.mjs — elenen alternatifin surec ici modeli. Gercek dis taraf yoktur:
// sonuclanma suresi parametredir, zaman model saatidir (saniye).
const TEPE = 55.56, CEVRIM = 900, N = Math.round(TEPE * CEVRIM);   // hesap; OD6

function uretec(tohum) {                        // 32 bitlik dogrusal esitlikli uretec
  let s = tohum >>> 0;
  return () => { s = (Math.imul(s, 1103515245) + 12345) >>> 0; return s / 4294967296; };
}
const sonuclanma = (r) =>                       // OD9: %90 3 s, %8 3-60 s, %2 60-900 s
  (r < 0.9 ? 3 : r < 0.98 ? 3 + 57 * ((r - 0.9) / 0.08) : 60 + 840 * ((r - 0.98) / 0.02));

function kos(butce) {                           // her odeme yanit gelene dek istegi acik tutar
  const rnd = uretec(20260730);
  let belirsiz = 0, tutulan = 0;
  for (let i = 0; i < N; i += 1) {
    const s = sonuclanma(rnd());
    tutulan += Math.min(s, butce);
    if (s > butce) belirsiz += 1;               // yanitsiz kapandi, kapatacak cevrim de yok
  }
  return { belirsiz, binde: (1000 * belirsiz) / N, ort: tutulan / N };
}

console.log(`model: tepe ${TEPE} islem/s, cevrim ${CEVRIM} s, ${N} islem, tohum 20260730`);
for (const b of [20, 60, 540]) {
  const r = kos(b);
  console.log(`butce ${b} s: belirsiz ${r.belirsiz} (binde ${r.binde.toFixed(2)}, esik ` +
    `${r.binde <= 10 ? "gecer" : "gecmez"}), ortalama tutulma ${r.ort.toFixed(2)} s, ` +
    `tepede acik istek ${(TEPE * r.ort).toFixed(1)}`);
}
```

```
model: tepe 55.56 islem/s, cevrim 900 s, 50004 islem, tohum 20260730
butce 20 s: belirsiz 3789 (binde 75.77, esik gecmez), ortalama tutulma 4.48 s, tepede acik istek 249.1
butce 60 s: belirsiz 995 (binde 19.90, esik gecmez), ortalama tutulma 6.38 s, tepede acik istek 354.4
butce 540 s: belirsiz 421 (binde 8.42, esik gecer), ortalama tutulma 13.06 s, tepede acik istek 725.7
```

Bu sayılar **ölçüm** sınıfındadır; tohum 20260730 ile yeniden üretilir. Alternatifi eleyen sayı
**binde 75,77**tir: 20 saniyelik bütçede çevrim başına 3789 işlem yanıtsız kapanır — eşiğin 7,6
katı — ve bunları kapatacak bir çevrim yoktur; kapanma süresi 30 dakika değil, tanımsızdır.
Bütçeyi büyütmek ucuz değildir: 60 saniyede oran binde 19,90'da kalıyor, eşik ancak 540
saniyede geçiliyor, yani istemci dokuz dakika bekletilerek; o noktada tepede aynı anda 725,7
istek açık duruyor.

Kazandığı da yazılır: bütçe içinde yanıtlanan işlemde iki defter **yanıt anında** eşleşir,
ortalama kapanma 4,48 saniyedir, çevrim ve telafi işi hiç doğmaz. Kısıt şurada dönerdi: dış
taraf işlemlerin yüzde 99'unu bütçe içinde sonuçlandırsaydı belirsiz oran binde 10'a iner,
alternatif eşiği geçer ve mutabakat çevrimi gereksizleşirdi.

## Arıza Davranışı ve Feda Edilen

Dış tarafın bildirim ucu tümden durursa yoklama tek kanal kalır ve bütün işlemler en geç 60
saniye gecikmeyle öğrenilir; bu tepe yükte saniyede 55,56 sorgudur, normalin 33 katıdır ve
Dayanıklılık ve Güvenilirlik kursunun Kısıtlama ve Yük Boşaltma dersindeki kısıtlama bu hızı
keser. Mutabakat çevrimi kaçırılırsa fark kaybolmaz, sonraki çevrimde iki katı kayıtla görünür;
mutabakatın kendisi durumunu izden yeniden kurduğu için kesintiye dayanıklıdır.

Feda edilen tek cümlededir: bu tasarım anlık tutarlılığı feda eder — iki defter hiçbir zaman
aynı anda aynı şeyi söylemez, yalnız 30 dakika içinde söyleyeceği güvence altına alınır.

## Özet

- Bu vakada hacim karar vermiyor: tepe 55,56 işlem/s her yapıda taşınır, asıl hacim kalemi
  denetim izidir — günde 1,56 GB, yedi yılda 3,99 TB.
- Yalnız bildirime dayanan düzende çevrim başına 2987 kayıt eşleşmiyor (binde 59,74); yoklama
  bunu 488'e (binde 9,76) indiriyor ve kaybolan bildirimi 1550'den 119'a düşürüyor.
- Kalan 488 farkın 369'u geç gelen onaydır; yoklama bunu kapatamaz, çünkü dış taraf da o anda
  sonucu bildirmemiştir.
- Eşleşmeyen kayıt sayısı çevrim uzunluğundan neredeyse bağımsızdır (488, 488, 482); çevrimi
  uzatmak farkı çözmez, oranı binde 29,28'den binde 2,41'e seyreltir.
- İki eşik çevrimi tek bir değere sıkıştırıyor: binde 10 sınırı 5 dakikayı, 30 dakikalık
  kapanma sınırı 60 dakikayı eliyor ve 15 dakika kalıyor.
- Çevrimsiz eşzamanlı doğrulama alternatifi binde 75,77 belirsiz kayıtla eleniyor; eşiği ancak
  540 saniyelik bekleme bütçesiyle, tepede 725,7 açık istekle geçiyor.

## Sonraki Adım

Beş vaka aynı ailedendi: yazma hâkimdi ve bir kaydın yanlış olması kabul edilmiyordu. Kararlar
teslim garantisinden, kanal sırasından, pencere biçiminden, kilit türünden ve mutabakat
çevriminden çıktı. Beşinde de gözden kaçan ortak bir özellik var: veri **küçüktü**. Bir ileti
220 bayt, bir bildirim kaydı 300 bayt, bir sayaç 48 bayt, bir stok satırı 64 bayt, bir iz
kaydı 260 bayttı; hiçbir tasarım kararı baytın kendisinden çıkmadı, hepsi kayıt başına anlamdan
çıktı. Kaydın tek başına anlamsız olduğu, değerinin ancak yığın hâlinde ortaya çıktığı ve tek
bir nesnenin bir sunucunun belleğine sığmadığı sistemlerde bu sıralama tersine döner. Sonraki
konu o tersine dönmüş sıralamayı ele alır.
