ZFS gelişmiş önbellekleme özellikleri taşır. Bu makalede ZFS havuzunuza bir önbellek atayacak ve hem etkisini, hem de nasıl işlediğini tartışacağım.
ZFS önbelleği ve stratejiler
Önbelleklemeyi kabaca daha çabuk ihtiyaç duyacağımız veriyi hızlı bir yerlerde saklamak olarak ifade edebiliriz. Her türlü depolamada genel eğilim hız arttıkça fiyatın da artması olduğundan önbellekler tipik olarak küçük boyutludur. Hatta işlemcilerdeki önbellekler (cache diye yazar ya) aynı zamanda alan kısıntısı nedeniyle de çok küçüktür.
Önbellek olarak illa ki özel bir şey kullanmanız gerekmez. Esas veriyi depoladığınız yerden hızlı her şey bir önbellek olabilir. Veriniz teyp kasedindeyse normal bir sabit disk sizin önbelleğiniz olabilir. Böyle manyetik disklerdeki verinizi bir SSD alıp ona önbellekleyebilirsiniz. Pratikte en hızlı önbellek ise RAM’in kendisidir. Tüm işletim sistemleri RAM’i mümkün olduğunca önbellek olarak kullanmak isterler.
Şimdi önbelleğin alanı kısıtlı olur dedik -zaten kısıtlı olmasaydı tüm veriyi önbellek yapacağımız şeyde saklardık. O zaman bu önbellekte tutacağımız veriyi seçmek için stratejilere ihtiyacımız var çünkü kullanılmayacak verinin yer işgal etmesini istemiyoruz. Yaygın strateji önbellekte bulunan en eski veriyi; “Least Recently Used” (LRU) bilgi parçasını önbellekten şutlamaktır. Bu strateji yakın zamanda diskten okunmuş bilginin tekrar okunma ihtimalinin yüksek olduğunu varsayar.
ZFS ise buna ek olarak bir de en sık kullanılan bilgiyi tutma stratejisini kullanır. Eğer önbelleğinizdeki belirli bir grup veri diğerlerine göre daha sık kullanılıyorsa bu veriyi önbellekte tutmaya çalışır.
İkisinin farkını detaylandıralım. 100 birimlik bir önbelleğiniz olsun. Her veri isteğini sabit disklerinizden okuyup buraya yazıyorsunuz. Gelecekte aynı veri tekrar istenirse sabit diske gidip okumanıza gerek kalmıyor, hızlıca buradan karşılıyorsunuz. Ta ki dolana kadar. Önbellek dolduğunda yeni bir şey yazmak için yazacağınız kadarını önbellekten atmanız gerekiyor. Hangisini atacağız?
LRU stratejisi önbelleğe yazdığı veri parçalarını hangi sırayla yazdığını da takip eder ve en eski olan hangisiyse onu önbellekten atar. Bunun sakıncasını, normalde belirli türde verinin çok fazla kullanıldığı bir sistemde, bu sık kullanımın olmadığı bir anda başka bir grup verinin bir kere talep edilmesinde görebilirsiniz. Yeni istenen veri belki bir kere istenecek ve başka da hiç kullanılmayacak, ama siz önbelleği boşaltıp bunu koyuyorsunuz. Normalde çok kullandığınız verinin tekrar önbelleğe gelmesi için hepsinin birer kere okunmasını bekleyeceksiniz.
ZFS ise önbellekteki parçaların ne zaman kullanıldığının yanısıra ne kadar sık kullanıldığını da takip eder. Yukarıdaki 100 birimlik belleğin belli bir kısmı sık kullanılan veri için tutulmuş gibi düşünün. Yeni gelen veri normalde 100 birimlik alanı dolduracaktı, ama ZFS ona belki 75 birimlik alanı tahsis ediyor ve kalanını (sık kullanıldığı için) önbellekten atmayı reddediyor.
ZFS’in önbelleğine verilen isim Adaptive Replacement Cache (ARC). Bazı kaynaklarda Adjustable Replacement Cache de denir. ARC normalde RAM’dedir -ZFS hakkında bol bellek olsun tavsiyeleri de buradan gelir.
İkinci seviye ZFS önbelleği: L2ARC
Tahmin edeniniz olmuştur, L2ARC basitçe “Level 2 ARC” demek, ikinci seviye önbellek. L2ARC bir disk bölümü olabilir. Genellikle SSD’leri, bazı durumlarda elimizde bol varsa hızlı USB diskleri kullanırız. Bir ZFS havuzuna şu komutla L2ARC önbellek eklenir:
zpool add tank cache /dev/sdf
Bu temel komutun bir sakıncası var: sdf, sdb gibi düğüm isimleri anakart tarafından verilen disk sırasına göre belirlenir. Bazı anakartlar bu düğüm isimlerine her açılışta aynı şekilde vermeyebilirler. Yahut birisi bakım sırasında SAS/SATA yuvalarına bağlı diskleri ve sıralarını karıştırabilir. Öyle bir durumda, bugün sdf olarak bildiğiniz disk yarın sdg olarak karşınıza çıkabilir. ZFS havuzunuz o diski sdf olarak tanıdığı için, bakım yapıp SATA kablolarını karıştıran arkadaş sdf’ye denkgelen yuvaya hangi diski taktıysa onu önbellek zanneder.
Dolayısıyla bunu /dev/disk/by-id altındaki isimlerle yapmanız doğru olur. Yani benim sistemim için şöyle:
ata-TOSHIBA… diye devam eden şey benim sistemimdeki SSD. Sonunda part1, part2 gibi bölümler görüyorsunuz çünkü ben onu aynı zamanda sistem diski olarak da kullanıyorum ve bölümlendirdim. Evet ZFS’te önbellek olarak illa ki tüm diski kullanmak zorunda değilsiniz, bir blok aygıtı kullanabilirsiniz ki bu bir diskin bölümü de olabilir.
L2ARC ekledikten sonra fayda görmek için dolmasını bekliyorsunuz. Bu tamamen sistemin ne kadar kullanıldığına bakıyor. Çok miktarda rastgele okuma varsa hızlı dolacaktır, veya Cuma akşamı eklediğiniz L2ARC ancak Pazartesi günü çalışanlar mesaiye geldikten sonra anlamlı şekilde dolmaya başlayabilir. Yine benim Thinkpad’den:
Hmm, 761MB önbellek kullanımı? Çünkü bilgisayarı geçen günlerde yeniden başlattım. Sistem yeniden başlayınca L2ARC geçersiz kılınır ve tekrar doldurulmaya başlar. Toplam L2ARC boyutumun 25GB olduğunu da görüyorsunuz ki orada bir not iletmem gerek: L2ARC olarak verdiğiniz diskin tamamının dolması şart değil. L2ARC’deki veri RAM’deki ARC içinde kayıtlar yaratıyor. Bir başka deyişle RAM’inizde bu kayıtlara ayırabildiğiniz yerle orantılı miktarda L2ARC kullanabiliyorsunuz. Bu yine deduplication’da olduğu gibi blok büyüklüğü ve kayıtların büyüklüğünü içeren bir hesaplama gerektiriyor.
ZFS ARC aynı zamanda sıralı veri transferlerini önbelleklemekten kaçınır. Sıralı veri transferleri sabit disklerin yeteri kadar iyi olduğu bir konudur; onlar rastgele erişimde zorlanırlar. Böylece önbellek olarak eklediğiniz SSD kendi güçlü yönü olan rastgele erişim ağırlıklı kullanılır, sabit diskten zaten hızlı okunan veriyle boşuna işgal edilmez.
ZFS Intent Log ve SLOG: ZFS nasıl yazar?
ZFS Intent Log’u (ZIL) anlatabilmek için programların sabit diske yazmakta kullandığı iki yöntemden bahsetmek gerek: Senkron ve Asenkron. Çok da zor değil aslında.
- Program, sabit diske kaydedilmek üzere gönderdiği verinin gerçekten kaydedildiği bilgisini beklemeden çalışmasına devam ediyorsa asenkron,
- Sabit diske kaydedilmek üzere gönderdiği verinin gerçekten kaydedildiği bilgisi gelmeden çalışmaya devam etmiyor, bekliyorsa senkron erişim sağlıyordur.
Asenkron erişim sağlayan programların kaydetmek istediği veri işletim sistemi tarafından bellekte tutulup uygun bir zamanda diske kaydedilebilir. Program bunu umursamaz. Ama senkron erişim sağlayan program kaç saniye sürerse sürsün sistemten “verini sağlam bir yere kaydettim devam et” bilgisini bekler. Veritabanları veya NFS gibi protokoller genelde senkron erişim tercih eder; yazacakları verinin RAM’de kalıp elektrik kesintisi gibi bir durumda kaybolmasını istemezler.
ZIL, sabit diskteki veri yapılarıyla uğraşmadan hızlıca kayıt yapmaya yarayan bir alan, bir tür not defteri olarak düşünülebilir. ZFS senkron erişim isteyen bir programın kaydedeceği veriyi RAM’de tutmanın yanısıra ZIL’e de kaydeder ve programa “veri yazıldı, sen devam et” sinyali gönderir. Böylece senkron yazma isteğinin “sağlam depolamaya kaydedilme” şartı sağlanmış olur.
Bu yazma istekleri nihai yerlerine belirli süre aralıklarıyla ulaşırlar (ZFSonLinux için 5 saniyede bir). ZFS biriken yazma isteklerini düzenleyip işlem grupları (transaction group) haline getirir. Bu şekilde sabit diske düzenli halde yazar.
İşte ZIL sadece o 5 saniye (veya sisteminizde kaç saniye olarak belirlenmişse o süre) için vardır. Bir elektrik kesintisi, ya da sistemin durmasına yolaçan başka bir arıza durumunda o son birkaç saniyelik veri RAM’deki diğer bilgilerle birlikte puf olabilir. Sistemin sonraki açılışında ZFS ZIL’i okur ve diske yazılacak veriyi “replay” eder. Dolayısıyla sistem normal çalıştığı sürece ZIL hiç okunmaz, sürekli olarak yazılır.
ZFS bu ZIL kaydını ayrı bir diske almaya olanak tanır. Bu ayrı diskteki alana SLOG, yani “Separate LOG” denir. Böylece senkron yazma isteklerinin yazıldı onayı daha kısa sürede gidecektir, bu da performans artışı demek. Esasında yük gören bir sistemde ZIL kayıtlarını ayrı ama mekanik bir diske almak bile fayda sağlayabilir. Ancak bu çağda hızlı SSD’ler kullanıyoruz tabii.
SLOG’u ZFS havuzunuza şöyle ekliyorsunuz:
zpool add tank log /dev/disk/by-id/diskin-kimligi
Gerçek örnekle:
zpool add tank log /dev/disk/by-id/ata-TOSHIBA_THNSNJ128GMCU_X42S1104TOGY
L2ARC’de olduğu gibi bunu da aynı sebepten disk kimliğiyle ekledik dikkat ederseniz (gerçek örnek dediğim komut tek satır, aman dikkat).
Gerçek ekran görüntümde de logs bölümünde görüyorsunuz.
SLOG’un boyutunu sizin arkaplandaki VDEV’lerinizin toplam yazma hızına göre belirliyorsunuz. Eğer standart kurulumla devam ediyorsanız muhtemelen 5 saniyede bir disklere aktarım olacak. Demek ki disklerinizin o 5 saniyede yazabileceği kadar SLOG alanı yaratmalısınız. Bu sistemde tek bir disk var (laptop ya 🙂 ), bu diski test ettiğimde 70-80MB/s gibi transfer hızları elde ettim. Yani 400-500MB kadar bir SLOG yeterliydi. Eğer bu diskten 2 tane olsaydı ve iki tane VDEV yapmış olsaydım toplam aktarım hızım 150MB/s gibi olacaktı, 5 saniyelik veri depolama için de 750-800MB gibi bir alan bırakmam gerekecekti. Yine de bu alanı biraz daha büyük tutmanızda fayda var.
ZIL’in sürekli yazma karakteristiğinden dolayı bu SSD’ye dikkat etmek gerek. Bir kere yazma hızı yüksek olmalı. Ayrıca sürekli yazma göreceğinden normale göre erken ölme olasılığı var. Tabii veri kaybı ihtimallerini en aza indirmek için güç kesildikten sonra SSD’nin kendi önbelleğinde veri kalmasın, kalıcı depolamaya yazılsın diye pil/süperkondansatör takviyeli de olabilir. Benim tavsiyem, eğer bütçe varsa batarya takviyeli bir SLC SSD.
Eğer bütçe yoksa, ekstra boş alan bırakılmış normal, tüketici sınıfı bir SSD de -erken değişimi göze alarak- kullanılabilir. Ekstra boş alan bırakma sebebiniz SSD’lerin belli bir yazma ömrü olması. Tüketici sınıfı SSD’ler MLC teknolojisiyle üretiliyor ve bunların ömrü SLC’lere göre daha da kısıtlı. MLC kullanıyorsanız SLOG’unuzu hesapladığınızın birkaç katı bırakın, hatta SSD’de %10-%20 gibi bölümlenmemiş alan bırakın. Siz yazdıkça yıpranan alanlar yerine SSD bu boşta bıraktığınız alanları kullanmaya başlayacak.