İçeriğe geç
academia.sh

Ders 10 / 20

İş Akışı Orkestrasyonu

Beş adımlı bir fatura akışının durum makinesi olarak koşturulması: adım başına yeniden deneme ve telafi adımı sayısının ölçülmesi, akış durumunun orkestratöre taşınmasının getirdiği kısıtlar ve aynı akışı işlev içinde kurmakla orkestratöre vermek arasındaki farkın ücret ile kilitlenen eşzamanlılık cinsinden sayılması.

İçindekiler

Kuyruk iki işlevi güvenle bağlar: biri yazar, öteki okur, hata olursa ileti geri gelir. Ölçüm ağındaki fatura üretimi ise iki adım değil beş adımdır — okuma doğrulanır, tüketim hesaplanır, tarife uygulanır, fatura yazılır, bildirim gönderilir. Dördüncü adım kalıcı olarak hata verdiğinde ilk üçünün ne olacağı hiçbir kuyrukta yazılı değildir; kuyruk yalnız kendi iletisini bilir.

Telafi işlemleriyle yürüyen dağıtık iş akışı — saga kalıbı — daha önce ölçüldü. O kalıp burada tekrarlanmaz, yalnız adıyla anılır. Bu dersin sorusu şudur: akışın tamamı bir iş akışı orkestratörüne verildiğinde hangi karar devredilir ve karşılığında hangi sayı gelir.

Akışı Kim Tutuyor

Beş adımı tek bir işlevin içine yazmak en kısa yoldur: bir işlev, beş çağrı, aralarında if bloklarıyla hata yönetimi. Akışın durumu o işlevin yerel değişkenlerindedir. Bu, akış bitene kadar sorun çıkarmaz — çıktığında ise geriye hiçbir şey kalmaz. Üçüncü adımda ölen bir işlevin hangi adıma kadar geldiği, hangi adımın yan etkisini bıraktığı hiçbir yerde yazılı değildir.

Orkestratör bu durumu işlevin dışına alır. Her adımın başlangıcı, bitişi, girdisi, çıktısı ve deneme sayısı orkestratörün kaydına yazılır; işlev yalnız tek bir adımı yapar ve sonucu döner. Devredilen karar budur: akışın nerede olduğunu bilme sorumluluğu. Karşılığında gelen ilk kısıt aynı yerden çıkar — adımlar arasında geçen her veri o kayıttan geçer, dolayısıyla bir boyut sınırına tabidir ve büyük gövdeler adımlar arasında taşınamaz, ancak bir depoya yazılıp anahtarı taşınabilir.

Devredilen ikinci karar yeniden denemenin kendisidir. İşlev içinde yazılan bir akışta kaç kez deneneceği, ne kadar bekleneceği ve hangi hatanın yeniden denenebilir sayılacağı koddadır; orkestratörde bunlar adım tanımının yanında duran bir politikadır. Kazanç, politikanın koddan ayrılıp tek yerde görülmesidir. Kısıt ise akış tanımının önceki dersteki kuralla aynı yere düşmesidir: tanım bir yapılandırma kalemi olduğu için kod incelemesinden geçmez, bir adımın yeniden deneme sayısı üçten beşe çıkarıldığında hiçbir işlev değişmez ve fark yalnız faturada ve gecikmede görünür.

Ölçüm yine kurgu bölgesel ölçüm ağı üzerindedir.

  • OS13. Akış beş adımdır ve adım süreleri kurgu birimdir: 2, 3, 2, 4, 1.
  • OS14. Her adımın kendi hata oranı vardır; yeniden deneme politikası üç deneme ve denemeler arasında artan beklemedir (2 ve 4 birim).
  • OS15. 200 akışın on yedide birinde fatura yazımı kalıcı olarak çatışır; bu akışlar üç denemeyi de tüketir ve başarısız biter.
  • OS16. Telafi yalnız yan etkisi olan adımlar için tanımlıdır: tarife-uygula 1 birim, fatura-yaz 2 birim. İlk iki adımın telafisi yoktur.
  • OS17. Geçiş sayısı, adım denemeleri ile telafi adımlarının toplamıdır.
  • OS18. Model tek bir akışın içini kurar; akışlar arası eşzamanlılık ve sıra ölçülmez.

Durum Makinesi

// akis.mjs — is akisi orkestratoru modeli: adimlar, yeniden deneme politikasi, telafi yolu
// Model: gercek bir orkestrator degil, adim tabanli durum makinesinin sayilabilir kurulumu.
const TOHUM = 20260603;                       // uretec tohumu: kosum tekrarlanabilir
let d = TOHUM;
const r = () => (d = (d * 1103515245 + 12345) % 2147483648) / 2147483648;

const ADIM = [                                // sure ve telafi: kurgu birim
  { ad: "okuma-dogrula", sure: 2, hata: 0.06, telafi: 0 },
  { ad: "tuketim-hesapla", sure: 3, hata: 0.04, telafi: 0 },
  { ad: "tarife-uygula", sure: 2, hata: 0.10, telafi: 1 },
  { ad: "fatura-yaz", sure: 4, hata: 0.08, telafi: 2 },
  { ad: "bildirim-gonder", sure: 1, hata: 0.15, telafi: 0 },
];
const AZAMI = 3, BEKLE = [2, 4];              // 3 deneme; denemeler arasi artan bekleme
const N = 200;
const KALICI = (n) => n % 17 === 5;           // bu akislarda fatura yazimi her denemede catisir

const s = { deneme: ADIM.map(() => 0), hata: ADIM.map(() => 0), basarili: 0, telafi: 0,
            telafiAdim: 0, is: 0, duvar: 0, gecis: 0, enUzun: 0 };

for (let n = 0; n < N; n++) {
  const bitti = [], basi = s.duvar;
  let kesildi = false;
  for (let a = 0; a < ADIM.length && !kesildi; a++) {
    let deneme = 0, tamam = false;
    while (deneme < AZAMI) {
      deneme++; s.deneme[a]++; s.gecis++; s.is += ADIM[a].sure; s.duvar += ADIM[a].sure;
      const kalici = KALICI(n) && ADIM[a].ad === "fatura-yaz";
      if (!kalici && r() >= ADIM[a].hata) { tamam = true; break; }
      s.hata[a]++;
      if (deneme < AZAMI) s.duvar += BEKLE[deneme - 1];   // bekleme: is yok, sure var
    }
    if (tamam) { bitti.push(a); continue; }
    for (const t of bitti.reverse()) {                    // telafi: ters sirada geri alma
      if (ADIM[t].telafi === 0) continue;
      s.gecis++; s.is += ADIM[t].telafi; s.duvar += ADIM[t].telafi; s.telafiAdim++;
    }
    s.telafi++; kesildi = true;
  }
  if (!kesildi) s.basarili++;
  s.enUzun = Math.max(s.enUzun, s.duvar - basi);        // tek akisin en uzun duvar suresi
}

console.log("adim".padEnd(18) + "deneme".padStart(8) + "hata".padStart(7) +
  "deneme/akis".padStart(13));
ADIM.forEach((a, i) => console.log(a.ad.padEnd(18) + String(s.deneme[i]).padStart(8) +
  String(s.hata[i]).padStart(7) + (s.deneme[i] / N).toFixed(2).padStart(13)));
console.log(`\nakis: ${N}, basarili: ${s.basarili}, telafiye giden: ${s.telafi}, ` +
  `telafi adimi: ${s.telafiAdim}`);
console.log(`is suresi: ${s.is} birim, duvar suresi: ${s.duvar} birim, gecis: ${s.gecis}`);
console.log(`en uzun tek akis: ${s.enUzun} birim, tohum: ${TOHUM}`);
node akis.mjs
adim                deneme   hata  deneme/akis
okuma-dogrula          213     13         1.06
tuketim-hesapla        211     11         1.05
tarife-uygula          229     29         1.15
fatura-yaz             234     46         1.17
bildirim-gonder        220     32         1.10

akis: 200, basarili: 188, telafiye giden: 12, telafi adimi: 12
is suresi: 2685 birim, duvar suresi: 2967 birim, gecis: 1119
en uzun tek akis: 31 birim, tohum: 20260603

Adım tablosu, yeniden denemenin nereye yığıldığını gösteriyor. Beş adımın her biri ilk denemede geçseydi 200 akış 1.000 deneme yapardı; ölçümde 1.107 deneme var. Fark, hata veren adımların ikinci ve üçüncü denemeleridir. En yüklü adım fatura yazımıdır: 234 deneme, 46 hata. Bu 46’nın 36’sı kalıcı çatışan on iki akıştan gelir; kalan 10’u geçici hatadır ve yeniden denemeyle kapanmıştır.

Son satırdaki sayı ilk bakışta ters görünüyor: bildirim gönderme adımının hata oranı en yüksek olduğu halde akış başına denemesi 1,10, yani tarife adımından düşük. Nedeni paydadır — bu adıma yalnız 188 akış ulaştı, çünkü 12 akış bir önceki adımda kesildi. Aynı sayı ulaşan akışa bölündüğünde 1,17 çıkar. Adım ölçütleri akış sayısına değil, o adıma ulaşan akış sayısına bölünmelidir; yoksa akışın sonuna doğru bütün hata oranları olduğundan küçük görünür.

Telafi yolu iki sayı üretti: 12 akış telafiye gitti ve toplam 12 telafi adımı koştu. Oran akış başına birdir, çünkü fatura yazımı başarısız olduğunda geri alınacak tek yan etki tarife uygulamasıdır; ilk iki adımın telafisi tanımlı değildir. Bu, telafi tasarımının asıl sorusunu gösterir: geri alınacak adım sayısı, başarısız olan adımın kaçıncı olduğuna bağlıdır. Başarısızlık ne kadar geç olursa geri alma o kadar uzundur ve son adımda başarısız olan bir akışın telafisi, akışın kendisinden pahalı olabilir.

Yeniden deneme politikasının kendisi de bu sayıların içindedir. Azami deneme üç yerine beş olsaydı, kalıcı çatışan 12 akış fatura yazımında 36 değil 60 deneme harcardı: 24 fazladan deneme, 96 birim fazladan iş ve — beklemeler artan olduğu için — telafinin başlamasından önce akış başına daha uzun bir gecikme. Kalıcı hatada yeniden deneme hiçbir şeyi kurtarmaz, yalnız başarısızlığın kabul edilmesini geciktirir. Politikayı gevşetmenin bedeli buradan okunur; sıkılaştırmanın bedeli ise ters yöndedir — üç yerine iki deneme, tarife adımındaki 29 geçici hatanın bir bölümünü kalıcı başarısızlığa çevirir ve telafiye giden akış sayısını yükseltir.

Uzun Süren Akışın Ücretlendirilmesi

Toplam iş süresi 2.685 birim, duvar süresi 2.967 birim. Aradaki 282 birim, yeniden denemeler arasındaki beklemedir — hiçbir iş yapılmayan, ama akışın açık olduğu süre. Bu ölçümde bekleme toplamın yüzde 10’u kadardır, çünkü politikadaki bekleme değerleri küçük tutuldu. Onay bekleyen ya da dış bir servisin yanıtını bekleyen akışlarda oran tersine döner ve bekleme iş süresinin katlarına çıkar. Aşağıdaki hesap bu farkı bir çarpanla tarar; her satırda aynı 200 akış, yalnız beklemenin ağırlığı değişir. Farkın kime yazılacağı, akışın nerede kurulduğuna bağlıdır.

// akis-ucret.mjs — ayni 200 akis: akis islevin icinde mi, orkestratorde mi kuruluyor
// Sayilar ilk kosumdan okundu. Ucret birimi kurgudur; oran korunur, para birimi yoktur.
const N = 200, IS = 2685, DUVAR = 2967, GECIS = 1119;
const BEKLEME = DUVAR - IS;                   // adimlar arasi bekleme: is yapilmayan sure
const SURE_UCRET = 1;                         // kurgu birim: calisan sure birimi basina
const GECIS_UCRET = 0.25;                     // kurgu birim: orkestratorde durum gecisi basina

console.log("bekleme carpani".padEnd(17) + "islev icinde".padStart(14) +
  "orkestratorde".padStart(15) + "kilitlenen (islev)".padStart(20) +
  "kilitlenen (ork.)".padStart(19));
for (const k of [1, 5, 20, 100]) {
  const bekleme = BEKLEME * k;
  const islev = (IS + bekleme) * SURE_UCRET;               // islev bekleme boyunca da ayakta
  const ork = IS * SURE_UCRET + GECIS * GECIS_UCRET;       // bekleme ucretsiz, gecis ucretli
  console.log(String(k).padEnd(17) + islev.toFixed(0).padStart(14) + ork.toFixed(0).padStart(15) +
    String(IS + bekleme).padStart(20) + String(IS).padStart(19));
}
console.log(`akis: ${N}, is: ${IS} birim, bekleme (carpan 1): ${BEKLEME} birim, gecis: ${GECIS}`);
node akis-ucret.mjs
bekleme carpani    islev icinde  orkestratorde  kilitlenen (islev)  kilitlenen (ork.)
1                          2967           2965                2967               2685
5                          4095           2965                4095               2685
20                         8325           2965                8325               2685
100                       30885           2965               30885               2685
akis: 200, is: 2685 birim, bekleme (carpan 1): 282 birim, gecis: 1119

İlk satır dürüst bir sonuçtur: bekleme kısayken iki düzenin ücreti neredeyse aynıdır — 2.967’ye karşı 2.965. Orkestratörün geçiş başına aldığı 1.119 × 0,25 = 280 birim, işlevin bekleme boyunca ödediği 282 birimi tam olarak karşılıyor. Adım başına ücretlendirme bedavaya gelmez; adım sayısı arttıkça geçiş ücreti de artar ve çok adımlı, hızlı biten akışlarda orkestratör pahalı kalabilir.

Bu ücret biçiminin bir yan etkisi, akışın tanecikliğini fiyatlandırmasıdır. Beş adımın her biri üçe bölünse — her adım kendi doğrulaması, kendi işi ve kendi yazması olarak ayrılsa — iş süresi değişmez ama geçiş sayısı 1.119’dan üç katına çıkar ve geçiş ücreti 280 birimden 840 birime yükselir. Adım sınırlarını nereye koyduğu, orkestratörde çalışan bir akışın maliyetini doğrudan belirler. Ters yönde de aynı şey geçerlidir: iki adımı tek adımda birleştirmek geçiş ücretini düşürür, ama birleşen adımın yeniden denemesi artık ikisini birden koşturur ve başarısızlık noktası kabalaşır.

Fark bekleme uzadıkça açılır. Çarpan 100’de — onay bekleyen, dış servisin yanıtını bekleyen ya da ertesi güne kadar duran bir akışta — işlev içindeki düzen 30.885 birime çıkarken orkestratör 2.965’te kalır: 10,4 kat. Kesişme noktası ölçümden okunabilir; bekleme, geçiş ücretinin toplamını aştığı anda orkestratör ucuzlar.

Son iki sütun daha sert bir kısıtı gösteriyor. Kilitlenen süre, eşzamanlılık havuzundan tutulan yerdir. İşlev içinde kurulan akış bekleme boyunca da bir yuva işgal eder; çarpan 100’de 30.885 birimlik yuva-süresi kilitlenir. Orkestratörde bu sayı 2.685’te sabit kalır, çünkü bekleme sırasında ayakta hiçbir işlev yoktur. Eşzamanlılık sınırı olan bir ortamda bu fark ücretten önce kapasiteye çarpar: bekleyen akışlar, yeni gelen okumaların işlenmesini engeller.

Görünürlük, Yeniden Başlatılabilirlik, Sınır

Ücret ve kapasite dışında üç fark daha var ve üçü de ölçümdeki sayılardan okunur.

Görünürlük. Orkestratör her geçişi kaydettiği için 1.119 geçişin tamamı sorgulanabilir bir kayıttır: hangi akış hangi adımda, kaçıncı denemede, ne kadar bekledi. Aynı akış işlev içinde kurulduğunda bu bilgi yalnız günlük satırlarında bulunur ve akış bazında birleştirilmesi ayrı bir iş olur. Devredilen karar burada bir kazanç olarak geri döner.

Yeniden başlatılabilirlik. Telafiye giden 12 akış, orkestratörde başarısız adımdan itibaren yeniden başlatılabilir; ilk üç adımın sonucu kayıtta durur ve tekrar koşmaz. İşlev içindeki düzende yeniden başlatma baştan başlamaktır — 12 akış için üç adım daha, yani 12 × 7 = 84 birim fazladan iş. Kalıcı hatanın nedeni giderildikten sonra bu fark doğrudan sayılır.

Sınır. En uzun tek akış 31 birim sürdü. Bu sayı, işlev içindeki düzenin can alıcı kısıtıdır: akışın duvar süresi işlev çalıştırma ortamının süre sınırını aşamaz. 31 birim makul bir sınırın altında kalır, ama duvar süresi bekleme çarpanıyla birlikte büyür; onay bekleyen ya da ertesi güne kalan bir akış hiçbir işlev süre sınırına sığmaz. Orkestratörde böyle bir sınır yoktur, çünkü bekleme sırasında çalışan bir şey yoktur.

Bunun karşılığında orkestratörün kendi sınırları gelir ve bunlar süre değil sayı cinsindendir: bir akışın alabileceği azami adım sayısı, tutabileceği kayıt boyutu, saklanan geçmişin ömrü. Ölçümdeki akış beş adımlı ve akış başına ortalama 5,6 geçişli olduğu için hiçbir sınıra yaklaşmıyor; ama adım sayısı akışın veri büyüklüğüne bağlıysa — örneğin her sayaç için bir adım açan bir toplu akış — sınır tasarımı doğrudan imkânsız kılar. O durumda tek yol akışı sabit adımlı bir dış döngüye çevirmek, yani her yinelemede yeni bir akış başlatmaktır; bedeli, akış sayısının ve dolayısıyla geçiş ücretinin veriyle birlikte büyümesidir.

Kısıtın etrafından dolaşmanın yolu akışı ikiye bölmektir: kısa ve sıkı adımlar işlev içinde, bekleme içeren geçişler orkestratörde. Bedeli, akışın iki yerde birden tanımlı olmasıdır — görünürlük yeniden bölünür ve hangi adımın nerede koştuğu ayrı bir bilgi haline gelir.

Özet

  • Akışın durumunu tutma sorumluluğu orkestratöre devredilir; karşılığında adımlar arasında geçen her veri orkestratörün kaydından geçer ve bir boyut sınırına tabi olur.
  • 200 akış 1.107 adım denemesi üretti; en yüklü adım 234 deneme ve 46 hatayla fatura yazımıdır, bu hataların 36’sı kalıcı çatışan 12 akıştan gelir.
  • Adım ölçütleri akış sayısına değil o adıma ulaşan akış sayısına bölünmelidir: son adımın denemesi 200’e bölününce 1,10, ulaşan 188 akışa bölününce 1,17 çıkar.
  • Telafiye giden 12 akış 12 telafi adımı koştu; geri alınacak adım sayısı, başarısızlığın akışın kaçıncı adımında olduğuna bağlıdır.
  • Bekleme kısayken iki düzenin ücreti eşittir (2.967’ye karşı 2.965); bekleme yüz katına çıktığında işlev içindeki akış 30.885, orkestratördeki 2.965 birimdir ve kilitlenen eşzamanlılık 30.885’e karşı 2.685 yuva-süresidir.
  • Geçiş başına ücretlendirme akışın tanecikliğini fiyatlandırır: adımlar üçe bölünürse geçiş ücreti 280 birimden 840 birime çıkar, iş süresi ise değişmez.

Sonraki Adım

Bu akışın tamamı bir olayla başladı: okuma geldi, doğrulama tetiklendi, zincir yürüdü. Ölçüm ağının işlerinin bir bölümünde ise böyle bir olay yoktur. Gece toplu faturalama, günlük mutabakat ve haftalık sayaç sağlık taraması hiçbir okumanın gelişine bağlı değildir; onları başlatan tek şey saattir. Saati de bir hizmet tutar. Sonraki ders bu tetiklemeyi ölçer: hizmetin verdiği garantinin türü, aynı dakikada iki kez tetiklenmenin faturaya ne yaptığı ve kaçırılan bir koşumun neden kendiliğinden telafi edilmediği.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat