Ders 12 / 15
Koreografi ve Orkestrasyon
Dört adımı dört servise yayılan gün sonu ücretlendirme işinin iki modelle kurulması: adımların birbirini olayla tetiklediği koreografi ile tek yürütücünün adımları çağırdığı orkestrasyon; ortak işlem sınırının kaybolduğunun gösterilmesi, telafi adımının kurulması ve iki kipin ileti, telafi edilen adım, telafisiz kalan adım ile yarım kalan iş cinsinden ölçülmesi.
İçindekiler
Önceki dersin bütün olayları tek adımlıydı: bir durum yazılır ve iş biter. Gün sonu ücretlendirmesi böyle değildir. Bir satıcının bir günü için tarife hesaplanır, indirim uygulanır, fatura satırı üretilir ve bildirim gönderilir. Dört adım birbirini bekler ve her adım ayrı bir serviste yürür — tarife ile fatura ücretlendirme bağlamında, indirim sözleşme bağlamında, bildirim ise teslimat operasyonu tarafında.
İşi kurmanın iki modeli vardır. Koreografi (choreography) düzeninde ortada yürütücü yoktur: her adım bittiğinde bir olay yayımlar, sonraki adımın servisi o olaya abonedir. Orkestrasyon (orchestration) düzeninde tek bir yürütücü adımları sırayla çağırır ve işin nerede olduğunu kendi tutar. Koreografi, Mimari Biçemler kursunda anlatılan olay güdümlü mimarinin iş akışı hâlidir; biçemin kendisi ve yayımla–abone ol mekaniği orada ve Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunda kuruldu, burada yeniden anlatılmaz. Ölçülen şey iki kipin aynı işi aynı hatalarla koştururken bıraktığı sayılardır.
Ortak İşlem Sınırı Yok
Veri Erişim Katmanı ve İş Mantığı kursu iş birimini ve işlem sınırını kurmuştu: bir sınırın içindeki yazmalar ya birlikte kesinleşir ya hiçbiri kesinleşmez. Dört adım dört ayrı serviste yürüdüğünde bu dayanak kalkar. Her servis kendi sınırını kendi açar ve kapatır; üçüncü adım başarısız olduğunda birinci ve ikinci adımın yazmaları çoktan kesinleşmiştir ve onları birlikte geri alacak bir çağrı yoktur.
Yerine konan şey bir telafi adımıdır: her adımın etkisini iş anlamıyla geri alan ikinci bir
adım tanımlanır ve hata çıktığında tamamlananlar tersten telafi edilir. Telafi geri alma
değildir; yazma bir süre görünür kalır, sonra ters bir yazmayla kapatılır. Dördüncü adım —
bildirim — telafi edilemez, çünkü gönderilmiş bir bildirim geri alınamaz; bu yüzden sıranın
sonuna konur. Sıralamadaki bu kural iki kip için de aynıdır ve modelde telafi alanının null
olmasıyla yazılıdır.
// akis/is.mjs — gun sonu ucretlendirme is akisinin surec ici modeli. Dort adim dort ayri // serviste yurur; her servis kendi islem sinirini kendi kapatir, ortak bir sinir yoktur. export const ADIM = [ { ad: "tarife", servis: "ucretlendirme", telafi: "tarife-iptal" }, { ad: "indirim", servis: "sozlesme", telafi: "indirim-iptal" }, { ad: "fatura", servis: "faturalama", telafi: "fatura-iptal" }, { ad: "bildirim", servis: "bildirim", telafi: null }, // geri alinamaz, bu yuzden sonda ]; export const ISLER = ["S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8"]; export const HATA = { S3: "fatura", S7: "indirim" }; // belirlenimli hata noktalari // kip: "koreografi" adimlari olayla tetikler, "orkestrasyon" tek yuruticuyle cagirir. // eksikAbone: koreografide iptal olayina abone olmamis servis (null ise zincir tam). export function kosum({ kip, eksikAbone = null }) { const s = { tamamlanan: 0, adim: 0, ileti: 0, telafiEdilen: 0, telafisizAdim: 0, yarimKalanIs: 0 }; const kalici = new Map(ADIM.map((a) => [a.ad, new Set()])); // kesinlesmis yazmalar const iz = []; for (const is of ISLER) { if (kip === "koreografi") s.ileti += 1; // is akisini baslatan olay const yapilan = []; let hata = null; for (const a of ADIM) { if (kip === "orkestrasyon") s.ileti += 1; // yurutucu -> servis komutu if (HATA[is] === a.ad) { hata = a.ad; s.ileti += 1; break; } // hata yaniti ya da olayi s.adim += 1; kalici.get(a.ad).add(is); // adim kendi sinirinda kesinlesti yapilan.push(a); s.ileti += 1; // koreografi: adimin yayimladigi olay; orkestrasyon: yanit } if (hata === null) { s.tamamlanan += 1; continue; } let acik = 0; for (const a of [...yapilan].reverse()) { if (a.telafi === null) continue; const abone = kip === "orkestrasyon" || a.servis !== eksikAbone; s.ileti += kip === "orkestrasyon" ? 2 : (abone ? 1 : 0); // telafi komutu+yanit / iptal olayi if (abone) { kalici.get(a.ad).delete(is); s.telafiEdilen += 1; } else { s.telafisizAdim += 1; acik += 1; } // kimse dinlemedi, yazma kaldi } if (acik > 0) s.yarimKalanIs += 1; iz.push(`${is}: ${hata} adiminda durdu, kesinlesmis adim ${yapilan.length}, acik kalan ${acik}`); } return { ...s, iz, kalanYazma: ADIM.map((a) => `${a.ad}=${kalici.get(a.ad).size}`).join(" ") }; } // Yapisal olculer: kip secildiginde bellidir, kosuma bagli degildir. export function yapi(kip) { const n = ADIM.length, telafili = ADIM.filter((a) => a.telafi !== null).length; const o = kip === "orkestrasyon"; return { "is akisi tanimini tasiyan birim": o ? 1 : n, "is akisi durumunu tutan birim": o ? 1 : 0, "durumu okumak icin sorulan birim": o ? 1 : n, "telafi sorumlulugu tasiyan birim": o ? 1 : telafili, "sona adim eklenince degisen birim": o ? 2 : 1, "islem siniri": n, "atomik geri alinabilen adim": 0, }; }
Üçüncü koşum bir soruyu sınar: koreografide telafi de bir olayla tetiklenir, yani her servisin
iptal olayına abone olmuş olması gerekir. eksikAbone bir servisin bu aboneliği kurmadığı
durumu üretir.
// akis/olc.mjs — iki kip ayni is kumesinde: adim, ileti, telafi, yarim kalan is ve yapi import { kosum, yapi, ISLER, ADIM, HATA } from "./is.mjs"; const K = [["koreografi", kosum({ kip: "koreografi" })], ["kor+eksik abone", kosum({ kip: "koreografi", eksikAbone: "ucretlendirme" })], ["orkestrasyon", kosum({ kip: "orkestrasyon" })]]; const OLCU = [["tamamlanan", "tamamlanan is"], ["adim", "yurutulen adim"], ["ileti", "ileti"], ["telafiEdilen", "telafi edilen adim"], ["telafisizAdim", "telafisiz kalan adim"], ["yarimKalanIs", "yarim kalan is"]]; console.log(`${ISLER.length} satici-gun, ${ADIM.length} adim, ` + `${Object.keys(HATA).length} is hata veriyor: ${Object.entries(HATA).map(([i, a]) => `${i}@${a}`).join(", ")}`); console.log(); console.log(`${"olcu".padEnd(22)}${K.map(([a]) => a.padStart(17)).join("")}`); for (const [k, ad] of OLCU) console.log(`${ad.padEnd(22)}${K.map(([, r]) => String(r[k]).padStart(17)).join("")}`); console.log(`\nhata izi (uc kosumda da ayni):`); for (const satir of K[2][1].iz) console.log(` ${satir}`); console.log(`kesinlesmis kalan yazma:`); for (const [ad, r] of K) console.log(` ${ad.padEnd(16)}${r.kalanYazma}`); const YAPI = Object.keys(yapi("orkestrasyon")); console.log(`\n${"yapisal olcu".padEnd(36)}${"koreografi".padStart(13)}${"orkestrasyon".padStart(14)}`); for (const a of YAPI) console.log(`${a.padEnd(36)}${String(yapi("koreografi")[a]).padStart(13)}` + `${String(yapi("orkestrasyon")[a]).padStart(14)}`); const [kor, , ork] = K.map(([, r]) => r); console.log(`\nileti orani orkestrasyon/koreografi = ${(ork.ileti / kor.ileti).toFixed(3)}`); console.log(`is basina ileti: koreografi ${(kor.ileti / ISLER.length).toFixed(2)}, ` + `orkestrasyon ${(ork.ileti / ISLER.length).toFixed(2)}`);
8 satici-gun, 4 adim, 2 is hata veriyor: S3@fatura, S7@indirim olcu koreografi kor+eksik abone orkestrasyon tamamlanan is 6 6 6 yurutulen adim 27 27 27 ileti 40 38 64 telafi edilen adim 3 1 3 telafisiz kalan adim 0 2 0 yarim kalan is 0 2 0 hata izi (uc kosumda da ayni): S3: fatura adiminda durdu, kesinlesmis adim 2, acik kalan 0 S7: indirim adiminda durdu, kesinlesmis adim 1, acik kalan 0 kesinlesmis kalan yazma: koreografi tarife=6 indirim=6 fatura=6 bildirim=6 kor+eksik abone tarife=8 indirim=6 fatura=6 bildirim=6 orkestrasyon tarife=6 indirim=6 fatura=6 bildirim=6 yapisal olcu koreografi orkestrasyon is akisi tanimini tasiyan birim 4 1 is akisi durumunu tutan birim 0 1 durumu okumak icin sorulan birim 4 1 telafi sorumlulugu tasiyan birim 3 1 sona adim eklenince degisen birim 1 2 islem siniri 4 4 atomik geri alinabilen adim 0 0 ileti orani orkestrasyon/koreografi = 1.600 is basina ileti: koreografi 5.00, orkestrasyon 8.00
Sayıların Okunması
İki kip aynı işi yapıyor: 8 satıcı-gününün 6’sı tamamlandı, 27 adım yürütüldü, telafi edilen adım ikisinde de 3. İş sonucu açısından fark yok. Fark iki başka yerde toplanıyor.
Birincisi ileti sayısıdır: koreografi 40, orkestrasyon 64 — oran 1,600. İş başına 5’e karşı 8. Sebep yapısaldır: koreografide bir adım tamamlandığında tek bir olay yayımlanır ve sonraki adım onu kendisi alır; orkestrasyonda her adım bir komut ve bir yanıt gerektirir, telafi de öyle. Yürütücünün işin nerede olduğunu bilmesi bedavaya gelmez; bilgiyi taşıyan iletileri kendisi ödetir.
İkincisi üçüncü sütundadır ve asıl karar oradadır. Koreografide telafi de bir olayla tetiklenir;
ücretlendirme servisi iptal olayına abone olmadığında telafi edilen adım 3’ten 1’e iner,
telafisiz kalan adım 0’dan 2’ye çıkar ve 2 iş yarım kalır. tarife satırındaki kesinleşmiş
yazma 6’dan 8’e çıkıyor: iki satıcı için tarife hesabı sistemde durmaya devam ediyor, oysa
faturaları hiç üretilmedi. Bu iki yazma bir hata mesajı üretmez; yalnız ay sonunda mutabakat
tutmaz.
Kaçırılan aboneliğin orkestrasyonda karşılığı yoktur, çünkü telafi listesi yürütücünün kodundadır. Yapısal tablo bunu adlandırıyor: telafi sorumluluğu koreografide 3 birime dağılmış, orkestrasyonda 1 birimde toplanmış. Aynı satır düzeni iş akışı tanımı ve durumu için de geçerli. Koreografide iş akışının tanımı hiçbir yerde bütün olarak yazılı değildir; onu okumak için dört servisin abonelik listesine bakmak gerekir ve “bu iş nerede kaldı” sorusunu tek bir birime soramazsınız.
Tablonun tek satırı ters yönde: sona adım eklendiğinde koreografide 1 birim değişir (yeni servis son olaya abone olur), orkestrasyonda 2 (yeni servis ve yürütücü). Koreografinin kazancı burada somuttur ve iletideki 1,600 çarpanıyla birlikte okunmalıdır.
Hesaba Dönüş
Modelin 8 işi ve 2 hatası bir hacim değildir; ölçülen şey iş başına orandır. Hacim K01’den gelir: günde 4000 fatura satırı bir hesaptır ve her satır bir satıcının bir günü olduğuna göre günde 4000 iş akışı koşar; gün sonu penceresi 4 saat K01’in V10 varsayımıdır.
KK2 — gün sonu iş akışının hata oranı 0,02. Gerekçesi eksik sözleşme kaydı, pencere kapandıktan sonra gelen tarife değişikliği ve henüz kapanmamış gönderilerin sürekli bir taban üretmesidir. Modelin 2/8 oranı gerçekçi değildir ve öyle sunulmaz; K01’in tablosuna da eklenmez. Duyarlılığı 0,04 ile birlikte hesaplanır.
// akis/hesap.mjs — modelin oranlarini K01'in gun sonu is hacmine uygular import { kosum, yapi, ISLER, ADIM } from "./is.mjs"; const FATURA_SATIRI = 4000; // K01: gunluk fatura satiri (hesap) — satici basina bir is akisi const PENCERE = 4 * 3600; // K01 V10: gun sonu penceresi 4 saat (varsayim) const kor = kosum({ kip: "koreografi" }), ork = kosum({ kip: "orkestrasyon" }); const eksik = kosum({ kip: "koreografi", eksikAbone: "ucretlendirme" }); const iletiPerIs = { koreografi: kor.ileti / ISLER.length, orkestrasyon: ork.ileti / ISLER.length }; const hataliIs = 2; // modeldeki hata veren is sayisi const telafiPerHata = kor.telafiEdilen / hataliIs; const telafisizPerHata = eksik.telafisizAdim / hataliIs; console.log(`is akisi ${FATURA_SATIRI}/gun, pencere ${PENCERE} s -> ` + `${(FATURA_SATIRI / PENCERE).toFixed(4)} is/s, ${(FATURA_SATIRI * ADIM.length / PENCERE).toFixed(4)} adim/s`); for (const [ad, n] of Object.entries(iletiPerIs)) console.log(` ${ad.padEnd(13)} ${n.toFixed(2)} ileti/is -> ${(FATURA_SATIRI * n / PENCERE).toFixed(4)} ileti/s`); console.log(`\n${"KK2".padStart(5)}${"hatali is/gun".padStart(15)}${"telafi adim/gun".padStart(17)}` + `${"telafisiz adim/gun".padStart(20)}${"yarim kalan is/gun".padStart(20)}`); for (const KK2 of [0.02, 0.04]) { // KK2: gun sonu is akisinin hata orani const hatali = FATURA_SATIRI * KK2; console.log(`${KK2.toFixed(2).padStart(5)}${hatali.toFixed(0).padStart(15)}` + `${(hatali * telafiPerHata).toFixed(0).padStart(17)}` + `${(hatali * telafisizPerHata).toFixed(0).padStart(20)}${hatali.toFixed(0).padStart(20)}`); } console.log(`\nmodelden gelen oranlar: hata basina telafi edilen adim = ${telafiPerHata.toFixed(2)}, ` + `eksik abonede telafisiz kalan = ${telafisizPerHata.toFixed(2)}`); console.log(`K01 tepe yazma 97.22 istek/s ile karsilastirma: orkestrasyon ileti akisi ` + `${(100 * (FATURA_SATIRI * iletiPerIs.orkestrasyon / PENCERE) / 97.22).toFixed(2)}%`); console.log(`is akisi tanimini okumak icin acilacak birim: koreografi ` + `${yapi("koreografi")["is akisi tanimini tasiyan birim"]}, orkestrasyon ` + `${yapi("orkestrasyon")["is akisi tanimini tasiyan birim"]}`);
is akisi 4000/gun, pencere 14400 s -> 0.2778 is/s, 1.1111 adim/s koreografi 5.00 ileti/is -> 1.3889 ileti/s orkestrasyon 8.00 ileti/is -> 2.2222 ileti/s KK2 hatali is/gun telafi adim/gun telafisiz adim/gun yarim kalan is/gun 0.02 80 120 80 80 0.04 160 240 160 160 modelden gelen oranlar: hata basina telafi edilen adim = 1.50, eksik abonede telafisiz kalan = 1.00 K01 tepe yazma 97.22 istek/s ile karsilastirma: orkestrasyon ileti akisi 2.29% is akisi tanimini okumak icin acilacak birim: koreografi 4, orkestrasyon 1
İleti farkı büyütüldüğünde küçülüyor. Dört saatlik pencerede iş akışı hızı saniyede 0,2778, adım hızı 1,1111; koreografi saniyede 1,3889 ileti, orkestrasyon 2,2222 ileti üretiyor. Orkestrasyonun fazlası saniyede 0,83 iletidir ve K01’in tepe yazma akışının yüzde 2,29’u kadardır. İleti sayısındaki 1,600 çarpan, sistemin bütününde bir kapasite sorunu değildir.
Öteki sütun aynı büyütmede tersine davranıyor. KK2 = 0,02 ile günde 80 iş akışı hata veriyor; model oranıyla günde 120 telafi adımı yürütülür. Telafi zincirinde tek bir eksik abonelik, günde 80 telafisiz adım ve 80 yarım kalan iş demektir. KK2 iki katına çıkarsa 160 olur. Bu sayılar bir kesinti üretmez, bir hata sayacı artırmaz; yalnız ay sonu mutabakatında ortaya çıkar. Ölçülen iki maliyet arasındaki mertebe farkı kararı veriyor: koreografinin ileti kazancı uçtaki akışın yüzde ikisi kadar, telafi zincirindeki bir boşluğun bedeli ise günde 80 yanlış kayıttır. Adım sayısı üçü aşan ve telafi gerektiren iş akışları için orkestrasyon, telafi sorumluluğunu tek bir birime topladığı için savunulabilir olandır; adımların birbirinden habersiz büyümesi beklenen, telafisi olmayan bildirim türü akışlar için koreografi yerindedir.
Özet
- Dört adım dört serviste yürüdüğünde ortak işlem sınırı yoktur: işlem sınırı sayısı 4, atomik olarak geri alınabilen adım 0; hata çıktığında önceki adımlar kesinleşmiş kalır.
- Yerine telafi adımı konur; telafi edilemeyen adım (bildirim) sıralamanın sonuna alınır.
- İki kip aynı sonucu üretiyor — 6 tamamlanan iş, 27 adım, 3 telafi — ama koreografi 40, orkestrasyon 64 ileti harcıyor (oran 1,600; iş başına 5’e karşı 8).
- Koreografide telafi sorumluluğu 3 birime dağılır: tek bir eksik abonelik telafi edileni 3’ten
1’e indirdi, 2 adımı telafisiz bıraktı ve
tarifeyazmalarını 6’dan 8’e çıkardı. - Yapısal fark iş akışının tanımında toplanıyor: koreografide tanım 4 birime dağılmış ve durumu tutan birim 0; orkestrasyonda ikisi de 1. Ters yöndeki tek satır uzatmadır — sona adım eklenince koreografide 1, orkestrasyonda 2 birim değişir.
- K01’e dönüş: 4000 iş akışı ve 4 saatlik pencerede 0,2778 iş/s, 1,1111 adım/s; ileti farkı saniyede 0,83 (tepe yazmanın yüzde 2,29’u), buna karşılık KK2 = 0,02 ile eksik abonelik günde 80 telafisiz adım ve 80 yarım kalan iş bırakıyor.
Sonraki Adım
Bu dersin bütün hataları açıkça bildirildi: bir adım hata döndürdü, telafi zinciri işledi ya da işlemedi. Gerçek bir iş akışının çoğu arızası böyle konuşmaz. Yürütücü komutu gönderdikten sonra çöker, adım yanıt vermeden asılı kalır, telafi çağrısı bir kez denenir ve düşer. Böyle bir işin durumunu kimse sormazsa iş sonsuza kadar “yürüyor” görünür ve pencere kapanır. Sonraki ders bu boşluğu kapatan yerleşimi kurar: işi kalıcı olarak kaydeden ve adımları başlatan bir zamanlayıcı, adımı uzaktan yürüten bir aracı ve süresi dolan adımları bulup yeniden süren ya da telafi eden bir denetçi — ve denetçinin tarama sıklığının yarım kalan iş sayısına ne yaptığını ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.