Ders 10 / 14
Yönetilen Anahtar–Değer Servisi
Bölüm anahtarı seçiminin üç aday üzerinde gerçek anahtar dağılımıyla ölçülmesi: her adayda bölüm başına düşen istek, en dolu bölümün payı ve anahtarla desteklenmeyen erişim örüntüsünün karşılanamayan sorgu olarak sayılması, ayrılmış kapasite ile istek başına modelin aynı yük profilinde karşılaştırılıp sıcak bölümün zorladığı aşırı ayırmanın hesaplanması ve bölüm anahtarını değiştirmenin süre ve kurgu birim olarak bedelinin çıkarılması.
İçindekiler
Önceki iki derste elde kalan kararların hemen hepsi ayardı: yapışkan pencere değiştirilebilir, kopya kapatılabilir. Yönetilen anahtar–değer servisinde tablo değişir. Veri, bölüm anahtarı denen alanın değerine göre yerleşir ve o anahtar seçildikten sonra hangi sorguların karşılanabileceği sabitlenir.
Bölümlemenin mekaniği — aralığa göre mi karmaya göre mi bölündüğü, yeniden dengelemenin taşıdığı veri — İleri Veri Ölçekleme kursunda ölçüldü ve burada tekrarlanmaz. Bu dersin ölçtüğü iki şey bulut bağlamına özgüdür: anahtarın kapasite modeline ne yaptığı ve anahtarı değiştirmenin geri alınamazlığı.
Karşılanamayan Sorgu
Bir sorgu bölüm anahtarını eşitlikle sabitliyorsa istek doğrudan ilgili bölüme gider; sabitlemiyorsa servis nereye bakacağını bilemez ve tek yol tablonun tamamını taramaktır. Bu ölçekte tarama bir sorgu değil bir toplu işlemdir; böyle bir erişim örüntüsü karşılanamayan sorgu sayılır ve aşağıda ayrı bir sütun olarak durur.
İkinci ölçü, karşılanabilen isteklerin bölümlere nasıl dağıldığıdır: on altı bölüme yayılan bir yükte bölüm başına düşen istek ile en dolu bölümün aldığı istek arasındaki fark, sıcak bölümün kendisidir.
Düzenek
YV13 — kurgu ölçüm ağında 40.000 sayaç, 12 bölge ve 26.000 abone vardır; her sayaç 15 dakikada bir okuma yazar (günde 96) ve saklama 90 gündür: 345,6M öğe, öğe başına 180 bayt, 62,2 GB. Bölge payları 27’den 1’e iner; merkez bölge sayaçların yaklaşık dörtte birini taşır. YV14 — erişim karışımı: bir sayacın son 24 saati yüzde 38, tek okuma kaydı yüzde 22, bir bölgenin günlük toplamı yüzde 17, bir abonenin son okumaları yüzde 10, günün eşik aşan okumaları yüzde 8, son bir saatin tüm okumaları yüzde 5. YV15 — servis veriyi 16 bölüme yayar; ayrılmış kapasitede toplam birim bölümlere eşit bölünür ve bir bölüm kendi payını aşamaz. YV16 — istek hızı ortalama 1.200/sn, günlük profil 24 saatlik kurgu bir çarpan dizisidir. YV17 — kurgu fiyat: ayrılmış kapasite 0,12 birim/kapasite-saat, istek başına 0,25 birim/1.000 istek, yazma birimi okumanın 5 katı. YV18 — anahtar değiştirme işi 12.000 öğe/sn koşar. YV14 belirleyicidir; ağırlıklar değişirse karşılanamayan istek payı aynı yönde değişir.
// yv/model.mjs — yonetilen anahtar-deger servisi MODELI: kurgu bolgesel olcum aginin sayac // okumalari uzerinde bolum anahtari adaylari kosturulur. Bolumleme MEKANIGI (aralik mi karma mi, // yeniden dengeleme) M17/K05'te olculdu, burada tekrarlanmaz; olculen sey anahtarin DEGER // DAGILIMI ile erisim orunttusune uygunlugudur. Uretec kendi yazilmistir, tohum gorunurdur. export const BOLGE = [["merkez", 27], ["kuzey", 14], ["liman", 11], ["sanayi", 9], ["bati", 8], ["dogu", 7], ["yayla", 6], ["kiyi", 5], ["ova", 5], ["baraj", 4], ["tepe", 3], ["ada", 1]]; export const SAYAC = 40000, ABONE = 26000, DILIM = 96, SAKLAMA = 90, BOLUM = 16; export const OGE = SAYAC * DILIM * SAKLAMA, OGE_BAYT = 180; export const BUGUN = SAKLAMA - 1; // Sayac kutugu cagirandadir: sayac_id verilince bolgesi, abone verilince sayaclari bilinir. export function kutuk(tohum = 20260803) { let s = tohum % 2147483647; const rast = () => (s = (s * 48271) % 2147483647) / 2147483647; const toplam = BOLGE.reduce((t, [, w]) => t + w, 0); const bolgesi = new Int32Array(SAYAC), abonesi = new Int32Array(SAYAC); const bolgeSayac = new Array(BOLGE.length).fill(0), aboneninSayaclari = new Map(); for (let i = 0; i < SAYAC; i += 1) { let x = rast() * toplam, b = 0; for (let j = 0; j < BOLGE.length; j += 1) { if (x < BOLGE[j][1]) { b = j; break; } x -= BOLGE[j][1]; } bolgesi[i] = b; bolgeSayac[b] += 1; const a = Math.floor(rast() * ABONE); abonesi[i] = a; if (!aboneninSayaclari.has(a)) aboneninSayaclari.set(a, []); aboneninSayaclari.get(a).push(i); } return { rast, bolgesi, abonesi, bolgeSayac, aboneninSayaclari }; } // Erisim orunttusu, sorguyu kurarken SABITLEYEBILDIGI alanlarla tanimlidir (YV14 sirasiyla); // bolum anahtari o alanlar arasinda degilse sorgu karsilanamaz. export const ERISIM = [38, 17, 22, 8, 10, 5]; export function istekUret(k, adet = 300000) { const agirlik = ERISIM, toplam = agirlik.reduce((a, b) => a + b, 0); const istek = []; for (let i = 0; i < adet; i += 1) { let x = k.rast() * toplam, tur = 0; for (let j = 0; j < agirlik.length; j += 1) { if (x < agirlik[j]) { tur = j; break; } x -= agirlik[j]; } const sayac = Math.floor(k.rast() * SAYAC); const abone = k.abonesi[Math.floor(k.rast() * SAYAC)]; const eski = Math.floor(k.rast() * SAKLAMA); // E2 ve E3 gecmise de bakar const gun = tur === 0 ? BUGUN // E1 "son 24 saat" hep bugundur : tur === 3 ? (k.rast() < 0.7 ? BUGUN : BUGUN - Math.floor(k.rast() * 7)) : eski; istek.push({ tur, sayac, bolge: k.bolgesi[sayac], abone, gun }); } return istek; } // Istek hangi bolum anahtari DEGERLERINE dokunuyor; null = anahtar sabitlenemiyor, yani // KARSILANAMAYAN sorgu (tum tablo taranir). export function anahtarlar(q, aday, k) { const sayaclar = () => k.aboneninSayaclari.get(q.abone) ?? [q.sayac]; if (aday === "bolge") { if (q.tur === 3 || q.tur === 5) return null; if (q.tur === 4) return [...new Set(sayaclar().map((i) => k.bolgesi[i]))].map((b) => "b" + b); return ["b" + q.bolge]; } if (aday === "gun") { if (q.tur === 0) return ["g" + q.gun, "g" + Math.max(0, q.gun - 1)]; return ["g" + (q.tur === 4 || q.tur === 5 ? BUGUN : q.gun)]; } if (q.tur === 1 || q.tur === 3 || q.tur === 5) return null; // sayac_id sabitlenemiyor return q.tur === 4 ? sayaclar().map((i) => "s" + i) : ["s" + q.sayac]; } export const karma = (m) => { let h = 2166136261; for (const c of m) h = Math.imul(h ^ c.charCodeAt(0), 16777619); return (h >>> 0) % BOLUM; };
// yv/olc.mjs — uc bolum anahtari adayi, sicak bolum, karsilanamayan sorgu ve kapasite modeli import { kutuk, istekUret, anahtarlar, karma, ERISIM, BOLGE, SAYAC, ABONE, DILIM, SAKLAMA, BOLUM, OGE, OGE_BAYT } from "./model.mjs"; const s = (x, n) => String(x).padStart(n); const yz = (a, b) => "%" + (100 * a / b).toFixed(2); const k = kutuk(); const istek = istekUret(k); const ADAY = [["bolge | zaman", "bolge", BOLGE.length], ["gun | sayac_id#zaman", "gun", SAKLAMA], ["sayac_id | zaman", "sayac_id", SAYAC]]; console.log(`${SAYAC} sayac, ${BOLGE.length} bolge, ${ABONE} abone, ${DILIM} okuma/gun, ` + `${SAKLAMA} gun saklama -> ${(OGE / 1e6).toFixed(1)}M oge, ${(OGE * OGE_BAYT / 1e9).toFixed(1)} GB.`); console.log(`${istek.length} istek uzerinde olculdu. Tohum 20260803.\n`); const sonuc = new Map(); console.log("bolum anahtari | farkli deger | karsilanamayan orunttu | karsilanamayan istek | bolum basina istek (ort / en dolu) | sicak bolum"); console.log("---------------------|--------------|------------------------|----------------------|-----------------------------------|------------"); for (const [ad, aday, farkli] of ADAY) { const yuk = new Array(BOLUM).fill(0); let bos = 0; const orunttu = new Set(); for (const q of istek) { const a = anahtarlar(q, aday, k); if (a === null) { bos += 1; orunttu.add(q.tur); continue; } for (const deger of a) yuk[karma(deger)] += 1; // her deger ayri bir bolum istegidir } const toplam = yuk.reduce((a, b) => a + b, 0), enDolu = Math.max(...yuk); sonuc.set(aday, { sicak: enDolu / toplam, bos }); console.log(`${ad.padEnd(20)} | ${s(farkli, 12)} | ${s(orunttu.size + " / " + ERISIM.length, 22)} | ` + `${s(bos + " (" + yz(bos, istek.length) + ")", 20)} | ` + `${s(Math.round(toplam / BOLUM) + " / " + enDolu, 33)} | ${s(yz(enDolu, toplam), 11)}`); } console.log(`ideal sicak bolum payi ${BOLUM} bolum icin %${(100 / BOLUM).toFixed(2)}; ` + `bolum basina istek karsilanabilen isteklerin dokundugu bolum sayisi uzerinden sayildi.`); // Kapasite modeli. Ayrilmis kapasitede toplam birim BOLUM parcaya esit bolunur; bir bolum kendi // payini asamaz, dolayisiyla sicak bolum toplam ayirmayi yukari zorlar. const TABAN = 1200, FIYAT_AYRILMIS = 0.12, FIYAT_ISTEK = 0.25; const PROFIL = [0.22, 0.18, 0.16, 0.16, 0.20, 0.35, 0.70, 1.20, 1.75, 2.10, 2.20, 2.05, 1.80, 1.70, 1.80, 2.00, 2.30, 2.55, 2.45, 1.90, 1.30, 0.85, 0.50, 0.32]; const ort = PROFIL.reduce((a, b) => a + b, 0) / 24; const hiz = PROFIL.map((p) => TABAN * p / ort); const gunlukIstek = hiz.reduce((a, b) => a + b, 0) * 3600; const tepe = Math.max(...hiz); console.log(`\nyuk profili: ortalama ${TABAN} istek/sn, tepe ${tepe.toFixed(0)} istek/sn ` + `(${(tepe / TABAN).toFixed(2)} kat), gunluk ${(gunlukIstek / 1e6).toFixed(1)}M istek.`); console.log(`kurgu fiyat: ayrilmis kapasite ${FIYAT_AYRILMIS} birim/kapasite-saat, istek basina ` + `${FIYAT_ISTEK} birim/1000 istek.`); console.log("bolum anahtari | asiri ayirma | ayrilmis (birim/gun) | istek basina | tepeye ayirmada kisilan istek"); console.log("---------------------|--------------|----------------------|--------------|------------------------------"); for (const [ad, aday] of ADAY) { const h = sonuc.get(aday).sicak; const ayrilmis = BOLUM * h * tepe * 24 * FIYAT_AYRILMIS; // kisilmasiz ayirma = BOLUM * h * tepe const tavan = tepe / BOLUM; // yalniz toplami karsilayan ayirma: C = tepe const kisilan = hiz.reduce((t, r) => t + Math.max(0, h * r - tavan) * 3600, 0); console.log(`${ad.padEnd(20)} | ${s((BOLUM * h).toFixed(2) + " kat", 12)} | ${s(ayrilmis.toFixed(0), 20)} | ` + `${s((gunlukIstek / 1000 * FIYAT_ISTEK).toFixed(0), 12)} | ${s((kisilan / 1e6).toFixed(1) + "M", 29)}`); } // Geri alinamayan kalem: bolum anahtarini degistirmek veriyi yeniden yazmaktir. const AKTARMA_HIZ = 12000, YAZMA_KAT = 5; const esdeger = OGE * (1 + YAZMA_KAT), sure = OGE / AKTARMA_HIZ / 3600; const bedel = esdeger / 1000 * FIYAT_ISTEK, gunluk = gunlukIstek / 1000 * FIYAT_ISTEK; const cikis = OGE * OGE_BAYT / 1e9; console.log(`\nanahtari degistirmek: ${(OGE / 1e6).toFixed(1)}M oge okunup yeni anahtarla yeniden ` + `yazilir (yazma birimi okumanin ${YAZMA_KAT} kati) -> esdeger istek ${(esdeger / 1e9).toFixed(2)}G.`); console.log(`bedel ${(bedel / 1000).toFixed(1)} bin kurgu birim = gunluk isletimin ` + `(${gunluk.toFixed(0)} birim) ${(bedel / gunluk).toFixed(0)} kati; sure ${sure.toFixed(1)} sa ` + `(${AKTARMA_HIZ} oge/sn) ve o sure boyunca cift yazma penceresi.`); console.log(`servisten cikis daha ucuz: ${cikis.toFixed(1)} GB disa aktarim, internet uzerinden ` + `9 birim/GB = ${(cikis * 9).toFixed(0)} kurgu birim. Farkli deger sayisi (bolge icin ` + `${BOLGE.length}) bolum sayisinin kosumdan bagimsiz ust siniridir.`);
40000 sayac, 12 bolge, 26000 abone, 96 okuma/gun, 90 gun saklama -> 345.6M oge, 62.2 GB. 300000 istek uzerinde olculdu. Tohum 20260803. bolum anahtari | farkli deger | karsilanamayan orunttu | karsilanamayan istek | bolum basina istek (ort / en dolu) | sicak bolum ---------------------|--------------|------------------------|----------------------|-----------------------------------|------------ bolge | zaman | 12 | 2 / 6 | 39168 (%13.06) | 18545 / 78103 | %26.32 gun | sayac_id#zaman | 90 | 0 / 6 | 0 (%0.00) | 25888 / 184840 | %44.62 sayac_id | zaman | 40000 | 3 / 6 | 89856 (%29.95) | 16010 / 16312 | %6.37 ideal sicak bolum payi 16 bolum icin %6.25; bolum basina istek karsilanabilen isteklerin dokundugu bolum sayisi uzerinden sayildi. yuk profili: ortalama 1200 istek/sn, tepe 2389 istek/sn (1.99 kat), gunluk 103.7M istek. kurgu fiyat: ayrilmis kapasite 0.12 birim/kapasite-saat, istek basina 0.25 birim/1000 istek. bolum anahtari | asiri ayirma | ayrilmis (birim/gun) | istek basina | tepeye ayirmada kisilan istek ---------------------|--------------|----------------------|--------------|------------------------------ bolge | zaman | 4.21 kat | 28978 | 25920 | 16.8M gun | sayac_id#zaman | 7.14 kat | 49127 | 25920 | 34.7M sayac_id | zaman | 1.02 kat | 7010 | 25920 | 0.0M anahtari degistirmek: 345.6M oge okunup yeni anahtarla yeniden yazilir (yazma birimi okumanin 5 kati) -> esdeger istek 2.07G. bedel 518.4 bin kurgu birim = gunluk isletimin (25920 birim) 20 kati; sure 8.0 sa (12000 oge/sn) ve o sure boyunca cift yazma penceresi. servisten cikis daha ucuz: 62.2 GB disa aktarim, internet uzerinden 9 birim/GB = 560 kurgu birim. Farkli deger sayisi (bolge icin 12) bolum sayisinin kosumdan bagimsiz ust siniridir.
Üç Aday, Üç Farklı Başarısızlık
Hiçbir aday üstün çıkmıyor; her biri başka bir sütunda batıyor.
bolge işletme düzenine uyuyor ve sıcak bölüm üretiyor. Bölüm başına ortalama 18.545 istek
düşerken en dolu bölüm 78.103 alıyor: yüzde 26,32, ideal olan yüzde 6,25’in dört katı. Sebep, on
iki farklı değerden birinin sayaçların dörtte birini taşımasıdır; bölüm eklemek bunu düzeltmez,
çünkü bir anahtar değeri bölünemez.
gun her sorguyu karşılıyor ve en kötü sıcak bölümü üretiyor. Karşılanamayan örüntü sıfır —
tabloda tek sıfır bu. Karşılığında bugünün bölümü 184.840 istek alıyor, ortalamanın yedi katı,
isteklerin yüzde 44,62’si: artan bir anahtarda yeni yazma ve okumaların çoğu tek değere yığılır.
sayac_id kusursuz dengeleniyor ve isteklerin üçte birini karşılayamıyor. Ortalama 16.010,
en dolu bölüm 16.312 — sıcak bölüm yüzde 6,37, ideale yüzde 2 uzaklıkta. Buna karşılık altı
örüntünün üçü, bölge toplamı, eşik taraması ve son bir saatin okumaları, anahtarı hiç
sabitlemiyor: isteklerin yüzde 29,95’i, 89.856 istek. Bunlar yavaş çalışmıyor; hiç çalışmıyor.
Sıcak Bölüm Faturaya Kapasite Modelinden Geçer
İkinci tablo sıcak bölümü paraya çeviriyor. Ayrılan toplam birim bölümlere eşit bölünür (YV15) ve
bir bölüm kendi payını aşamaz; sıcak bölümün payı h ise kısılmamak için ayrılması gereken kapasite
16 × h × tepe’dir. İlk sütun bu katsayıyı veriyor: sayac_id için 1,02, bolge için 4,21, gun
için 7,14 kat. Sıcak bölümü olan bir anahtarda ayrılan kapasitenin altıda beşi hiç kullanılmaz;
kapasitenin karşılığı işlem değil, dengesizliktir.
Gündelik bedel bunun sonucudur. sayac_id ile ayrılmış kapasite 7.010 kurgu birim, istek başına
model 25.920 — ayrılmış model 3,7 kat ucuz. bolge ile ayrılmış 28.978’e çıkıp istek başına
modelin üstüne geçiyor, gun ile 49.127 oluyor. Hangi kapasite modelinin ucuz olduğunu belirleyen
şey yük değil, bölüm anahtarıdır. İstek başına model dengesizliğe duyarsızdır; ayrılmış model onu
katsayısıyla ücretlendirir.
Son sütun ayırmanın kısıldığı durumu gösteriyor: yalnız toplam tepeyi karşılayacak kadar (2.389
birim) ayrıldığında sayac_id hiç kısılmıyor, bolge günde 16,8M, gun 34,7M isteği kısıyor.
Toplam kapasite yeterlidir; kısılan tek bölümdür.
Anahtarı Değiştirmenin Bedeli
Buraya kadar ölçülen her şey bir seçim gibi görünüyor; son blok neden öyle olmadığını sayıyor. Bölüm anahtarını değiştirmek bir ayar değişikliği değildir: 345,6M öğenin tamamı okunur ve yeni anahtarla yeniden yazılır. Yazma birimi okumanın beş katı olduğu için eşdeğer istek 2,07 milyar, kurgu bedeli 518,4 bin birim — günlük işletim bedelinin 20 katı. Süre 8 saat ve o süre boyunca uygulama iki tabloya birden yazar, çünkü aktarma sürerken gelen yazmaların da bir yere düşmesi gerekir. İlişkisel taraftaki ana sürüm yükseltmesi de tek yönlüydü ama veri yerinde kalıyordu; burada geri dönüş verinin kendisini yeniden yazmaktır. Servisten büsbütün çıkmak daha ucuzdur: 62,2 GB dışa aktarım ve 560 kurgu birim. Anahtarı değiştirmek, servisi terk etmekten 900 kat pahalıya geliyor; bağlayıcı olan sağlayıcı değil, şemadır.
Özet
bolgeanahtarında sıcak bölüm ideal payın dört katıdır (%26,32) ve on iki farklı değer bölüm sayısının üst sınırını çizer; bölüm eklemek dengeyi düzeltmez.gunaltı erişim örüntüsünün altısını da karşılıyor ama bugünün bölümü 184.840 istek alıyor (%44,62);sayac_id16.010’a karşı 16.312 ile kusursuz dengeleniyor ama altı örüntünün üçünü, isteklerin %29,95’ini karşılayamıyor.- Sıcak bölüm ayrılmış kapasitede aşırı ayırmaya çevrilir: 1,02 / 4,21 / 7,14 kat. Hangi kapasite modelinin ucuz olduğunu yük değil, bölüm anahtarı belirliyor (7.010’a karşı 25.920 kurgu birim).
- Toplam tepeyi karşılayan bir ayırma bile sıcak anahtarda günde 16,8M ve 34,7M isteği kısar.
- Anahtarı değiştirmek 345,6M öğenin yeniden yazılmasıdır: 8 saat, 518,4 bin kurgu birim ve 8 saatlik çift yazma penceresi — servisten büsbütün çıkmanın 900 katı.
Sonraki Adım
Tablo bir eksik bırakıyor. En iyi dengeyi veren sayac_id anahtarında isteklerin yüzde 29,95’i
karşılanamıyor ve bunu düzeltmenin yolu anahtarı değiştirmek değil — o kapı 518,4 bin kurgu birimle
kapandı. Yönetilen anahtar–değer servisleri bu boşluk için ikincil dizin sunar: aynı veriyi
başka bir anahtara göre ikinci kez yerleştirir. Sonraki ders ikincil dizinin karşılanamayan üç
örüntünün kaçını kurtardığını ve karşılığında ne aldığını sayar — ek yazma, ek saklama, geri kalma
süresi — ve değişim akışını bir tüketiciyle modelleyip olay sırasını, yeniden işlemeyi ve
akışın saklama süresi dolduğunda kaçırılan pencereyi ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.