İçeriğe geç
academia.sh

Ders 15 / 16

Yedekleme Stratejisi

Yedeğin kendisinin ölçülmesi: kapsam boşluğunun kalem kalem sayılması ve yedeklenmeyen kalemin adıyla yazılması, sıklık ile veri kaybı penceresinin ve saklama ile geriye gidilebilen noktanın depolama maliyetiyle birlikte taranması, yedek kopyalarının kaç kimlik tarafından okunabildiğinin sayılması ve şifreleme anahtarının getirdiği yeni tek noktanın gösterilmesi.

İçindekiler

Önceki ders bir varsayımla bitti: yama geri alındığında geri dönülecek bir önceki durum vardır. Aynı varsayım her kurtarma planının altında durur. Kurtarma süresi ve veri kaybı hedefleri Dayanıklılık Kalıpları kursunda ölçüldü; burada girdi olarak alınır. Ölçülen şey yedeğin kendisidir.

Varsayılanın bıraktığı kalem burada da bir boşluktur: kurulum sonrası akla gelen tek yedek veritabanının gecelik dökümüdür. Geri kalanı — yapılandırma, sır, nesne deposu, dış hizmetteki veri — kimsenin karar vermediği bir şekilde plan dışında kalır. Ölçü kapsam boşluğudur: üretimde var olup yedek kümesinde bulunmayan kalem sayısı.

Kapsam Boşluğu Kalem Kalem

  • ST25 — Üretim envanteri kurgudur: on altı kalem; türü, boyutu ve günlük değişimi modelde yazılıdır.

  • ST26 — Dört servisin gerektirdiği kalem kümesi modelde yazılıdır; bir kalem eksikse o servis geri yüklenemez.

  • ST27 — Üç kalemin yedeği alınamaz; gerekçe kalemin türündedir.

  • ST28 — Sıkıştırma oranı 0,42; artımlı yedek günlük değişimin aralık payıdır, her noktanın 0,02 GiB üst verisi vardır.

  • ST29 — Veri kaybı penceresi ortalamada aralığın yarısı, en kötüde aralığın kendisidir.

  • ST30 — Şifreleme bölümü gerçekten koşar; süre ölçülür ama basılmaz, bant denetiminden geçirilir.

// yedek/model.mjs — uretim envanteri MODELIDIR: on alti kalem, dort servis. Gercek yedek alinmaz.
const K = (ad, tur, gib, degisim, alinabilir = true) => ({ ad, tur, gib, degisim, alinabilir });
export const ENVANTER = [
  K("okuma-veritabani", "veritabani", 420, 6.0), K("tarife-veritabani", "veritabani", 4, 0.02),
  K("is-emri-veritabani", "veritabani", 18, 0.6), K("fatura-belge-deposu", "nesne deposu", 260, 1.4),
  K("saha-foto-deposu", "nesne deposu", 610, 3.1), K("servis-yapilandirmasi", "yapilandirma", 0.02, 0.001),
  K("guvenlik-duvari-kurallari", "yapilandirma", 0.001, 0.0002),
  K("ad-bolge-dosyasi", "yapilandirma", 0.0005, 0.0001),
  K("dagitim-yapilandirmasi", "yapilandirma", 0.05, 0.01),
  K("sir-deposu-icerigi", "sir", 0.002, 0.0005), K("sertifika-ozel-anahtarlari", "sir", 0.0004, 0.00005),
  K("gozetim-olcum-serisi", "olcum", 95, 4.2), K("denetim-gunlugu", "gunluk", 140, 2.8),
  K("mesaj-kuyrugu-durumu", "kuyruk", 2.5, 2.5, false),
  K("dis-fatura-hizmeti-verisi", "dis hizmet", 12, 0.3, false),
  K("dis-bildirim-listeleri", "dis hizmet", 0.8, 0.05, false),
];
// Servis ancak gereken kalemlerin hepsi yedekteyse geri yuklenebilir.
export const SERVIS = {
  toplayici: ["okuma-veritabani", "servis-yapilandirmasi", "sir-deposu-icerigi", "dagitim-yapilandirmasi"],
  dogrulayici: ["okuma-veritabani", "servis-yapilandirmasi", "sir-deposu-icerigi", "mesaj-kuyrugu-durumu"],
  faturalama: ["okuma-veritabani", "tarife-veritabani", "fatura-belge-deposu", "servis-yapilandirmasi",
    "sir-deposu-icerigi", "dis-fatura-hizmeti-verisi"],
  "is-emri": ["is-emri-veritabani", "saha-foto-deposu", "servis-yapilandirmasi",
    "sertifika-ozel-anahtarlari", "ad-bolge-dosyasi"],
};
export const PLAN = {                             // hangi turler yedek kumesine giriyor
  varsayilan: ["veritabani"],
  "veri-ve-nesne": ["veritabani", "nesne deposu"],
  "yapilandirma-eklendi": ["veritabani", "nesne deposu", "yapilandirma"],
  "sir-eklendi": ["veritabani", "nesne deposu", "yapilandirma", "sir"],
  tam: ["veritabani", "nesne deposu", "yapilandirma", "sir", "olcum", "gunluk", "kuyruk", "dis hizmet"],
};
export const kapsanan = (p) =>
  ENVANTER.filter((k) => PLAN[p].includes(k.tur) && k.alinabilir);
// yedek/kapsam.mjs — kapsam boslugunu kalem kalem sayar ve geri yuklenebilir servisi olcer
import { ENVANTER, SERVIS, PLAN, kapsanan } from "./model.mjs";

const TOPLAM_GIB = ENVANTER.reduce((a, k) => a + k.gib, 0);
const g = (x, n, d = 2) => x.toFixed(d).padStart(n);
console.log(`${ENVANTER.length} uretim kalemi, ${g(TOPLAM_GIB, 0, 1)} GiB, ${Object.keys(SERVIS).length} servis; ` +
  `${ENVANTER.filter((k) => !k.alinabilir).length} kalem yedegi alinamiyor.`);
console.log("\nplan                 | kapsanan | bosluk | yedeklenen GiB | bayt orani | geri yuklenebilir");
console.log("---------------------|----------|--------|----------------|------------|------------------");
for (const p of Object.keys(PLAN)) {
  const ic = kapsanan(p), ad = new Set(ic.map((k) => k.ad));
  const gib = ic.reduce((a, k) => a + k.gib, 0);
  const servis = Object.entries(SERVIS).filter(([, ger]) => ger.every((x) => ad.has(x)));
  console.log(`${p.padEnd(20)} | ${String(ic.length).padStart(8)} | ` +
    `${String(ENVANTER.length - ic.length).padStart(6)} | ${g(gib, 14, 1)} | ` +
    `%${g(100 * gib / TOPLAM_GIB, 9)} | ${(servis.length + "/" + Object.keys(SERVIS).length).padStart(18)}`);
}

console.log("\nKapsam boslugu kalem kalem (yapilandirma-eklendi planinda disarida kalanlar):");
const icinde = new Set(kapsanan("yapilandirma-eklendi").map((k) => k.ad));
for (const k of ENVANTER.filter((x) => !icinde.has(x.ad)))
  console.log(`${k.ad.padEnd(26)} | ${k.tur.padEnd(11)} | ${g(k.gib, 7, 3)} GiB | ` +
    `${k.alinabilir ? "plan disi" : "ALINAMIYOR"}`);

const engelli = ENVANTER.map((k) => ({ k, e: Object.keys(SERVIS).filter((s) => SERVIS[s].includes(k.ad)) }))
  .filter((x) => x.e.length > 0).sort((a, b) => a.k.gib - b.k.gib).slice(0, 4);
const kucuk = engelli.reduce((a, x) => a + x.k.gib, 0);
console.log(`\nen kucuk dort servis engelleyen kalem: ${engelli.map((x) => x.k.ad).join(", ")}`);
console.log(`toplam ${g(kucuk * 1024, 6)} MiB = uretim baytlarinin %${g(100 * kucuk / TOPLAM_GIB, 6, 4)}'i; ` +
  `birlikte ${new Set(engelli.flatMap((x) => x.e)).size}/${Object.keys(SERVIS).length} servisi engelliyor.`);
16 uretim kalemi, 1562.4 GiB, 4 servis; 3 kalem yedegi alinamiyor.

plan                 | kapsanan | bosluk | yedeklenen GiB | bayt orani | geri yuklenebilir
---------------------|----------|--------|----------------|------------|------------------
varsayilan           |        3 |     13 |          442.0 | %    28.29 |                0/4
veri-ve-nesne        |        5 |     11 |         1312.0 | %    83.97 |                0/4
yapilandirma-eklendi |        9 |      7 |         1312.1 | %    83.98 |                0/4
sir-eklendi          |       11 |      5 |         1312.1 | %    83.98 |                2/4
tam                  |       13 |      3 |         1547.1 | %    99.02 |                2/4

Kapsam boslugu kalem kalem (yapilandirma-eklendi planinda disarida kalanlar):
sir-deposu-icerigi         | sir         |   0.002 GiB | plan disi
sertifika-ozel-anahtarlari | sir         |   0.000 GiB | plan disi
gozetim-olcum-serisi       | olcum       |  95.000 GiB | plan disi
denetim-gunlugu            | gunluk      | 140.000 GiB | plan disi
mesaj-kuyrugu-durumu       | kuyruk      |   2.500 GiB | ALINAMIYOR
dis-fatura-hizmeti-verisi  | dis hizmet  |  12.000 GiB | ALINAMIYOR
dis-bildirim-listeleri     | dis hizmet  |   0.800 GiB | ALINAMIYOR

en kucuk dort servis engelleyen kalem: sertifika-ozel-anahtarlari, ad-bolge-dosyasi, sir-deposu-icerigi, servis-yapilandirmasi
toplam  23.45 MiB = uretim baytlarinin %0.0015'i; birlikte 4/4 servisi engelliyor.

Varsayılan plan on altı kalemin üçünü kapsıyor, kapsam boşluğu 13. Nesne deposu eklendiğinde bayt oranı yüzde 28,29’dan yüzde 83,97’ye fırlıyor ve plan tamamlanmış görünüyor — ama geri yüklenebilir servis hâlâ 0/4. Yapılandırma eklendiğinde bayt oranı 0,01 puan artıyor, servis yine 0/4. Sır eklendiğinde bayt oranı hiç değişmiyor, servis 0’dan 2’ye çıkıyor. Bayt oranı kapsamı ölçmez. Son iki satır nedenini veriyor: en küçük dört engelleyici kalem toplam 23,45 MiB, üretim baytlarının yüzde 0,0015’i, ama dört servisi de engelliyor.

Tam planda bile servis 2/4’te kalıyor: mesaj kuyruğu durumunun tutarlı anlık görüntüsü alınamıyor, dış fatura hizmetindeki veri ile dış bildirim listelerinin dışa aktarım arayüzü yok. Doğrulayıcı birinciye, faturalama ikinciye bağlı; ikisi de geri yüklenemez. Bu kalemler için yedekleme kararı yoktur — karar, kalemi yedeklenebilir bir yere taşımaktır.

Sıklık, Saklama ve Depolama

// yedek/siklik.mjs — siklik, saklama, nokta sayisi ve depolama birlikte taranir (MODELDIR)
import { ENVANTER, kapsanan } from "./model.mjs";

const SIKISTIRMA = 0.42, UST_VERI = 0.02;         // nokta basina ust veri, GiB
const ic = kapsanan("tam");
const TAM = ic.reduce((a, k) => a + k.gib, 0) * SIKISTIRMA;
const GUNLUK = ic.reduce((a, k) => a + k.degisim, 0) * SIKISTIRMA;
const URETIM = ENVANTER.reduce((a, k) => a + k.gib, 0);
const DUZEN = {                                   // tam: gun, art: saat (null = artimli yok)
  "haftalik-tam": { tam: 7, art: null }, "gecelik-tam": { tam: 1, art: null },
  "gecelik+6s": { tam: 1, art: 6 }, "haftalik+1s": { tam: 7, art: 1 },
  "haftalik+5dk": { tam: 7, art: 1 / 12 },
};
const nokta = (d, R) => Math.floor(R / d.tam) + 1 + (d.art ? Math.floor(R * 24 / d.art) : 0);
const depo = (d, R) => (Math.floor(R / d.tam) + 1) * TAM + (d.art ? R * GUNLUK : 0)
  + nokta(d, R) * UST_VERI;
const g = (x, n, d = 2) => x.toFixed(d).padStart(n);

console.log(`yedeklenen ${ic.length} kalem: tam yedek ${g(TAM, 0, 1)} GiB (sikistirma ${SIKISTIRMA}), ` +
  `gunluk degisim ${g(GUNLUK, 0, 2)} GiB, nokta basina ust veri ${UST_VERI} GiB.`);
console.log("\nduzen        | tam yedek | artimli | ort. veri kaybi (dk) | en kotu (dk) | gunluk yazilan GiB");
console.log("-------------|-----------|---------|----------------------|--------------|-------------------");
for (const [ad, d] of Object.entries(DUZEN)) {
  const dk = (d.art ?? d.tam * 24) * 60;
  console.log(`${ad.padEnd(12)} | ${(d.tam + " gun").padStart(9)} | ` +
    `${(d.art ? (d.art < 1 ? d.art * 60 + " dk" : d.art + " saat") : "yok").padStart(7)} | ` +
    `${g(dk / 2, 20, 1)} | ${g(dk, 12, 1)} | ${g(TAM / d.tam + (d.art ? GUNLUK : 0), 18)}`);
}

const SAKLAMA = [7, 30, 90, 365];        // saklama = geriye gidilebilen en eski nokta
console.log("\ndepolanan GiB (saklama gunune gore) ve 30 gunde geri donulebilen nokta:");
console.log(`duzen        |${SAKLAMA.map((R) => (R + " gun").padStart(11)).join(" |")} | 30g nokta`);
console.log("-------------|------------|------------|------------|------------|----------");
for (const [ad, d] of Object.entries(DUZEN))
  console.log(`${ad.padEnd(12)} |${SAKLAMA.map((R) => g(depo(d, R), 11, 1)).join(" |")} | ` +
    `${String(nokta(d, 30)).padStart(9)}`);
console.log(`uretim verisi ${g(URETIM, 0, 1)} GiB; haftalik+1s duzeninde depolanan, saklama 7 gunde ` +
  `${g(depo(DUZEN["haftalik+1s"], 7) / URETIM, 0)} kati, 365 gunde ${g(depo(DUZEN["haftalik+1s"], 365) / URETIM, 0)} kati.`);
yedeklenen 13 kalem: tam yedek 649.8 GiB (sikistirma 0.42), gunluk degisim 7.62 GiB, nokta basina ust veri 0.02 GiB.

duzen        | tam yedek | artimli | ort. veri kaybi (dk) | en kotu (dk) | gunluk yazilan GiB
-------------|-----------|---------|----------------------|--------------|-------------------
haftalik-tam |     7 gun |     yok |               5040.0 |      10080.0 |              92.82
gecelik-tam  |     1 gun |     yok |                720.0 |       1440.0 |             649.77
gecelik+6s   |     1 gun |  6 saat |                180.0 |        360.0 |             657.39
haftalik+1s  |     7 gun |  1 saat |                 30.0 |         60.0 |             100.44
haftalik+5dk |     7 gun |    5 dk |                  2.5 |          5.0 |             100.44

depolanan GiB (saklama gunune gore) ve 30 gunde geri donulebilen nokta:
duzen        |      7 gun |     30 gun |     90 gun |    365 gun | 30g nokta
-------------|------------|------------|------------|------------|----------
haftalik-tam |     1299.6 |     3249.0 |     8447.3 |    34438.9 |         5
gecelik-tam  |     5198.3 |    20143.5 |    59131.0 |   237823.5 |        31
gecelik+6s   |     5252.2 |    20374.4 |    59823.6 |   240632.3 |       151
haftalik+1s  |     1356.2 |     3491.8 |     9175.9 |    37393.7 |       725
haftalik+5dk |     1393.2 |     3650.2 |     9651.1 |    39320.9 |      8645
uretim verisi 1562.4 GiB; haftalik+1s duzeninde depolanan, saklama 7 gunde 0.87 kati, 365 gunde 23.93 kati.

Gecelik tam yedek en yaygın varsayılan alışkanlıktır ve iki ucu da kaybeder: günde 649,77 GiB yazar, otuz günde 20.143,5 GiB depolar, penceresi 720 dakikadır, 31 nokta bırakır. Haftalık tam yedek üstüne saatlik artımlı düzen günde 100,44 GiB yazar, otuz günde 3.491,8 GiB depolar, pencereyi 30 dakikaya indirir ve 725 nokta bırakır — altı kat az yazma, beş kat az depolama, yirmi dört kat küçük pencere.

Sıklığı artırmanın depolamaya etkisi neredeyse yoktur: artımlı aralık beş dakikaya inince otuz günlük depolama 3.491,8 GiB’den 3.650,2 GiB’ye çıkıyor — yüzde 4,5 — ve kayıp penceresi 2,5 dakikaya iner. Artan şey depolanan veri değil, nokta sayısı ve üst veridir. Pahalı olan sıklık değil saklamadır: saklama 7 günden 365 güne çıkınca depolanan 1.356,2 GiB’den 37.393,7 GiB’ye, üretim verisinin 0,87 katından 23,93 katına çıkıyor.

Saklama aynı zamanda geriye gidilebilen en eski noktadır ve sessiz bozulmanın fark edilme süresiyle karşılaştırılmadıkça bir sayı değildir: yedi günlük saklamada sekizinci günde fark edilen bozulma için temiz nokta yoktur, 725 noktanın hepsi bozulmadan sonrasına aittir.

Yedeğin Kendisi Bir Yüzeydir

Kopya yerleşimi de bir modeldir. Tek olayda kaybolan kopya, kopya/bölge oranının yukarı yuvarlanmışıdır; okunabilir yüzey kopya sayısı ile okuyan kimlik sayısının çarpımıdır.

yerleşim kopya bölge okuyan kimlik silebilen şifreli tek olayda kaybolan okunabilir yüzey
varsayılan 1 1 9 9 hayır 1 9
iki-kopya 2 1 9 9 hayır 2 18
ayrı-bölge 3 2 5 5 evet 2 15
daraltılmış 3 2 2 2 evet 2 6
değiştirilemez 4 2 2 0 evet 2 8
// yedek/anahtar.mjs — sifreleme bolumu GERCEKTEN kosar: dogru ve yanlis anahtarla geri donus
// denenir. Sure olculur ama HAM OLCUM BASILMAZ, yalniz bant denetimi yazilir.
import { createCipheriv, createDecipheriv, scryptSync } from "node:crypto";

const TOHUM = 90211, MIB = 24;           // veri kendi uretecimizden, tohum gorunur: kurgudur
let x = TOHUM >>> 0;
const sonraki = () => { x = (Math.imul(x, 1103515245) + 12345) >>> 0; return x; };
const duz = Buffer.allocUnsafe(MIB * 1024 * 1024);
for (let i = 0; i < duz.length; i += 4) duz.writeUInt32LE(sonraki(), i);
const iv = Buffer.allocUnsafe(12);       // baslatma vektoru de ayni uretecten: rastgelelik yok
for (let i = 0; i < 12; i += 4) iv.writeUInt32LE(sonraki(), i);
const tuz = Buffer.from("kurgu-tuz-ornek-gecersiz");   // gercek sir ya da anahtar yazilmaz
const anahtar = scryptSync("kurgu-parola-ornek-gecersiz", tuz, 32);
const baska = scryptSync("kurgu-baska-parola-ornek-gecersiz", tuz, 32);

const t0 = process.hrtime.bigint();
const s = createCipheriv("aes-256-gcm", anahtar, iv);
const kapali = Buffer.concat([s.update(duz), s.final()]), etiket = s.getAuthTag();
const coz = (a) => {                     // yanlis anahtarda butunluk etiketi tutmaz
  try {
    const d = createDecipheriv("aes-256-gcm", a, iv).setAuthTag(etiket);
    return Buffer.concat([d.update(kapali), d.final()]);
  } catch { return null; }
};
const geri = coz(anahtar), yanlis = coz(baska);
const sn = Number(process.hrtime.bigint() - t0) / 1e9;

const [ALT, UST] = [5, 40000];           // MiB/s bandi; olculen deger degil denetim sonucu basilir
const yaz = (e, d) => console.log(`${e.padEnd(44)}: ${d}`);
console.log(`\nkurgu yedek kumesi ${MIB} MiB (tohum ${TOHUM}), sifreli boyut ${kapali.length} bayt`);
yaz("dogru anahtarla girdinin aynisina donuldu", geri && geri.equals(duz) ? "evet" : "hayir");
yaz("baska anahtarla geri donulebildi", yanlis ? "evet" : "hayir");
yaz(`hiz ${ALT}-${UST} MiB/s bandinda`, MIB / sn >= ALT && MIB / sn <= UST ? "evet" : "hayir");
kurgu yedek kumesi 24 MiB (tohum 90211), sifreli boyut 25165824 bayt
dogru anahtarla girdinin aynisina donuldu   : evet
baska anahtarla geri donulebildi            : hayir
hiz 5-40000 MiB/s bandinda                  : evet

Varsayılan yerleşim üretim verisinin tam kopyasını üretimle aynı yerde, aynı dokuz kimliğin okuyabildiği ve şifresiz biçimde tutar: okunabilir yüzey 9, tek olayda kopyanın tamamı gidiyor. İkinci kopya dayanıklılığı artırırken yüzeyi 18’e çıkarıyor — yedek almak, veriyi ikinci kez açığa çıkarmaktır. Erişim daraltıldığında üç kopyayla yüzey 6’ya iniyor: kopya üç kat artarken yüzey üçte birine düşüyor. Değiştirilemez dördüncü kopya silebilen kimliği sıfırlıyor.

Şifrelemenin getirdiği kalem koşumda görünüyor: doğru anahtarla girdinin aynısına dönülüyor, başka bir anahtarla dönülemiyor. Bu, yeni tek noktanın da tanımıdır — anahtar kaybolursa yedek de kaybolur. Anahtar bir sırdır ve sır deposunda durur; sır deposu içeriği ise yedeklenmesi gereken kalemlerden biridir: yedeğin anahtarı yedeğin içinde saklanamaz.

Özet

  • Kapsam boşluğu bayt oranıyla ölçülmez: nesne deposu eklendiğinde bayt oranı yüzde 83,97’ye çıkarken geri yüklenebilir servis 0/4’te kalıyor; sır eklendiğinde bayt oranı hiç değişmeden servis 2/4’e çıkıyor.
  • Dört küçük kalem — sertifika özel anahtarları, ad bölge dosyası, sır deposu içeriği, servis yapılandırması — toplam 23,45 MiB, üretim baytlarının yüzde 0,0015’i, ama dört servisi de engelliyor.
  • Yedeklenemeyen üç kalem adıyla yazılır: anlık kuyruk durumu, dış fatura hizmetindeki veri, dış bildirim listeleri. Tam planda bile servis 2/4’te kalır.
  • Sıklık ucuz, saklama pahalıdır: artımlı aralığı beş dakikaya indirmek otuz günlük depolamayı yüzde 4,5 artırır, saklamayı 365 güne çıkarmak 1.356,2 GiB’den 37.393,7 GiB’ye taşır.
  • Yedeğin kendisi bir yüzeydir: okunabilir yüzey varsayılanda 9, iki kopyada 18, erişimi daraltılmış üç kopyada 6. Şifreleme anahtarı yeni bir tek noktadır ve yedeğin içinde saklanamaz.

Sonraki Adım

Bu dersin bütün sayıları bir yedek kümesinden çıktı; hiçbiri bir geri yükleme yapılarak elde edilmedi. Kapsam tablosu bir kalemin yedek kümesinde bulunduğunu söyler, okunabilir olduğunu değil; nokta sayısı bir noktaya dönülebileceğini söyler, dönüşün ne kadar süreceğini değil. Sonraki ders bunu denetimli bir tatbikatla sınar: gerçek dosyalar yedeklenip geri yüklenir ve geri gelenin gidenle birebir aynı olduğu doğrulanır. Ölçülecek üç şey var — tatbikatta geçen gerçek süre, kapsam tablosunun doğru saydığı kalem sayısı ve tatbikatsız bir düzende ilk geri yüklemenin hangi varsayımları birden kırdığı.

İ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