· kaynak dev.to (home feed)
cgroup v2 io.max, yedekleme I/O'sunu sınırlıyor ve gece görevleri veritabanı gecikmesini aç bırakmayı bırakıyor
dev.to'da yayımlanan bir rehber, ionice'in modern NVMe zamanlayıcılarında neden artık işe yaramadığını açıklıyor ve systemd slice'ları ile cgroup v2 io.max kullanarak yedekleme işinin I/O'sunun nasıl sınırlandırılacağını adım adım anlatıyor.
Hata modu
dev.to'da yayımlanan bir rehber, birçok operatörün tanıyacağı bir senaryoyu ele alıyor: gece yedeği 01:00'de başlıyor ve 01:05'e kadar veritabanının p99 sorgu gecikmesi 4 ms'den 90 ms'ye sıçrayarak nöbetçi uyarısını tetikliyor. Yazıya göre yedekleme bozuk, yavaş veya CPU canavarı değil. Basitçe, veritabanının bulunduğu aynı NVMe cihazına saniyede yaklaşık 400 MB yazıyor ve veritabanı block layer'da beklemeye mahkum kalıyor.
ionice artık neden yardımcı olmuyor
Yazarın dediğine göre ilk içgüdü olan ionice -c3, çoğu sistemde yıllardır etkisiz. I/O önceliği ancak block scheduler ona uyarsa bir anlam taşır ve ionice'i üne kavuşturan CFQ zamanlayıcısı Linux 5.0'da kaldırıldı. NVMe diskler genellikle none veya mq-deadline zamanlayıcılarını kullanıyor ve ikisi de ioprio'ya göre zamanlama yapmıyor; dolayısıyla öncelik değeri kaydediliyor ama hiçbir zaman okunmuyor. Öncelikleri gerçekten dikkate alan BFQ altında bile ioprio oransal, bir üst sınır değil: idle önceliğine sahip bir yedekleme yine de veritabanının kullanmadığı tüm boş IOPS'leri tüketiyor ve hızlı bir cihazda bu bile kuyruk (tail) gecikmesini berbat etmeye yeter.
Üç ayar, üç mekanizma
Yazının özü, cgroup v2 io denetleyicisinin ayrıntılı bir çözümlemesi; yazarın vurguladığı gibi bu, farklı garantileri olan birkaç mekanizmadan oluşuyor:
- io.max, blk-throttle tarafından desteklenir ve cihaz başına saniyedeki bayt veya işlem sayısına sert bir üst sınır getirir. Work-conserving değildir, yani kullanılmayan kapasite boşa gider.
- io.weight, iocost veya BFQ tarafından desteklenir ve kardeş gruplar arasında I/O zamanının oransal bir payını dağıtır; yalnızca iocost etkinse veya BFQ zamanlayıcıysa etkindir.
- io.latency, blk-iolatency tarafından desteklenir ve akranları kısıtlayarak bir grubun gecikme hedefini korur; yalnızca kardeşleri karşılaştırır ve önce gözlemleyip sonra tepki vererek çalışır.
Yazıya göre iki tasarım ayrıntısı çoğu sürprizi açıklıyor. Birincisi, io.max block layer istekleri üzerinde uygulanır, write(2) çağrılarında değil: tamponlanmış yazmalar page cache'e gider ve cihaz I/O'suna dönüşmeleri writeback sırasında, daha sonra olur; dolayısıyla bir süreç, kısıtlama onları görmeden önce yüzlerce megabaytlık veriyi kirletebilir. İkincisi, çekirdek belgeleri geçici patlamalara (burst) açıkça izin veriyor. Pratik sonuç şu: io.max süre başına cihaz trafiğini sınırlar, syscall başına hızı değil; ve bu, doğru şeyi ölçdüğünüz sürece bir yedekleme için kabul edilebilir.
systemd'e bağlamak
Tarif doğrulamayla başlıyor: /sys/fs/cgroup'un birleşik hiyerarşi (cgroup2fs) olduğunu doğrulayın, io'nun cgroup.controllers içinde göründüğünü kontrol edin ve lsblk ile MAJ:MIN cihaz numaralarını toplayın. systemd.resource-control(5)'in belirttiği gibi ayarlar, bir bölüme veya loop cihazına değil, kaynağı olan fiziksel cihaza atıfta bulunmalı.
Yazar daha sonra hizmeti doğrudan sınırlamak yerine bir backup.slice oluşturuyor; böylece işin başlattığı her şey aynı bütçeyi devralıyor ve sınır, unit dosyasını düzenlemeden sonradan yükseltilebiliyor. Gerçek sınırlar bir drop-in'e gidiyor: cihaz üzerinde sırasıyla 200M ve 100M değerlerinde IOReadBandwidthMax ve IOWriteBandwidthMax, ayrıca 2K değerinde IOWriteIOPSMax.
Bu yapılandırmayı kopyalamadan önce üç ayrıntıya dikkat çekiliyor. Systemd son ekleri 1000 tabanlıdır, yani 100M saniyede 100.000.000 bayt demektir; MiB düşünüyorsanız niyetinizden yaklaşık %4,6 düşük olur. Bant genişliği ve IOPS sınırları eşzamanlı uygulanır; küçük rastgele yazmalarda önce IOPS sınırı, büyük sıralı yazmalarda ise önce bant genişliği sınırı devreye girer ki bu genellikle bir yedeklemenin ihtiyacı olan şeydir. Ayrıca /srv gibi bir yolu cihaza çözümlemek RAID veya çoğu volume manager üzerinden çalışmaz; bu yüzden fiziksel cihazı açıkça adlandırın.
Sınırın gerçek olduğunu kanıtlamak
Bir daemon-reload'dan sonra gerçeğin kaynağı /sys/fs/cgroup/backup.slice/io.max dosyasıdır. Sınır satırı yoksa denetleyici slice'a bağlı değildir ve hizmeti yeniden başlatmak hiçbir işe yaramaz. io.stat dosyası cihaz başına canlı sayaçlar sunar: bir çalıştırmadan önce ve sonra okuyun; wbytes değerinin geçen saniyeye bölümü, sınırdan çok yüksekte değil ona yakın çıkmalı. Kontrollü bir test için yazı, systemd-run ile aynı slice içinde direct I/O kullanan fio çalıştırıyor ve kabaca sınırlandırılmış hıza ulaşmayı bekliyor; bunun yerine sınırsız bir aktarım hızı görüyorsanız, sınır o unit'e bağlı değildir.
Tuzaklar
Yazar uyarıyor: tamponlanmış yazmalar yalan söyler; oflag=direct veya conv=fsync olmadan dd, page cache'e kopyalama hızını ölçer ve cgroup 100 MB/s ile sınırlıyken 3 GB/s bildirmekten mutluluk duyar, çünkü baytlar henüz cihaza ulaşmamıştır. Her zaman direct I/O veya zorunlu writeback ile test edin. Yazı ayrıca cgroup writeback atıfının dosya sistemi desteği gerektirdiğini belirtiyor; ne var ki yayımlanan metin o noktada açıklamanın ortasında kesiliyor.
Neden önemli
Toplu iş yükleri ve gecikmeye duyarlı hizmetler rutin olarak tek bir NVMe cihazını paylaşır; bu, küçük sunucularda ve birçok bulut VM'inde varsayılan yerleşimdir ve nöbetçi mühendisi sayfalara gömen bir yedekleme penceresi, tekrarlayan, kendi kendine verilmiş bir kazadır. Yazının değeri, çalışan bir io.max yapılandırmasını, önceki girişimlerin neden başarısız olduğuna dair bir açıklamayla eşleştirmesidir: ionice modern zamanlayıcılar tarafından yok sayılır, page cache tamponlaması kısıtlamayı gizler ve 1000 tabanlı son ekler sayıları kaydırır. Ayrıca io.max'a ne zaman başvurulacağını io.weight veya io.latency'ye karşı netleştirir: arka plan işleri için sert bir üst sınır; amaç kapsama değil adil paylaşım olduğunda ise oransal pay veya gecikme koruması.
- #linux
- #systemd
- #cgroups
- #storage
- #performance