MySQL InnoDB I/O Kapasitesini Doğru Ayarlamak
Selamlar, bu yazımda MySQL'in en sık ihmal edilen ayarlarından innodb_io_capacity üzerine konuşacağız. Konu kuru gibi durur ama aslında şu işe yarıyor: InnoDB'ye 'kardeşim, altındaki disk saniyede şu kadar I/O kaldırıyor, sen de arka plan işlerini buna göre ayarla' demek. Yanlış değer girince ya disk tembelleşir ya da gereksiz yere foreground sorgularını boğarsınız. Hadi başlayalım.
InnoDB arka planda ne yapıyor?
InnoDB her yazma işlemini diske anında basmaz; önce buffer pool'da kirli sayfa (dirty page) olarak tutar. Sonra arka planda bunları diske flush eder. Bunun yanında bir de change buffer var; secondary index güncellemelerini biriktirip tek seferde merge ediyor. Bütün bu arka plan işleri için InnoDB'nin elinde bir 'I/O bütçesi' var. Bu bütçeyi siz innodb_io_capacity ile veriyorsunuz.
Varsayılan değer 200. Bu rakam 2000'lerin sonundan kalma, klasik dönen disk (HDD) için seçilmiş. Bugün ortalama bir SATA SSD bile saniyede on binlerce IOPS kaldırırken 200 demek, Ferrari'ye dönüşüm hızında yol vermek gibi.
Mevcut değerlere bakalım
SHOW GLOBAL VARIABLES LIKE 'innodb_io_capacity%';
İki değişken görürsünüz:
innodb_io_capacity: normal koşullarda saniyede yapılacak arka plan I/O sayısı.innodb_io_capacity_max: redo log dolmaya başladığında, adaptive flushing devreye girince çıkılabilecek üst sınır.
İkincisi tavan, birincisi cruise hızı diye düşünebilirsiniz.
Diskinizin gerçekten kaç IOPS verdiğini ölçün
Bence bu adımı atlamak büyük hata. İnternette 'NVMe ise 10000 yaz' diyen rehberler çok ama sizin diskiniz cloud'da paylaşımlı bir volume olabilir, IOPS sınırı var olabilir. Önce ölçün:
sudo apt-get install -y fio
fio --name=mysql_iops \
--ioengine=libaio \
--iodepth=32 \
--rw=randwrite \
--bs=4k \
--direct=1 \
--size=2G \
--numjobs=4 \
--runtime=60 \
--filename=/var/lib/mysql/fio_test
Test bittikten sonra fio_test dosyasını silin. 4K random write seçtik çünkü InnoDB'nin sayfa boyutu 16K olsa da yazma deseni buna oldukça benziyor.
Ölçtüğünüz IOPS'un kabaca %75'ini innodb_io_capacity olarak alın; geri kalan %25 foreground sorgularına nefes payı.
Pratik başlangıç değerleri
Bana sorarsanız, ölçemeyeceğiniz bir ortamda şu rakamlardan birini seçip izlemeye başlamak makul:
| Donanım | innodb_io_capacity | innodb_io_capacity_max |
|---|---|---|
| Klasik HDD | 200 | 400 |
| SATA SSD | 2000 | 4000 |
| NVMe SSD | 10000 | 20000 |
| Yüksek uçlu NVMe | 20000 | 40000 |
Genel kural: _max değeri normal değerin yaklaşık iki katı olsun.
Çalışan sunucuda denemek
Restart gerekmiyor, runtime'da değiştirip izleyebilirsiniz:
SET GLOBAL innodb_io_capacity = 2000;
SET GLOBAL innodb_io_capacity_max = 4000;
Beğendiyseniz my.cnf'e kalıcı yazın:
[mysqld]
innodb_io_capacity=2000
innodb_io_capacity_max=4000
innodb_flush_method=O_DIRECT
O_DIRECT SSD'de işletim sistemi cache'i ile InnoDB cache'inin çift tampon yapmasını engeller; SSD ortamında kazançlıdır. NVMe'de ise O_DIRECT_NO_FSYNC sıkça tercih edilir.
Çalışıyor mu, nereden anlarız?
Kirli sayfa oranı en pratik göstergedir:
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_total';
Dirty oranı sürekli %75 üzerinde takılıyorsa flush yetişmiyor demektir, innodb_io_capacity'yi kademeli artırın. Tam tersi, %10'un altında geziniyorsa ya yazma yükünüz hafif ya da değer fazla agresif; biraz indirip kıyaslayın.
Sık karşılaşılan tuzaklar
- Belgeye bakmadan büyük rakam yazmak: 50000 yazınca disk hızlanmıyor, sadece InnoDB kendine yalan söylüyor. Ölçtüğünüzden büyük değer vermeyin.
_max'ıio_capacity'ye eşitlemek: Adaptive flushing'in nefes alacak yeri kalmaz; redo log dolmaya başlayınca sistem aniden tıkanır.- Cloud disk sınırını unutmak: AWS gp3 veya Azure Premium SSD'de IOPS satın alınır. Disk fiziksel olarak fazlasını kaldırsa bile sınır aşılınca throttle olursunuz.
O_DIRECT'i HDD'de kullanmak: HDD'de OS cache hâlâ işe yarar; körlemesineO_DIRECTaçmayın.
Kapanış
Özetle, innodb_io_capacity diskin gerçek hızını InnoDB'ye anlatan bir köprü. Varsayılan 200 ile bırakmak modern donanıma yapılan bir haksızlık; ölçüp %75'ini vermek ise neredeyse her zaman doğru hamle. Şahsi kanaatim, değeri değiştirdikten sonra en az 24 saat dirty page sayısını izlemeden bir karara varmamak. Umarım faydalı olur, bir sonraki yazıda görüşmek üzere.
