İçeriğe geç
academia.sh

Ders 17 / 25

Zaman Noktasına Kurtarma

Taban yedek ile günlük arşivinin birlikte kullanılması: kurtarma penceresi, hedef anın seçilmesi, günlüğün hedefe kadar ileri sarılması, kaza sonrası işin kaybı ve kısmi kurtarmanın hesaplanması.

İçindekiler

Önceki ders su işareti tabanlı artımlı yedeğin üç boşluğunu bıraktı: güncellemeler, silmeler ve şema değişiklikleri yakalanmıyordu. Üçünün ortak nedeni aynıydı — satırların son hâline bakmak, aralarında ne olduğunu anlatmaz.

Aradaki her değişikliği sırayla kaydeden bir kaynak zaten var. Motor, kalıcılığı sağlamak için her değişikliği veri dosyalarına yazmadan önce bir günlüğe yazar; bu düzenek bu kursun Motor Mimarisi konusunda ele alındı. O günlük saklanırsa, elde yalnız veritabanının iki anlık görüntüsü değil, ikisi arasındaki bütün hareket bulunur.

Zaman noktasına kurtarma (point-in-time recovery) bunun kullanımıdır: bir taban yedek geri yüklenir, üzerine günlük kayıtları seçilen ana kadar uygulanır ve veritabanı o andaki hâline döner.

Kurtarma Penceresi

Yöntem iki parçadan oluşur.

Taban yedek (base backup), belirli bir andaki tam kopyadır — önceki dersteki mantıksal ya da fiziksel yedek. Kurtarmanın başlangıç noktasıdır.

Günlük arşivi (log archive), taban yedeğin alındığı andan bugüne kadarki günlük kayıtlarının saklanmış hâlidir. Motor günlüğü kendi çalışma alanında sınırlı süre tutar; arşivleme, dolan günlük parçalarının ayrı bir yere kopyalanmasıdır.

İkisi birlikte bir kurtarma penceresi tanımlar: taban yedeğin anı ile arşivin son anı arasındaki her noktaya dönülebilir. Pencerenin başı taban yedeğin yaşıyla, sonu arşivin sürekliliğiyle belirlenir. Arşivleme sessizce durursa pencere büyümeyi bırakır ve kimse fark etmeden kurtarma yeteneği taban yedeğin anına geriler.

Bir Kaza ve Kurtarılması

Aşağıdaki blok bir günü canlandırıyor. Sabah dokuzda taban yedek alınıyor. Gün boyunca ödünç kayıtları açılıyor ve iadeler işleniyor; her değişiklik zaman damgasıyla günlüğe yazılıyor. Saat 11:15’te koşulsuz bir silme deyimi çalışıyor — Sahil şubesinin bütün ödünç kayıtları gidiyor. Kimse fark etmiyor, iş akşama kadar sürüyor.

Kurtarma, taban yedeği yeni bir veritabanına yükleyip günlüğü 11:15’ten öncesine kadar uygulamaktır.

Bloktaki DELETE FROM odunc WHERE sube_id=2; deyimi kasıtlı olarak yıkıcıdır ve dersin konusunu oluşturur. Yalnız bu blokta üretilen geçici dosyalar üzerinde çalışır. Gerçek bir sistemde koşulsuz ya da geniş koşullu silme deyimleri, önce aynı koşulla bir sayım sorgusu çalıştırılarak sınanır; kurtarma bu alışkanlığın yerine geçmez.

rm -f kutuphane.db kurtarilan.db taban_ani.db taban.sql gunluk.log

sqlite3 kutuphane.db <<'SQL'
CREATE TABLE odunc(id INTEGER PRIMARY KEY, kitap_id INT NOT NULL, uye_id INT NOT NULL,
                   sube_id INT NOT NULL, alis TEXT NOT NULL, iade TEXT);
WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<2000)
INSERT INTO odunc(id,kitap_id,uye_id,sube_id,alis,iade)
SELECT n,(n%500)+1,(n%300)+1,(n%3)+1,'2025-06-01',NULL FROM s;
SQL

# 09:00 — taban yedek
sqlite3 kutuphane.db .dump > taban.sql

# Gunluk: her satir "zaman|deyim". 11:15'te kosulsuz bir silme var.
node - <<'EOF' > gunluk.log
const satir = [];
const zaman = (dk) => new Date(Date.UTC(2025, 5, 10, 9, 0, 0) + dk * 60000)
  .toISOString().slice(0, 19);
for (let i = 1; i <= 300; i++) {
  const dk = i * 0.44;
  if (i % 3 === 0) {
    satir.push(zaman(dk) + "|UPDATE odunc SET iade='2025-06-10' WHERE id=" + (i * 5) + ";");
  } else {
    const id = 2000 + i;
    satir.push(zaman(dk) + "|INSERT INTO odunc VALUES(" + id + "," + ((id % 500) + 1) +
               "," + ((id % 300) + 1) + "," + ((id % 3) + 1) + ",'2025-06-10',NULL);");
  }
}
satir.push("2025-06-10T11:15:00|DELETE FROM odunc WHERE sube_id=2;");
for (let i = 1; i <= 200; i++) {
  const id = 3000 + i;
  satir.push(zaman(136 + i * 1.7) + "|INSERT INTO odunc VALUES(" + id + "," + ((id % 500) + 1) +
             "," + ((id % 300) + 1) + "," + ((id % 3) + 1) + ",'2025-06-10',NULL);");
}
console.log(satir.join("\n"));
EOF

# Gunlugun tamami canli veritabanina uygulanir.
awk -F'|' '{print $2}' gunluk.log | sqlite3 kutuphane.db

# Kurtarma: taban yedek + gunlugun hedef ana kadarki bolumu.
HEDEF='2025-06-10T11:15:00'
sqlite3 kurtarilan.db < taban.sql
awk -F'|' -v t="$HEDEF" '$1 < t {print $2}' gunluk.log | sqlite3 kurtarilan.db

sqlite3 taban_ani.db < taban.sql

echo "gunluk kaydi   : $(wc -l < gunluk.log | tr -d ' ')"
echo "uygulanan kayit: $(awk -F'|' -v t="$HEDEF" '$1 < t' gunluk.log | wc -l | tr -d ' ')"
echo "atlanan kayit  : $(awk -F'|' -v t="$HEDEF" '$1 >= t' gunluk.log | wc -l | tr -d ' ')"

sqlite3 -box -header kutuphane.db "
ATTACH 'kurtarilan.db' AS k; ATTACH 'taban_ani.db' AS t;
SELECT 'taban yedek (09:00)' AS durum, COUNT(*) AS satir, SUM(sube_id=2) AS sube2, SUM(iade IS NOT NULL) AS iadeli FROM t.odunc
UNION ALL SELECT 'kurtarilan (11:15 oncesi)', COUNT(*), SUM(sube_id=2), SUM(iade IS NOT NULL) FROM k.odunc
UNION ALL SELECT 'canli (17:00, kazadan sonra)', COUNT(*), SUM(sube_id=2), SUM(iade IS NOT NULL) FROM main.odunc;

SELECT (SELECT COUNT(*) FROM k.odunc WHERE id NOT IN (SELECT id FROM main.odunc)) AS yalniz_kurtarilanda,
       (SELECT COUNT(*) FROM main.odunc WHERE id NOT IN (SELECT id FROM k.odunc)) AS yalniz_canlida;"
gunluk kaydi   : 501
uygulanan kayit: 300
atlanan kayit  : 201
┌──────────────────────────────┬───────┬───────┬────────┐
│            durum             │ satir │ sube2 │ iadeli │
├──────────────────────────────┼───────┼───────┼────────┤
│ taban yedek (09:00)          │ 2000  │ 667   │ 0      │
│ kurtarilan (11:15 oncesi)    │ 2200  │ 767   │ 100    │
│ canli (17:00, kazadan sonra) │ 1633  │ 67    │ 100    │
└──────────────────────────────┴───────┴───────┴────────┘
┌─────────────────────┬────────────────┐
│ yalniz_kurtarilanda │ yalniz_canlida │
├─────────────────────┼────────────────┤
│ 767                 │ 200            │
└─────────────────────┴────────────────┘

Sonuçların Okunması

İlk tablo üç durumu yan yana koyuyor.

Taban yedek anında iki bin satır vardı ve hiçbiri iade edilmemişti. Yalnız bu yedekten dönmek, sabah dokuzdan sonra yapılan her şeyi silmek demektir — iki yüz yeni ödünç kaydı ve yüz iade işlemi.

Kurtarılan kopya, günlüğün üç yüz kaydı uygulandıktan sonraki hâl. Sahil şubesinin yedi yüz altmış yedi kaydı yerinde, yüz iade işlenmiş durumda. Bu, kazadan hemen önceki gerçek durumdur ve taban yedekten değil, taban yedek artı günlükten elde edildi.

Canlı veritabanında Sahil şubesinden yalnız altmış yedi kayıt var — hepsi kazadan sonra açılmış yeni kayıtlar. Yedi yüz kayıt silinmiş durumda.

Kurtarmanın Bedeli

İkinci tablo, kurtarmanın gerçek maliyetini gösteriyor. Kurtarılan kopyada olup canlıda olmayan yedi yüz altmış yedi satır, silmenin götürdükleri. Canlıda olup kurtarılan kopyada olmayan iki yüz satır ise kurtarmanın götürecekleri: kazadan sonra yapılmış olağan işler.

Kurtarılan kopyayı doğrudan canlının yerine koymak, o iki yüz kaydı silmek demektir. Bu, zaman noktasına kurtarmanın çoğu kez atlanan yanıdır: hedef anı seçmek, o andan sonraki her şeyi feda etmektir.

Kaza ile fark ediliş arasında geçen süre uzadıkça bu maliyet büyür. Altı saat sonra fark edilen bir silme, iki yüz kayıtlık iş kaybı üretir; iki gün sonra fark edilen aynı silme, iki günlük iş kaybı üretir.

Bu yüzden işletim pratiğinde tercih edilen yol, kurtarılan kopyayı canlının yerine koymak değil, yanına koymaktır. Kurtarılan kopya ayrı bir veritabanı olarak açılır, eksik satırlar oradan çekilir ve canlıya eklenir. İkinci tablonun ilk sütunu tam olarak bu işlemin girdisidir: hangi satırların taşınacağı sayılmış durumdadır. Bu yol yalnız silmelerde işler; şema bozulması ya da yaygın bir güncelleme hatasında tam geri dönüş gerekir.

Hedef Anın Seçilmesi

Kurtarma hedefi iki biçimde verilebilir.

Zaman damgasıyla. Yukarıdaki örnekteki gibi: “şu ana kadar uygula”. Okunması kolaydır ama kesin değildir — aynı saniye içinde birden çok işlem bitmiş olabilir ve hepsi ya alınır ya alınmaz.

İşlem tanımlayıcısıyla. Motorların günlüğe yazdığı sıra numarası ya da işlem kimliğiyle: “şu işleme kadar uygula, o dâhil değil”. Kesin sınır verir. Hatalı deyimin tanımlayıcısını bulmak, günlüğü okuyabilmeyi gerektirir; motorların çoğu bunun için bir inceleme aracı sağlar.

Pratikte iki adım birlikte kullanılır: önce zaman damgasıyla kabaca daraltılır, sonra o aralıktaki günlük kayıtları okunarak hatalı deyimin tam sınırı bulunur. Kurtarmanın önce bir sınama ortamında yapılması, hedefin yanlış seçilmesi hâlinde ikinci bir deneme hakkı bırakır.

Bu Modelin Gerçekten Ayrıldığı Nokta

Yukarıdaki günlük, deyim metinlerinden oluşuyor ve yeniden çalıştırılarak uygulanıyor. Bu bir modeldir; kurtarma penceresi, ileri sarma ve hedef seçimi kavramlarını doğru gösterir ama gerçek motorların günlüğü böyle değildir.

Gerçek günlükler değişikliği fiziksel düzeyde kaydeder: hangi sayfanın hangi baytları ne oldu, ya da hangi satır hangi değerlere geçti. Bunun nedeni belirlenimci olmayan deyimlerdir. Şimdiki zamanı, rastgele bir sayıyı ya da bir sıra üretecini kullanan bir deyim, yeniden çalıştırıldığında farklı sonuç üretir. Deyim metnini tekrar oynatan bir kurtarma, kaynaktan sapmış bir veritabanı üretir.

İkinci fark işlem sınırlarıdır. Gerçek günlük, hangi kaydın hangi işleme ait olduğunu ve o işlemin kesinleşip kesinleşmediğini taşır. Kurtarma sırasında kesinleşmemiş işlemlerin kayıtları geri alınır. Yukarıdaki modelde her satır bağımsızdır; işlem kavramı yoktur.

Kavramsal olarak değişmeyen üç şey vardır: kurtarma taban yedekten başlar, günlük sırayla ileri sarılır, hedef anda durur.

Özet

  • Zaman noktasına kurtarma, taban yedeğin üzerine günlük kayıtlarının seçilen ana kadar uygulanmasıdır.
  • Kurtarma penceresinin başı taban yedeğin anı, sonu günlük arşivinin son anıdır; arşivleme durursa pencere sessizce daralır.
  • Hedef anın seçilmesi, o andan sonraki bütün işi feda etmek anlamına gelir; kayıp, kazanın fark edilme süresiyle büyür.
  • Kurtarılan kopyayı canlının yanına koyup eksik satırları taşımak, silme kazalarında iş kaybını önler.
  • Hedef, zaman damgasıyla kabaca, işlem tanımlayıcısıyla kesin biçimde verilir.
  • Gerçek günlükler deyim değil fiziksel değişiklik kaydeder; belirlenimci olmayan deyimler, deyim tekrarına dayalı kurtarmayı güvenilmez kılar.

Sonraki Adım

Bu dersteki kurtarma işledi, çünkü taban yedek okunabilir ve günlük eksiksizdi. İkisinin de doğru olduğu, ancak kurtarma denenerek bilinir — ve kurtarmanın denendiği an, gerçek bir arıza anı olmamalıdır. Sonraki ders yedek doğrulamayı ele alıyor: bir yedeğin bütünlüğünün karma ile denetlenmesi, bozulmuş bir yedeğin geri yüklemeden önce fark edilmesi ve düzenli kurtarma tatbikatının neyi güvence altına aldığı.

İ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