İçeriğe geç
academia.sh

Ders 09 / 10

Eski Sistemlerle Çalışma

Kaynak koduna erişilemeyen bir kayıt sisteminin sarmalanması ve sahipliğinin aşamalı devri: sistemin yüzeyinin koddan değil 60.000 çağrılık bir izden okunması, arayüzü tam kapatan bir sarmalayıcının çağrıların yüzde 71,8'ini kapatıp yedi çağrı çiftini ve dört sahibi dışarıda bırakması, sahiplik devrinde koordinasyon adımının 24'ten 13'e inmesi ve birlikte yazılan pencerenin en yavaş sahibin sürüm turundan kısalmaması.

İçindekiler

Önceki dersin bütün ölçümleri kaynak sistemlerin okunabildiğini varsayıyordu: alanları biliniyordu, şemaları değiştiğinde bu bir hata iletisiyle görünüyordu. Bölgesel kütüphane ağının kurgu modelinde bu varsayımı karşılamayan bir sistem var. Ödünç geçmişini yıllardır tutan kayıt sistemi çalışıyor, ağın en eski kayıtları onda duruyor, ama kaynak koduna kimse erişemiyor: ne bir alan eklenebiliyor, ne bir davranış değiştirilebiliyor, ne de içeride ne olduğu sorulabiliyor.

Bu ders geçişin yol yol nasıl taşındığını ölçmez. Sorusu daha önce gelir: değiştirilemeyen bir sistemin çevresine ne kurulabilir, o şeyin kapatamadığı ne kalır ve sistemin tuttuğu veri başka bir sahibe geçerken iki taraf ne kadar süre birlikte yazar. Ağ, sahipleri ve bütçeleri ayrı olan bir kurgudur.

Erişilemeyen Sistemin Yüzeyi Trafikten Okunur

Bir sistemin çağrı yüzeyi genelde kodundan çıkarılır. Burada kod yok, dolayısıyla ölçü de başka yerden gelmek zorunda: sisteme gelen çağrılar izlenir ve yüzey bu izden sayılır. Yüzeyin birimi tek bir işlem adı değil, (çağıran, işlem) çiftidir; aynı işlemi çağıran iki sistem iki ayrı bağdır, çünkü ikisinin sahibi ayrıdır.

TM15: çağıran sistemler, sahipleri, yolları ve çağrı payları kurgudur. TM16: eski sistemin yüzeyi koddan okunamaz; ölçü, doksan günde gözlenmiş 60.000 çağrılık izdir. TM17: sarmalayıcı yalnız çağrı arayüzündeki işlemi kapatabilir; veritabanına doğrudan giren iş ile dosya diziniyle gelen aktarım sarmalanamaz.

// eski/model.mjs — kaynak koduna erisilemeyen kayit sisteminin kurgu modeli. Sistemin yuzeyi
// koddan degil trafikten olculur: cagri izi gercekten uretilir ve sonraki bloklar onu tarar.
export const TOHUM = 4127, GUN = 90, OLAY = 60_000, BASLA = 30;
// Her sahibin kendi surum turu vardir (gun) ve bir turda tek bir yazani devreder (TM18).
export const TUR = { sarmal: 7, odunc: 7, sube: 14, ucret: 14, uyelik: 21, veri: 30, yonetim: 30 };

// Cagiran sistemler: sahibi, eski sisteme ulastigi yol ve kullandigi islemler. "arayuz" yolu
// sarmalanabilir; "veritabani" ve "dosya" yollari sarmalayicinin disinda kalir.
export const CAGIRANLAR = {
  "sube-ucu": { sahip: "sube", yol: "arayuz", pay: 34, islem: ["odunc-ac", "iade-al", "gecmis-oku"] },
  "odunc-servisi": { sahip: "odunc", yol: "arayuz", pay: 30, islem: ["odunc-ac", "iade-al", "uzat", "ceza-yaz"] },
  "uyelik": { sahip: "uyelik", yol: "arayuz", pay: 8, islem: ["uye-esle", "gecmis-oku"] },
  "gece-isi": { sahip: "veri", yol: "veritabani", pay: 12, islem: ["toplu-kapat", "arsivle"] },
  "ucret-hesabi": { sahip: "ucret", yol: "veritabani", pay: 9, islem: ["ceza-yaz", "gecmis-oku"] },
  "rapor-araci": { sahip: "yonetim", yol: "veritabani", pay: 5, islem: ["gecmis-oku"] },
  "sube-aktarim": { sahip: "sube", yol: "dosya", pay: 2, islem: ["toplu-kapat", "arsivle"] },
};

// Her islem bir veri varligina dokunur ve ya okur ya yazar.
export const ISLEM = {
  "odunc-ac": ["odunc", "yaz"], "iade-al": ["odunc", "yaz"], uzat: ["odunc", "yaz"],
  "toplu-kapat": ["odunc", "yaz"], "ceza-yaz": ["ceza", "yaz"], "uye-esle": ["uye-bag", "yaz"],
  arsivle: ["gecmis", "yaz"], "gecmis-oku": ["gecmis", "oku"],
};
export const VARLIKLAR = ["odunc", "ceza", "uye-bag", "gecmis"];

// Cagri izi: her olay bir cagiran, bir islem ve bir gun tasir.
export function izUret(t = TOHUM) {
  let s = t;
  const r = () => (s = (s * 48271) % 2147483647) / 2147483647;
  const adlar = Object.keys(CAGIRANLAR);
  const toplam = adlar.reduce((a, k) => a + CAGIRANLAR[k].pay, 0);
  const iz = [];
  for (let i = 0; i < OLAY; i += 1) {
    let p = r() * toplam, cagiran = adlar[0];
    for (const k of adlar) { p -= CAGIRANLAR[k].pay; if (p <= 0) { cagiran = k; break; } }
    const islem = CAGIRANLAR[cagiran].islem[Math.floor(r() * CAGIRANLAR[cagiran].islem.length)];
    const [varlik, yon] = ISLEM[islem];
    iz.push({ cagiran, islem, varlik, yon, yol: CAGIRANLAR[cagiran].yol, gun: Math.floor(r() * GUN) });
  }
  return iz;
}

// Sarmalayici yalnizca arayuz yolundaki islemleri kapatabilir.
export const kapali = (e, kapsam) => e.yol === "arayuz" && kapsam.includes(e.islem);
export const KAPSAM = {
  yok: [],
  dar: ["odunc-ac", "iade-al"],
  "arayuz-tam": ["odunc-ac", "iade-al", "uzat", "ceza-yaz", "uye-esle", "gecmis-oku"],
};

Sarmalayıcının Kapattığı ve Kapatamadığı

Sarmalayıcı, eski sistemin önüne konan ve bütün çağrıları kendi üzerinden geçiren bir katmandır. Kapatabileceği şey, çağıranın hangi yoldan geldiğine bağlıdır ve bu yol seçimi çağıranın sahibinin yıllar önce verdiği bir karardır.

// eski/yuzey.mjs — cagri yuzeyi ve sarmalayicinin kapattigi pay, izden sayilir
import { izUret, CAGIRANLAR, KAPSAM, kapali, OLAY } from "./model.mjs";

const iz = izUret();
const yuzey = (d) => new Set(d.map((e) => `${e.cagiran}|${e.islem}`)).size;

console.log(`iz: ${iz.length} cagri, ${Object.keys(CAGIRANLAR).length} cagiran sistem, ` +
  `${yuzey(iz)} ayri (cagiran, islem) cifti\n`);
console.log("yol           cagiran  yuzey  cagri     pay  sahip");
console.log("------------- ------- ------ ------- ------- ------");
for (const yol of ["arayuz", "veritabani", "dosya"]) {
  const d = iz.filter((e) => e.yol === yol);
  const c = Object.entries(CAGIRANLAR).filter(([, v]) => v.yol === yol);
  console.log(`${yol.padEnd(13)} ${String(c.length).padStart(7)} ${String(yuzey(d)).padStart(6)} ` +
    `${String(d.length).padStart(7)} ${`${(d.length / OLAY * 100).toFixed(1)}%`.padStart(7)} ` +
    `${String(new Set(c.map(([, v]) => v.sahip)).size).padStart(6)}`);
}

console.log("\nsarmal kapsami  kapanan yuzey  kapanan cagri      pay  disarida yuzey  disarida cagri  disarida sahip");
console.log("--------------- ------------- --------------- -------- --------------- --------------- ---------------");
for (const [ad, kapsam] of Object.entries(KAPSAM)) {
  const ic = iz.filter((e) => kapali(e, kapsam)), dis = iz.filter((e) => kapali(e, kapsam) === false);
  const disSahip = new Set(dis.map((e) => CAGIRANLAR[e.cagiran].sahip)).size;
  console.log(`${ad.padEnd(15)} ${String(yuzey(ic)).padStart(13)} ${String(ic.length).padStart(15)} ` +
    `${`${(ic.length / OLAY * 100).toFixed(1)}%`.padStart(8)} ${String(yuzey(dis)).padStart(15)} ` +
    `${String(dis.length).padStart(15)} ${String(disSahip).padStart(15)}`);
}
iz: 60000 cagri, 7 cagiran sistem, 16 ayri (cagiran, islem) cifti

yol           cagiran  yuzey  cagri     pay  sahip
------------- ------- ------ ------- ------- ------
arayuz              3      9   43073   71.8%      3
veritabani          3      5   15697   26.2%      3
dosya               1      2    1230    2.1%      1

sarmal kapsami  kapanan yuzey  kapanan cagri      pay  disarida yuzey  disarida cagri  disarida sahip
--------------- ------------- --------------- -------- --------------- --------------- ---------------
yok                         0               0     0.0%              16           60000               6
dar                         4           22516    37.5%              12           37484               6
arayuz-tam                  9           43073    71.8%               7           16927               4

İlk tablo, kaynak koduna erişilemeyen bir sistemin yine de ölçülebildiğini gösteriyor. Yedi çağıran sistem, on altı ayrı (çağıran, işlem) çifti ve üç ayrı yol var. Çağrıların yüzde 71,8’i çağrı arayüzünden geliyor; geri kalanı ya doğrudan veritabanına giriyor ya da bir dosya diziniyle ulaşıyor. Sayı olarak küçük görünen dosya yolu — yüzde 2,1 — iki ayrı yüzey çifti taşıyor ve bunlardan biri veri yazıyor.

İkinci tablo sarmalayıcının sınırını veriyor. Kapsam arayüzdeki bütün işlemleri içerdiğinde bile kapanan pay yüzde 71,8’de duruyor: yedi yüzey çifti ve 16.927 çağrı dışarıda kalıyor, çünkü o çağrılar arayüzü hiç kullanmıyor. Sarmalayıcı bir sistemin kapısını kapatır; duvarındaki delikleri kapatmaz. Kaynak koda erişim olmadığı için o delikleri kapatmanın tek yolu, deliği açanla — yani çağıranın sahibiyle — konuşmaktır.

Dışarıda kalan sahip sütunu ikinci bir şey söylüyor. Dar kapsamlı sarmalayıcı çağrıların yüzde 37,5’ini kapatıyor ama dışarıda kalan sahip sayısını altıdan hiç indirmiyor. Kapatılan çağrı oranı, koordinasyonun azaldığı anlamına gelmez; koordinasyonu azaltan şey bir sahibin bütün yollarının kapanmasıdır. Arayüzü tam kapatan sarmalayıcı altı sahibi dörde indiriyor.

Sahiplik Devri ve Birlikte Yazılan Pencere

Sarmalayıcı bir hazırlıktır; asıl iş, eski sistemin tuttuğu veri varlıklarının sahipliğinin yeni bir sisteme geçmesidir. Bir varlığın sahipliği tek bir anda geçmez: o varlığa yazan her yol ayrı ayrı çevrilir ve hepsi çevrilene kadar iki sistem birden yazar. Bu pencere ölçülebilir.

TM18: her sahibin kendi sürüm turu vardır ve bir turda tek bir yazanı devreder. TM19: dışarıda kalan her yazan için bir bildirim ve bir doğrulama turu gerekir (iki adım); sarmalayıcı ardındaki bütün yazanlar tek bir yönlendirmeyle devredilir (bir adım).

// eski/devir.mjs — veri sahipliginin devri: iki sistemin birlikte yazdigi pencere ve
// sahipler arasi koordinasyon adimi. Her sayi ayni cagri izinden okunur.
import { izUret, CAGIRANLAR, KAPSAM, kapali, VARLIKLAR, BASLA, TUR } from "./model.mjs";

const iz = izUret();

function devir(varlik, kapsam) {
  const yazar = (e) => e.varlik === varlik && e.yon === "yaz";
  const yazanlar = [...new Set(iz.filter(yazar).map((e) => `${e.cagiran}|${e.islem}`))];
  const gecis = new Map(), sayac = {}, dis = [];
  for (const y of yazanlar) {
    const [c, i] = y.split("|");
    if (kapali({ yol: CAGIRANLAR[c].yol, islem: i }, kapsam)) { gecis.set(y, TUR.sarmal); continue; }
    const s = CAGIRANLAR[c].sahip;
    sayac[s] = (sayac[s] ?? 0) + 1;
    gecis.set(y, sayac[s] * TUR[s]);
    dis.push(s);
  }
  const birlikte = iz.filter((e) => yazar(e) && e.gun >= BASLA
    && e.gun < BASLA + gecis.get(`${e.cagiran}|${e.islem}`)).length;
  return { yazan: yazanlar.length, ic: yazanlar.length - dis.length, dis: dis.length,
    sahip: new Set(dis).size, adim: (yazanlar.length > dis.length ? 1 : 0) + 2 * dis.length,
    pencere: Math.max(...gecis.values()), birlikte };
}

console.log("varlik   kapsam       yazan  sarmalda  disarida  sahip  koordinasyon  pencere (gun)  birlikte yazilan");
console.log("-------- ----------- ------ --------- --------- ------ ------------- -------------- -----------------");
const toplam = {};
for (const varlik of VARLIKLAR) for (const ad of ["yok", "arayuz-tam"]) {
  const d = devir(varlik, KAPSAM[ad]);
  toplam[ad] = { adim: (toplam[ad]?.adim ?? 0) + d.adim, birlikte: (toplam[ad]?.birlikte ?? 0) + d.birlikte,
    pencere: Math.max(toplam[ad]?.pencere ?? 0, d.pencere) };
  console.log(`${varlik.padEnd(8)} ${ad.padEnd(11)} ${String(d.yazan).padStart(6)} ${String(d.ic).padStart(9)} ` +
    `${String(d.dis).padStart(9)} ${String(d.sahip).padStart(6)} ${String(d.adim).padStart(13)} ` +
    `${String(d.pencere).padStart(14)} ${String(d.birlikte).padStart(17)}`);
}
for (const [ad, t] of Object.entries(toplam))
  console.log(`toplam (${ad}): ${t.adim} koordinasyon adimi, en uzun pencere ${t.pencere} gun, ` +
    `${t.birlikte} cagri iki sisteme birden yazildi`);
varlik   kapsam       yazan  sarmalda  disarida  sahip  koordinasyon  pencere (gun)  birlikte yazilan
-------- ----------- ------ --------- --------- ------ ------------- -------------- -----------------
odunc    yok              7         0         7      3            14             42              6862
odunc    arayuz-tam       7         5         2      2             5             30              3386
ceza     yok              2         0         2      2             4             14               781
ceza     arayuz-tam       2         1         1      1             3             14               781
uye-bag  yok              1         0         1      1             2             21               556
uye-bag  arayuz-tam       1         1         0      0             1              7               173
gecmis   yok              2         0         2      2             4             30              1307
gecmis   arayuz-tam       2         0         2      2             4             30              1307
toplam (yok): 24 koordinasyon adimi, en uzun pencere 42 gun, 9506 cagri iki sisteme birden yazildi
toplam (arayuz-tam): 13 koordinasyon adimi, en uzun pencere 30 gun, 5647 cagri iki sisteme birden yazildi

Sarmalayıcının kazandırdığı şey tabloda tek bir sütunda toplanmıyor. Koordinasyon adımı 24’ten 13’e, birlikte yazılan çağrı 9.506’dan 5.647’ye iniyor. En uzun pencere 42 günden 30 güne düşüyor — ama otuzun altına inmiyor.

Dört satır dört ayrı sonuç veriyor ve farkı yaratan, varlığa kimin yazdığıdır. Ödünç kayıtlarına yedi yol yazıyor; beşi arayüzden geçtiği için sarmalayıcının ardında tek bir yönlendirmeyle devrediliyor, kalan ikisi kendi sahiplerinin turunu bekliyor: koordinasyon 14 adımdan 5’e, pencere 42 günden 30 güne iniyor. Üye bağında tek yazan var ve o arayüzden geçiyor; sarmalayıcıyla pencere 21 günden 7 güne, birlikte yazılan çağrı 556’dan 173’e düşüyor. Ceza kayıtlarında sarmalayıcı bir adım kazandırıyor ama pencereyi hiç kısaltmıyor, çünkü pencereyi belirleyen dışarıdaki yazan. Geçmiş kayıtlarında iki satır birebir aynı: o varlığa yazan iki yolun ikisi de arayüzün dışında olduğu için sarmalayıcı bu devirde hiçbir şey değiştirmiyor.

Buradan çıkan sınır, bu dersin asıl ölçüsüdür. Pencerenin alt sınırını sarmalayıcı belirlemez; en yavaş sahibin sürüm turu belirler. Gece işini yürüten sahibin turu otuz gündür ve o sahip geçmiş kayıtlarına doğrudan veritabanından yazar. Sarmalayıcı ne kadar geniş olursa olsun bu yolu kapatamaz, dolayısıyla otuz gün ödenecektir. Geçişi hızlandırmak isteyen bir kararın önce bakması gereken yer, sarmalayıcının kapsamı değil, dışarıda kalan yolların sahipleri ve onların turlarıdır.

Bir uyarı da birlikte yazılan çağrı sütununda. Pencere boyunca 5.647 çağrı iki sisteme birden yazılıyor; bu çağrılar iki tarafta da doğru olmak zorunda ve her biri iki yazma işlemi demek. Pencerenin uzunluğu bir takvim sorunu değil, o takvim boyunca çift yazılan kayıt sayısıdır.

Özet

  • Kaynak koduna erişilemeyen sistemin çağrı yüzeyi koddan değil izden ölçülür: 60.000 çağrılık izde 7 çağıran, 16 ayrı (çağıran, işlem) çifti ve üç ayrı yol görünüyor (TM15, TM16).
  • Arayüzü tam kapatan sarmalayıcı çağrıların yüzde 71,8’ini kapatıyor; 7 yüzey çifti ve 16.927 çağrı dışarıda kalıyor, çünkü veritabanına ve dosya dizinine giren yol sarmalanamaz (TM17).
  • Kapatılan çağrı oranı koordinasyonun azaldığını göstermez: dar kapsamlı sarmalayıcı çağrıların yüzde 37,5’ini kapattığı halde dışarıdaki sahip sayısını altıdan indirmiyor. Sahip ancak bütün yolları kapandığında listeden çıkar.
  • Sahipliğin devrinde sarmalayıcı koordinasyon adımını 24’ten 13’e, birlikte yazılan çağrıyı 9.506’dan 5.647’ye indiriyor; üye bağında pencere 21 günden 7 güne iniyor, geçmiş kayıtlarında ise iki durum birebir aynı kalıyor (TM18, TM19).
  • Pencerenin alt sınırını sarmalayıcının kapsamı değil en yavaş sahibin sürüm turu belirler: otuz günlük turu olan sahip veritabanına doğrudan yazdığı için en uzun pencere 42 günden yalnız 30 güne inebiliyor.

Sonraki Adım

Bu ders elde olanla çalıştı: sistem duruyor, değiştirilemiyor, çevresine bir katman kuruluyor ve sahipliği adım adım devrediliyor. Kararın kendisi çoktan verilmişti — o sistem bir zamanlar ya satın alınmıştı ya da içeride yazılmıştı ve bugünkü bütün maliyetler o kararın devamıdır. Kursun son dersi bu kararı ölçmeye çalışır. Bir yetenek için iki seçenek modellenir: satın almak ve geliştirmek. Toplam sahip olma maliyeti kalem kalem toplanır — uyarlama, tümleştirme bağları, sürüm yükseltme, eğitim ve çıkış — ve kazananın zaman ufkuna göre değiştiği gösterilir. Yanına ikinci bir sayı konur: sahibi başkası olan bir yolun kesilmesi, yani bağımlılık riski.

İ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