Göğüs cerrahisinde ve acil travma kliniklerinde hekimlerin en çok korktuğu ölümcül tablolardan biri "Tansiyon Pnömotoraks"tır. Göğüs kafesinin içine biriken hava veya plevral kanama (masif hemotoraks), o kapalı alanda devasa bir basınç oluşturur. Akciğer dokusu genişleyecek fiziksel alan bulamaz; basınç altında ezilir, büzüşür ve tamamen söner (kollabe olur). Kalbe dönen ana toplardamarlar ezildiği için kardiyak debi sıfırlanır.

Şimdi düşünün ki acemi bir asistan hekim, göğüs kafesini bir iğne veya dren tüpüyle delip o sıkışan havayı/kanamayı dışarı tahliye etmek (yer açmak) yerine; hastanın ağzına mekanik ventilatörün hortumunu sokup en yüksek basınçla içeriye hava basmaya çalışıyor! Sonuç ne olur? Genişleyecek yeri olmayan akciğer dokusu o basınç karşısında yırtılır, kalp tamponadı gelişir ve hasta ameliyat masasında feci şekilde can verir. Yapılması gereken şey basmak değil, önce sıkışan alanı boşaltmaktır.

Linux sunucu yönetiminde ve veritabanı mühendisliğinde de acemi yöneticilerin panikle yaptığı ve yüz binlerce liralık kurumsal veritabanlarını mezarlığa çeviren en büyük felaket tam olarak bu mekanik ventilatör cinayetidir: Diski %100 dolan MySQL/MariaDB servisini, diskte yer açmadan zorla systemctl restart ile ayağa kaldırmaya çalışıp InnoDB tablolarını (ibdata1) parçalamak.

Gece 03:00: Diskin Sessizce Boğulması

Bir e-ticaret sitesinin, SaaS platformunun veya kurumsal portalın barındığı Linux sunucusunda işler yolunda gitmektedir. Ancak sistem yöneticisi log rotasyonunu (logrotate) doğru yapılandırmayı unutmuştur.

Apache veya Nginx'in access_log ve error_log dosyaları aylardır şişmektedir: 20 GB... 50 GB... 90 GB...

Ve gece saat 03:15'te sunucunun ana disk bölümü (/ veya /var) o kaçınılmaz sınıra toslar:

Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p1  100G  100G     0 100% /

Diskte kalan boş alan: Tam sıfır bayt!

O sırada MySQL veritabanı motoru hafızadaki transaction loglarını diske yazmak ister (redo log flush). Diske bir bayt bile yazamaz. İşletim sistemi No space left on device hatası döndürür.

MySQL/MariaDB son derece akıllı ve disiplinli bir cerrahtır. Diske yazamadığı an veritabanının bütünlüğünü korumak için tek bir güvenli hamle yapar: Panik moduna girer ve kendini güvenli bir şekilde kapatır (Emergency Shutdown).

Sabah mesaisi başladığında web siteleri o meşhur hatayı verir:

"Error establishing a database connection"

Acemi Yöneticinin İntihar Refleksi: "Restart Çekelim Düzelir!"

Şirketin acemi sistem yöneticisi veya dışarıdan destek veren teknisyeni sunucuya SSH ile bağlanır. Durumun nedenini araştırmaz, logları okumaz. Windows refleksinden kalma o en ilkel alışkanlığı devreye sokar: "Servisi yeniden başlatalım, düzelir!"

Terminale komutu yapıştırır:

systemctl restart mariadb
# veya
service mysql restart

Ekranda birkaç saniye sonra kırmızı bir hata patlar:

Job for mariadb.service failed because the control process exited with error code.
See "systemctl status mariadb.service" and "journalctl -xe" for details.

Yönetici panikler. "Nasıl başlamaz?" diyerek komutu tekrar yazar. Bir daha restart! Bir daha! Üçüncü, dördüncü, beşinci deneme...

İşte tansiyon pnömotoraks hastasının ciğerini patlatan an bu andır!

InnoDB'nin Ölümü: Parçalanan ibdata1 ve Tablespace

InnoDB depolama motoru başlatılırken önce ib_logfile0 ve ib_logfile1 dosyalarını okur, yarım kalan işlemleri tamamlamak için geçici alanlar (ibtmp1) oluşturmaya çalışır.

Fakat diskte sıfır bayt yer vardır!

MySQL açılmaya çalışırken diske geçici dosya yazamadığı için tam başlangıç aşamasında yarıda kesilir (SIGABRT / Crash). Yönetici bunu art arda beş kez tekrarladığında, InnoDB'nin o hassas ikili işaretçileri (pointers), veri sayfaları ve ibdata1 ana sistem tablosu yarım kalmış yazma operasyonlarının kurbanı olur.

Log dosyaları bozulur. Tablespace başlıkları (headers) geçersiz hale gelir.

Yönetici nihayet diskin dolu olduğunu fark eder: df -h. Bir log dosyasını siler, 10 GB yer açar. Ve sevinçle tekrar yazar: systemctl start mariadb.

Fakat artık çok geçtir! MariaDB hata günlüğünde o buz gibi ölüm raporu parıldar:

[ERROR] InnoDB: Page [page id: space=0, page number=241] log sequence number 
849182914 is in the future! Current LSN is 848911020.
[ERROR] InnoDB: Database was not shut down normally!
[ERROR] InnoDB: Corruption of an index tree: table `firma_db`.`orders` ...
[ERROR] InnoDB: Plugin initialization failed with error Generic error
[ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
[ERROR] Aborting

Veritabanı motoru artık ayağa kalkamaz; çünkü o şuursuz restart denemeleriyle veritabanının kemikleri kırılmış, omurgası felç edilmiştir!

Yoğun Bakım Ameliyatı: innodb_force_recovery

Bu aşamadan sonra veritabanını kurtarmak, açık kalp ameliyatı kadar hassas ve riskli bir cerrahi operasyondur:

  1. Önce Mevcut Bozuk Durumun Ham İmajını Alın: Hiçbir komut çalıştırmadan önce /var/lib/mysql dizinini harici bir diske veya dizine doğrudan ham haliyle kopyalayın (cp -rp /var/lib/mysql /var/lib/mysql_backup).
  2. Kurtarma Modunu Devreye Alın (my.cnf):
    MySQL ayar dosyasına InnoDB'nin çökmüş sayfaları görmezden gelip sadece salt-okunur (read-only) modda açılmasını sağlayan acil servis parametresini ekleyin:
    [mysqld]
    innodb_force_recovery = 1
    Eğer 1 seviyesinde açılmazsa bu seviyeyi kademeli olarak 2, 3 ve en fazla 4'e kadar yükseltin (5 ve 6 seviyeleri veriyi kalıcı olarak bozabilir!).
  3. Servisi Başlatın ve Döküm Alın (mysqldump): Veritabanı salt-okunur olarak ayağa kalktığı saniyede tüm veritabanlarını metin formatında döküm alın:
    mysqldump --all-databases --routines --triggers > /root/kurtarilan_veriler.sql
  4. Veritabanını Sıfırdan İnşa Edin: Servisi durdurun, /var/lib/mysql dizinini temizleyin, mysql_install_db ile sıfır temiz bir veritabanı kümesi oluşturun ve kurtarılan o .sql dosyasını içeri aktarın.

Diskin Boğulmasını Önleme Protokolü

Bir veritabanının disk doluluğundan ölmesini engellemek için izlenmesi gereken asgari sistem mühendisliği kuralları şunlardır:

  • Ayrı Bölümleme (Partitioning): Veritabanı dizinini (/var/lib/mysql) işletim sisteminin ve logların bulunduğu ana kök (/) diskinden tamamen ayırın. Veritabanı bağımsız, izole bir NVMe disk bölümünde (/data/mysql) yaşamalıdır. Böylece Nginx logları 100 GB bile dolsa, veritabanının diski asla dolmaz!
  • Otomatik Disk İzleme ve Alarm: Zabbix, Prometheus veya basit bir cron betiği ile disk doluluğu %85 seviyesine ulaştığında yöneticinin telefonuna acil durum bildirimi göndermek.
  • Logrotate Disiplini: Sunucudaki tüm web ve veritabanı loglarının günlük rotasyona tabi tutulması ve 7 günden eski logların otomatik sıkıştırılıp silinmesi.
  • Asla Körlemesine Restart Atmayın: Bir servis çöktüğünde ilk bakılacak yer df -h (disk doluluğu) ve tail -n 100 /var/log/messages olmalıdır. Nedeni bilinmeyen bir çöküşü restart ile zorlamak, arızayı kalıcı hasara dönüştürmekten başka bir işe yaramaz.

Nefes borusu tıkanmış hastayı döverek uyandıramazsınız; önce o boruyu açmanız gerekir. Diski dolan veritabanını da zorla yeniden başlatmak veriyi kurtarmaz; sadece dijital tabutun çivilerini çakar. Soğukkanlılık ve doğru teşhis, cerrahide olduğu gibi sistem mühendisliğinde de hayat ile ölüm arasındaki tek köprüdür.