MySQL InnoDB çöktükten sonra veri kurtarma
Selamlar, bu yazımda MySQL'in en sevilen ama en az anlaşılan konularından birine, InnoDB'nin crash recovery mekanizmasına bakacağız. Konuyu hem teorik hem de pratik tarafıyla ele alacağız; çünkü production'da bir gece yarısı MySQL ayağa kalkmıyorsa, dokümantasyonu o anda okumak biraz geç oluyor. Lafı çok uzatmadan başlayalım.
InnoDB aslında çökmelerden tek başına kurtulmak için tasarlanmıştır. Yani sunucu fişten çekildiğinde bile, redo log dosyaları sayesinde commit edilmiş işlemleri geri oynatır, yarım kalanları rollback eder. Çoğu zaman siz farkına bile varmazsınız. Ama bazen otomatik kurtarma yetmez ve iş başa düşer.
InnoDB crash recovery nasıl çalışır?
InnoDB, write-ahead logging (kısaca WAL) yaklaşımını kullanır. Şöyle ki, veri sayfaları diske yazılmadan önce değişiklikler önce redo log'a yazılır. MySQL 8.0.30 öncesinde bu dosyalar ib_logfile0 ve ib_logfile1 idi; sonrasında #innodb_redo/ klasörü altına taşındı.
Çökme sonrası başlangıçta InnoDB üç şey yapar:
- Son checkpoint'ten itibaren redo log'u okur.
- Commit edilmiş işlemleri ileri sarar (roll forward).
- Yarım kalan işlemleri undo log ile geri alır (rollback).
Recovery'nin gerçekten çalışıp çalışmadığını şuradan kontrol edebilirsiniz:
SELECT * FROM performance_schema.global_status
WHERE VARIABLE_NAME LIKE 'Innodb_redo_log%';
Otomatik kurtarma ve error log
Vakaların büyük çoğunluğunda MySQL kendi kendine ayağa kalkar. Bizim ilk işimiz error log'a bakmak olmalı:
sudo tail -100 /var/log/mysql/error.log | grep -i 'recovery\|innodb\|crash'
Tipik olarak şuna benzer satırlar görürsünüz:
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Restoring possible half-written data pages
InnoDB: Completed initialization of buffer pool
Bu satırları gördüyseniz rahat nefes alabilirsiniz; InnoDB işini yapmış demektir.
MySQL ayağa kalkmıyorsa
İşler çığrından çıktığında, yani MySQL servisi başlamıyorsa, error log yine ilk durağımız:
sudo journalctl -u mysql --since '1 hour ago'
Genelde şu iki hata mesajı yön gösterir:
[ERROR] InnoDB: Corruption in the InnoDB tablespace - use innodb_force_recovery
[ERROR] InnoDB: Unable to lock ./ibdata1 - check if another mysqld is running
İkincisi aslında masum bir durum; çoğu zaman zombi bir mysqld process'i takılı kalmıştır. İlki ise daha can sıkıcı, çünkü innodb_force_recovery parametresine başvurmamız gerekecek.
Yedekten geri dönmek
Açıkçası bana sorarsanız, ciddi bir bozulma varsa en sağlıklı yol yedekten dönmektir. innodb_force_recovery=6 ile veriyi kurtarabilirsiniz, ama o noktada veri tutarlılığı zaten yarım yamalaktır.
Mantıksal yedek (mysqldump) için:
mysql -u root -p < /backup/full_backup_2026-03-31.sql
Fiziksel yedek (Xtrabackup) için MySQL durdurulmalı ve data dizini boşaltılmalı:
sudo systemctl stop mysql
xtrabackup --prepare --target-dir=/backup/xtrabackup_2026-03-31/
sudo rm -rf /var/lib/mysql/*
xtrabackup --copy-back --target-dir=/backup/xtrabackup_2026-03-31/
sudo chown -R mysql:mysql /var/lib/mysql/
sudo systemctl start mysql
Binary log ile point-in-time recovery
Yedeği geri yüklediniz; tamam ama yedek sabah 03:00'a ait, çökme öğlen 13:00'da oldu. Aradaki on saatlik veri ne olacak? Eğer binary log açıksa, o on saati mysqlbinlog ile geri oynatabiliriz:
mysqlbinlog --start-datetime='2026-03-31 03:05:00' \
--stop-datetime='2026-03-31 12:55:00' \
/var/lib/mysql/mysql-bin.000001 | mysql -u root -p
Sık karşılaşılan hatalar
- Binary log'u kapalı bırakmak: Yedeğiniz olsa bile son N saatin verisi gider.
log_binproduction'da pazarlığa açık değil. - Tek replica'yı yedek sanmak: Replica master'ın bozulmasını da seve seve replike eder. Yedek dediğimiz şey ayrı, periyodik ve geri yüklemesi test edilmiş olandır.
innodb_force_recovery=6ile uzun süre çalışmak: Bu mod read-only'dir ve veri çıkarmak içindir. Veriyi alır almaz yeni bir instance kurun.- Redo log boyutunu küçük bırakmak: Yoğun yazma altında checkpoint baskısı recovery süresini de uzatır. MySQL 8.0.30+ için
innodb_redo_log_capacityile ayarlayın:
[mysqld]
innodb_redo_log_capacity=2G
log_bin=mysql-bin
binlog_expire_logs_seconds=604800
Kapanış
Bu yazıda InnoDB'nin redo log üzerinden nasıl kendi kendine toparlandığına, otomatik kurtarma yetmediğinde error log'dan başlayarak yedek ve binary log'a uzanan yola baktık. Şahsi kanaatim, crash recovery'nin asıl çözümü çökme anında değil, çökmeden çok önce alınan kararlardadır: düzenli yedek, açık binary log ve geri yükleme tatbikatı. Umarım faydalı olur, bir sonraki yazıda görüşmek üzere.
