Ders 15 / 15
Kapasite Sınırının Bulunması
Kırılma noktasının aranması: yükün basamak basamak artırılıp her basamakta verim, bekleme turu ve başarılı istek sayısının ayrı okunması, verimin artmayı bıraktığı doyum basamağı ile gecikmenin eşiği aştığı diz basamağının aynı yerde çıkmaması, sınırı verimle ilan eden kuralın üç basamağı yanlış geçirmesi ve kuyruğu uzatmanın verimi büyütürken başarılı istek sayısını değiştirmemesi.
İçindekiler
Bu konudaki üç deney aynı biçimde kuruldu: sistemin bir parçası seçildi ve bilerek bozuldu — katalog yavaşladı, bir yığın etiketlendi, bir tablo yedekten düştü. Hiçbiri sistemi kendi sınırına kadar itmedi.
Kırılma noktası testi yükü kademe kademe artırıp sistemin bozulmaya başladığı basamağı arar. Zorluk ölçmekte değil tanımaktadır: verimin artmayı bıraktığı basamak ile gecikmenin dikleştiği basamak aynı yerde olmayabilir. Sistem Tasarımına Giriş kursundaki doyum ve doluluk terimleri bu iki okumanın adıdır; Başarım Karşıt Kalıpları ve İzleme kursundaki kapasite planlaması ise bu testin girdisidir. Soru şudur: hangisi sınır ilan edilecek ve bu kararın iki hata biçimi kaç ediyor.
Yük Merdiveni ve Bekleme Turu
Ödünç ucu, sabit hizmet süreli bir hizmet yuvası kümesi ve sınırlı bir kuyruk olarak kurulur. Süre yerine tur sayılır: bir tur bir hizmet süresidir ve bir isteğin bekleme turu, kabul edildiği andaki kuyruk konumundan çıkar. Aşağıdaki sayılar koşumdan koşuma değişmez.
IO22 — bir hizmet turu 40 ms, hizmet yuvası 4. IO23 — kuyruk uzunluğu 16, basamak başına 5 dalga. İkisi de varsayımdır; dalgadaki istekler ilk hizmet bitmeden varır, bu yüzden kuyruk konumu deterministiktir.
// kapasite.mjs — odunc ucu sabit hizmet suresi, S hizmet yuvasi ve Q uzunlugunda kuyrukla // calisir. Her yanit, istegin kabul anindaki kuyruk konumundan hesaplanan bekleme turunu // tasir; kuyruk dolduysa istek reddedilir (yuk bosaltma). import { createServer } from 'node:http'; export const TUR = 40; // IO22: bir hizmet turu 40 ms export function ucKur({ yuva, kuyruk }) { const olcu = { kabul: 0, red: 0 }; const bekleyen = []; let calisan = 0; const basla = (bitir) => { calisan += 1; setTimeout(() => { calisan -= 1; bitir(); if (bekleyen.length > 0) basla(bekleyen.shift()); }, TUR); }; const sunucu = createServer((istek, yanit) => { const dolu = calisan + bekleyen.length; if (dolu >= yuva + kuyruk) { olcu.red += 1; yanit.writeHead(503, { 'content-type': 'application/json' }); return yanit.end('{"durum":"red"}'); } olcu.kabul += 1; const tur = Math.floor(dolu / yuva); // kacinci turda hizmete girecek const bitir = () => { yanit.writeHead(200, { 'content-type': 'application/json' }); yanit.end(`{"tur":${tur}}`); }; if (calisan < yuva) basla(bitir); else bekleyen.push(bitir); }); sunucu.listen(0, '127.0.0.1'); return { sunucu, olcu }; }
Basamaklar
Kabul edilebilirliğin ölçüsü bu konuda ölçülmüş bir sayıdan gelir: birinci derste ödünç servisinin katalog çağrısına koyduğu zaman aşımı 100 ms’dir; 40 ms’lik turla bu, isteğin en çok bir tur bekleyebileceği anlamına gelir. Daha uzun bekleyen istek işlenir ama çağırana ulaşmaz. IO24 — kabul edilebilir bekleme, zaman aşımının izin verdiği tur sayısıdır; varsayım değil, birinci dersin ölçüsünden türetilmiş bir hesaptır.
// merdiven.mjs — yuk basamak basamak artirilir; her basamakta verim, bekleme turu ve // basarili istek sayilir. Butun sayilar tamsayidir ve kosumdan bagimsizdir; sure basilmaz. import { writeFileSync } from 'node:fs'; import { ucKur, TUR } from './kapasite.mjs'; const YUVA = 4, KUYRUK = 16, DALGA = 5; // IO22, IO23 const BASAMAK = [1, 2, 4, 8, 12, 16, 20, 24, 32]; const ZAMAN_ASIMI = 100; // 01. dersin IO16'si: 100 ms const EN_COK_TUR = Math.ceil(ZAMAN_ASIMI / TUR) - 2; // IO24: bekleme turu ust siniri async function basamakKos(taban, c) { const tur = []; let red = 0; for (let d = 0; d < DALGA; d += 1) { const s = await Promise.all(Array.from({ length: c }, async () => { const y = await fetch(taban); const g = await y.json(); return y.status === 503 ? null : g.tur; })); for (const x of s) { if (x === null) red += 1; else tur.push(x); } } const s = [...tur].sort((a, b) => a - b); return { c, gonderilen: c * DALGA, islenen: tur.length, red, p95: s.length > 0 ? s[Math.ceil(0.95 * s.length) - 1] : 0, basarili: tur.filter((x) => x <= EN_COK_TUR).length }; } async function merdiven(kuyruk, basamaklar) { const { sunucu } = ucKur({ yuva: YUVA, kuyruk }); await new Promise((c) => sunucu.once('listening', c)); const taban = `http://127.0.0.1:${sunucu.address().port}/odunc`; const r = []; for (const c of basamaklar) r.push(await basamakKos(taban, c)); sunucu.closeAllConnections(); await new Promise((c) => sunucu.close(c)); return r; } const p = (x, n) => String(x).padStart(n); const sonuc = await merdiven(KUYRUK, BASAMAK); writeFileSync('merdiven.json', `${JSON.stringify({ EN_COK_TUR, sonuc }, null, 0)}\n`); console.log(`${YUVA} hizmet yuvasi, ${KUYRUK} kuyruk, tur ${TUR} ms, basamak basina ${DALGA} dalga; ` + `zaman asimi ${ZAMAN_ASIMI} ms -> kabul edilebilir bekleme en cok ${EN_COK_TUR} tur`); console.log(`\n${'es zamanli'.padStart(11)}${'gonderilen'.padStart(12)}${'islenen'.padStart(9)}` + `${'reddedilen'.padStart(12)}${'p95 bekleme turu'.padStart(18)}${'basarili'.padStart(10)}`); for (const r of sonuc) console.log(`${p(r.c, 11)}${p(r.gonderilen, 12)}${p(r.islenen, 9)}${p(r.red, 12)}` + `${p(r.p95, 18)}${p(r.basarili, 10)}`); const doyum = sonuc.find((r, i) => i > 0 && r.islenen === sonuc[i - 1].islenen); const diz = sonuc.find((r) => r.p95 > EN_COK_TUR); console.log(`\ndoyum basamagi (verim artmayi biraktigi yer): c=${doyum.c}, verim ${doyum.islenen} istek`); console.log(`diz basamagi (p95 bekleme ${EN_COK_TUR} turu astigi yer): c=${diz.c}`); console.log(`\nayni basamak (c=32), iki kuyruk uzunlugu:`); for (const q of [KUYRUK, 64]) { const [r] = await merdiven(q, [32]); console.log(`kuyruk ${p(q, 2)}: islenen ${p(r.islenen, 3)}, reddedilen ${p(r.red, 2)}, ` + `p95 ${r.p95} tur, basarili ${r.basarili}`); }
4 hizmet yuvasi, 16 kuyruk, tur 40 ms, basamak basina 5 dalga; zaman asimi 100 ms -> kabul edilebilir bekleme en cok 1 tur
es zamanli gonderilen islenen reddedilen p95 bekleme turu basarili
1 5 5 0 0 5
2 10 10 0 0 10
4 20 20 0 0 20
8 40 40 0 1 40
12 60 60 0 2 40
16 80 80 0 3 40
20 100 100 0 4 40
24 120 100 20 4 40
32 160 100 60 4 40
doyum basamagi (verim artmayi biraktigi yer): c=24, verim 100 istek
diz basamagi (p95 bekleme 1 turu astigi yer): c=12
ayni basamak (c=32), iki kuyruk uzunlugu:
kuyruk 16: islenen 100, reddedilen 60, p95 4 tur, basarili 40
kuyruk 64: islenen 160, reddedilen 0, p95 7 tur, basarili 40
Doyum mu, Diz mi
Üç sütun üç ayrı hikâye anlatıyor. İşlenen istek, yani verim, c = 24’e kadar artıyor ve orada duruyor: doyum basamağı burasıdır. p95 bekleme turu çok daha erken kıpırdıyor ve c = 12’de eşiği aşıyor: diz basamağı burasıdır. Arada üç kademe var ve o üç kademede sistem “daha çok istek işliyor” görünürken yanıtlarının çoğu zaman aşımına uğruyor.
Kararı üçüncü sütun veriyor. Başarılı istek sayısı c = 8’den sonra hiç artmıyor: 40’ta sabit. Eklenen her istek yalnız kuyruğa giriyor, bekleyenlerin süresini uzatıyor ve zaman aşımına uğruyor. Gerçek kapasite 40 başarılı istektir ve verimin düzleştiği yerin çok gerisinde bulunmuştur.
Son iki satır bunun neden yalnız verimle görülemeyeceğini söylüyor. Aynı basamak (c = 32) iki kuyruk uzunluğunda koşturuldu: kuyruk 16’da verim 100 ve 60 red, kuyruk 64’te verim 160 ve hiç red — 160/100, yani 1,60 kat. Başarılı istek ikisinde de 40, yani 1,00 kat. Kuyruğu uzatmak doyum basamağını sağa taşır ve kullanıcıya ulaşan hiçbir şeyi değiştirmez; verim ölçütü kırılma noktasını kuyruk ayarıyla saklanabilir kılar.
Sınırı İlan Etme Kuralı
Sınır bir sayı olarak yazılır ve hangi kuralla seçildiği eşiğin kendisidir. Tarama iki kural ailesini karşılaştırıyor: gecikmeye bakan (p95 bekleme ≤ t tur) ve verime bakan (doyumdan önceki son basamak).
IO25 — bir basamak, başarılı istek payı %99’un altına düşmediği sürece kabul edilebilir. Varsayımdır ve kuralların dışında tutulur; kurallar bu payı bilmeden karar verir.
// sinir.mjs — merdiven.json uzerinde sinir ilan etme kurallarinin taranmasi. Gercek kabul // olcutu basarili istek payidir; kurallar bunu bilmeden karar verir. import { readFileSync } from 'node:fs'; const { sonuc } = JSON.parse(readFileSync('merdiven.json', 'utf8')); const PAY = 0.99; // IO25 const gercek = (r) => r.basarili / r.gonderilen >= PAY; const doyum = sonuc.findIndex((r, i) => i > 0 && r.islenen === sonuc[i - 1].islenen); const say = (kabul) => { let gecme = 0, kalma = 0; sonuc.forEach((r, i) => { if (kabul(r, i) && gercek(r) === false) gecme += 1; if (kabul(r, i) === false && gercek(r)) kalma += 1; }); return { gecme, kalma, sinir: sonuc.filter(kabul).at(-1)?.c }; }; const p = (x, n) => String(x).padStart(n); console.log(`gercek kabul olcutu: basarili istek payi >= %${100 * PAY}; ` + `bu olcutu saglayan en yuksek basamak c=${sonuc.filter(gercek).at(-1).c}`); console.log(`\n${'kural'.padEnd(26)}${'ilan edilen sinir'.padStart(18)}` + `${'yanlis gecme'.padStart(14)}${'yanlis kalma'.padStart(14)}`); for (const t of [0, 1, 2, 3, 4]) { const r = say((x) => x.p95 <= t); console.log(`${`gecikme: p95 <= ${t} tur`.padEnd(26)}${p(`c=${r.sinir}`, 18)}${p(r.gecme, 14)}${p(r.kalma, 14)}`); } const v = say((_, i) => i < doyum); console.log(`${'verim: doyumdan onceki'.padEnd(26)}${p(`c=${v.sinir}`, 18)}${p(v.gecme, 14)}${p(v.kalma, 14)}`);
gercek kabul olcutu: basarili istek payi >= %99; bu olcutu saglayan en yuksek basamak c=8 kural ilan edilen sinir yanlis gecme yanlis kalma gecikme: p95 <= 0 tur c=4 0 1 gecikme: p95 <= 1 tur c=8 0 0 gecikme: p95 <= 2 tur c=12 1 0 gecikme: p95 <= 3 tur c=16 2 0 gecikme: p95 <= 4 tur c=32 5 0 verim: doyumdan onceki c=20 3 0
Son satır dersin sonucudur. Verime bakan kural sınırı c = 20 ilan ediyor ve üç basamağı yanlış geçiriyor — 12, 16 ve 20. Üçünde de sistem daha çok istek işliyor, hiçbirinde daha çok kullanıcı yanıt almıyor. Gecikmeye bakan kural eşik bir tura konduğunda sınırı c = 8’de ilan ediyor ve iki hata biçimini de sıfırlıyor.
Taramanın öteki ucu eşiği sıkmanın bedelini veriyor: p95 ≤ 0 tur kuralı hiç bekleme kabul etmiyor ve c = 8’i de eliyor — bir yanlış kalma; o basamakta bekleme zaman aşımının altındadır ve kapasitenin yarısı boşa yazılır. Seçilen eşik p95 bekleme ≤ 1 turdur ve kaynağı birinci dersin ölçtüğü zaman aşımıdır. Kararın sahibi kapasite planıdır: bu sayı yayımı durdurmaz, ölçekleme kararına girdi olur.
Bedel ve Görülmeyen Sınır
Koşumdan bağımsız bedel: dokuz basamak, 595 gönderilen istek, 515 kabul ve 80 red. Asıl bedel bu değildir — sınırı bulmanın tek yolu sınırın ötesine geçmektir. Son beş basamak bilerek zarar veriyor: orada işlenen 400 isteğin 240’ı zaman aşımına uğradı. Üretim benzeri bir ortamda bu, bulaşma kapsamı sınırlanmadan yapılamaz ve önceki dersin durdurma ölçütü gerekir.
Merdivenin göremediği üç sınıf var. Birincisi iş karışımına bağlı sınırdır: merdiven tek bir uca aynı isteği gönderdi. İkincisi birikmeli bozulmadır: beş dalgalık bir basamak, saatlerce süren yükün penceresi değildir. Üçüncüsü çöküş davranışıdır: buradaki uç yük boşaltma yaptığı için verim doyumdan sonra düz kaldı; boşaltması olmayan bir sistemde verim düşer.
Özet
- Kırılma noktası testi yükü basamak basamak artırır; dokuz basamakta verim, p95 bekleme turu ve başarılı istek ayrı okundu, bütün sayılar tam sayıdır.
- Doyum basamağı c = 24, diz basamağı c = 12; arada üç kademe var.
- Başarılı istek c = 8’den sonra 40’ta sabit kaldı: eklenen her istek kuyruğu uzattı ve zaman aşımına uğradı.
- Kuyruk 16’dan 64’e çıkarıldığında verim 1,60 kat büyüdü, başarılı istek 1,00 kat kaldı.
- Seçilen eşik p95 bekleme ≤ 1 turdur, kaynağı birinci dersin 100 ms’lik zaman aşımıdır ve 0 / 0 verir; verime bakan kural üç basamağı yanlış geçirir.
- Bedel 595 gönderilen istektir ve sınırın ötesine geçmeyi gerektirir: son beş basamakta işlenen 400 isteğin 240’ı zaman aşımına uğradı.
Kurs Kapanışı
Bu kursun on beş dersi aynı sistemi üç soruyla sınadı — yük, saldırı ve arıza altında ne olduğu — ve her ders sonucu bir eşiğe bağladı.
| Ders | Sınadığı eşik | Eşiğin kaynağı | Yanlış geçme / yanlış kalma | Bedeli |
|---|---|---|---|---|
| Başarım Testi Türleri | p95 ≤ 20 ms, dört karar penceresinde | IO1 varsayım+hesap: 60 ms bütçenin üçe bölünmesi | 1 / 0; 3 ms’de 0 / 1 | 9 süreç, 55.000 istek, 1,00 milyar satır adımı |
| Test Senaryosu Modelleme | aynı 20 ms, senaryo değişirken | IO1’den devralınır | 1 / 0; 15 ms’de 0 / 1; 100 ms’de 3 / 0 | koşum başına 3.000 istek; tarama adımı 10,7 kat yayılıyor |
| Ölçüt Seçimi | yüzdelik başına en az örnek | IO5 hesap | 20 örnekte 86/200 / 0; 100 örnekte 0 / 0 | 8.494 gecikme değeri, 536.000 çekilen örnek |
| Darboğaz Analizi | katman payı ≥ 0,50 | IO6 varsayım | 1 yanlış atıf / 0 atfedilemez; 0,80’de 0 / 2 | 5 süreç, istek başına 4 saat okuması |
| Karşılaştırmalı Ölçüm Disiplini | aday/taban ±%5, 8 tur | IO9 varsayım; alt sınırı ölçülen yayılım | 0 / 0; %2’de 0 / 141; %20’de 140 / 0 | 30 süreç, 2,4 milyon satır dolum, 20.939 istek |
| Statik Uygulama Güvenlik Testi | bulgu puanı ≥ 40 | IO8 varsayım: kaçan kusur = 5 yanlış alarm | 1 / 2; 50’de 2 / 0 | 75 karşılaştırma, 0 süreç, 7 elle inceleme |
| Dinamik Uygulama Güvenlik Testi | bulgu puanı ≥ 50 | ölçüm: en düşük maliyet 50’de | 1 / 0 | 1 süreç, 8 istek, elle rota tablosu |
| Bağımlılık ve Bileşen Taraması | önem ≥ 80 | ölçüm; ağırlık IO8’den | 1 / 0 | 10 paketin 5’i yükseltildi, her biri gerileme testi |
| Sızma Testinin Yeri | zincir uzunluğu ≤ 4 adım | bütçe (IO12), gereksinim değil | k=3’te 2 / 0; k=4’te 0 / 2; k=5’te 0 / 8 | k=3’te 40, k=4’te 84, k=5’te 169 adım |
| Erişilebilirlik Testi | sıfır otomatik bulgu ve 6 elle ölçüt | ölçüm: otomatik denetim üç kusurla yeşil döner | 3 / 1 | 1 ağaç dolaşımı, 14 öge; ekran başına 6 ölçüt |
| Uyumluluk Testi | kapsanan kullanıcı payı ≥ %90 | yanılgı: pay kusur dağılımını temsil etmez | 3 / 3; profil ve düzen ölçütüyle 0 / 5 | 8 ortam koşumu, elle destek tablosu, çarpımsal artış |
| Hata Enjeksiyonu | düşme oranı ≤ %5 ve enjekte başına bir bozulmuş yanıt | ölçüm: 10/200; ikinci eşik düzeneğin sayacı | 0 / 0; yalnız düşme oranıyla 1 / 0 | 38 satırın 13’ü, 5 karar noktası, 1 açma yolu |
| Kaos Deneyleri | pencere tam yanıt payı ≥ taban − %10 | ölçüm: kontrol koşumu ortalaması %96,00 | 0 / 0; %5’te 0 / 4; %20’de algılama 8. pencereye kayar | kapsam çarpanı 4,00; k = 3’te 44 hasarlı istek |
| Kurtarma Doğrulaması | D1+D2+D3+D4’ün tamamı geçmeli | ölçüm: küme taraması | 0 / 0; yalnız D1 ile 2 / 0; D5 ile 0 / 1 | geri yükleme 10,00 kat büyür, doğrulama 7 sorguda sabit |
| Kapasite Sınırının Bulunması | p95 bekleme ≤ 1 tur | ölçüm: birinci dersin 100 ms zaman aşımı | 0 / 0; verim ölçütüyle 3 / 0 | 595 istek, 9 basamak, 240 zaman aşımı |
Üçüncü sütun bu kursun kuralıdır: kaynaksız eşik karar taşımaz. Dördüncü sütun kuralın öteki yarısıdır. İşlevsel testte sonuç bir “geçti/kaldı”dır, çünkü beklenen değer bellidir. İşlevsel olmayan testte sonuç bir dağılımdır ve “başarılı” demek bir eşik seçmektir; o eşik ancak iki hata biçimiyle savunulabilir — kaç gerçek kusuru geçirdiği ve kaç sağlam koşumu kırmızıya döndürdüğü. Tabloda ikisini birden sıfırlayan satırların hiçbiri bunu eşiği sıkarak yapmadı; hepsi ölçtüğü niceliği değiştirdi.
Dört kurs boyunca sınamanın kendisi ölçüldü: hangi test hangi kusur sınıfını yakalıyor, hangisini kaçırıyor, karşılığında ne ödüyor. Ama bir soru hiç sorulmadı — hangi test ne zaman koşacak. Buradaki bazı testler her değişiklikte koşacak kadar ucuz, bazıları sürüm başına bir kez koşacak kadar pahalı, biri üretim benzeri bir ortam istiyor. Sınırlı zamanın bu testler arasında nasıl paylaştırılacağı ve kırmızı bir sonucun ekipte nasıl bir karara dönüşeceği hiçbir derste ele alınmadı. Test Süreci ve Otomasyon Altyapısı kursu bu soruyla başlar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.