Proxmox VE veya bare-metal sunucular üzerinde kurulan Ceph kümelerinde eski dosya tabanlı motor FileStore (XFS üzerine oturan yapı) terk edileli çok oldu. Yerini alan BlueStore, aradaki dosya sistemi katmanını kaldırarak doğrudan ham blok cihazlarla (raw block devices) konuşur.
Ancak All-Flash NVMe donanımlarla Ceph OSD’leri ayağa kaldırdığınızda sıkça karşılaşılan bir hayal kırıklığı vardır: Kağıt üstünde 800.000 IOPS sunan PCIe 4.0/5.0 kurumsal NVMe diskler, Ceph kümesinde 4K rastgele yazma testine sokulduğunda toplamda 40.000 – 60.000 IOPS bandında tıkanabilir. CPU kullanımı yükselir, ceph osd perf çıktısında commit süreleri 2-4 ms aralığına çıkar.
Bu darboğazın temel kaynağı Ceph’in altındaki RocksDB / WAL mimarisi ve BlueStore’un varsayılan tekil iş parçacığı (single-thread / lock contention) modelidir. Bugünkü yazımızda, BlueStore’un veri yolundaki gizli kilitleri ve NVMe hızlarını yakalamak için uygulanması gereken çekirdek parametrelerini inceliyoruz.
1. BlueStore Veri Yolu: Veri Nereye, Meta Veri Nereye Yazılır?
BlueStore disk alanını üç mantıksal bölüme ayırır:
- Veri (Data): Sanal makinelerden veya nesne depolamadan gelen asıl yük. Doğrudan diske Copy-on-Write (CoW) mantığıyla yazılır.
- RocksDB Meta Verisi: Nesne adları, konum haritaları, anlık görüntü (snapshot) ağaçları ve allokasyon tabloları.
- RocksDB WAL (Write-Ahead Log): Meta veri ve küçük I/O yazmalarının önce sıralı olarak yazıldığı günlük alanı.
[Gelen 4K Yazma İsteği]
│
├───> [Veri > min_alloc_size] ───> Doğrudan NVMe Bloklarına (Data Allocation)
│
└───> [Küçük Yazma / Meta Veri] ─> RocksDB WAL (Sync Flush) ──> RocksDB SST ──> NVMe
A. min_alloc_size Tuzağı
BlueStore, diske veri ayırırken (allocation) minimum bir blok boyutu belirler.
- HDD için varsayılan: Genellikle 64 KB
- Flash / NVMe için varsayılan: 4 KB
Eğer kurulum sırasında disk tipi yanlış algılanır veya bir havuz HDD parametreleriyle Flash üzerinde açılırsa (min_alloc_size = 64k), uygulamanızın yaptığı 4 KB’lık her yazma işlemi için diskte 64 KB alan bloke edilir. Bu durum hem aşırı alan israfına (slack space) hem de devasa bir yazma yükseltmesine (Write Amplification) sebep olur.
Mevcut OSD’lerinizin minimum blok tahsis boyutunu doğrulamak için:
# Canlı bir OSD'nin (örneğin osd.0) tahsis boyutunu sorgulayın
ceph daemon osd.0 config get bstore_min_alloc_size_ssd
# Çıktı: "bstore_min_alloc_size_ssd": "4096" olmalıdır.
2. RocksDB WAL ve DB Boyutlandırması
Karma (Hybrid) kümelerde (HDD verisi + NVMe WAL/DB) veya SATA SSD verisi + NVMe WAL yapılarında, RocksDB’nin boyutu yetersiz tanımlanırsa RocksDB SST tabloları yavaş olan ana veri diskine taşar. Bu durum kümenin performansını anında en yavaş bileşenin hızına kilitler.
- Altın Kural: OSD başına ayrılacak RocksDB alanı en az 30 GB (tercihen 60-100 GB) olmalıdır.
- NVMe All-Flash Kümeler: Eğer OSD’nin tamamı NVMe ise WAL, DB ve Data aynı disk üzerindedir. Burada kritik olan ayrılmış disk alanı değil, RocksDB’nin bellek önbelleğidir.
RocksDB Sıkıştırma ve Yazma Tamponları (ceph.conf):
RocksDB yoğun rastgele yazma altında memtable (RAM’deki yazma tamponu) doldurur ve diske L0 SST dosyaları olarak döker. Varsayılan ayarlar modern çok çekirdekli işlemcilerde yetersiz kalır:
[osd]
# RocksDB'nin aynı anda kullanabileceği arka plan birleştirme (compaction) thread sayısı:
rocksdb_compaction_threads = 4
rocksdb_flusher_threads = 2
# Memtable boyutunu büyütün (64MB -> 256MB)
bstore_rocksdb_write_buffer_size = 268435456
bstore_rocksdb_max_write_buffer_number = 6
3. OSD Thread Sharding ve CPU Kilitlenmelerini Çözmek
Geleneksel Ceph sürümlerinde her OSD, I/O isteklerini işlemek için tek bir ana döngü ve kilit (mutex) kullanırdı. 64 çekirdekli modern AMD EPYC veya Intel Xeon sunucularda tek bir OSD sürecinin (ceph-osd) tek bir CPU çekirdeğini %100 doldurarak darboğaza girmesinin nedeni budur.
Modern Ceph sürümlerinde (Quincy, Reef ve sonrası) Sharded OSD I/O Threads mimarisi mevcuttur.
A. OSD İş Parçacığı (Op Threads) Ayarı
Yüksek IOPS hedefleyen NVMe düğümlerinde OSD başına çalışan I/O kuyruk iş parçacığı sayısını artırmak gerekir:
# OSD worker thread sayısını CPU çekirdek sayısına göre optimize edin (Örn: 8 worker)
ceph config set osd osd_op_num_shards 8
ceph config set osd osd_op_num_shards_hdd 5
ceph config set osd osd_op_num_threads_per_shard 2
B. Allocator Seçimi: bitmap vs. hybrid
BlueStore, diskin neresinin boş neresinin dolu olduğunu takip etmek için bir Allocator kullanır.
- bitmap (Eski): Çok yüksek bellek tüketir ve yüksek IOPS altında kilitlenme (lock contention) yaşar.
- hybrid / avl (Modern & Önerilen): Boş alanları AVL ağaç yapısında tutarak bellek kullanımını minimize eder ve mikrosaniyelik tahsis sağlar.
[osd]
# NVMe diskler için en verimli tahsis motoru
bstore_allocator = hybrid
4. Ceph BlueStore Önbellek İnce Ayarı (osd_memory_target)
Daha önceki yazımızda bahsettiğimiz gibi BlueStore işletim sistemi Page Cache’ini kullanmaz; kendi DRAM önbelleğini yönetir. Ancak bu önbelleğin Data ve Meta veri (Kv / RocksDB) arasındaki dağılım oranı performansı doğrudan belirler.
NVMe All-Flash bir kümede meta verinin (indekslerin) her zaman RAM’de kalması, gerçek veri bloklarının ise doğrudan NVMe’den okunması hedeflenir:
[osd]
# OSD başına toplam bellek hedefi (Örn: 8 GB)
osd_memory_target = 8589934592
# Otomatik önbellek dengeleyici açık olmalı
bstore_cache_autotune = true
# Önbelleğin en az %40'ını doğrudan RocksDB meta verisine (KV cache) ayır:
bstore_cache_kv_ratio = 0.4
bstore_cache_meta_ratio = 0.4
Bu sayede bir nesne okumak veya yazmak istendiğinde RocksDB B-Tree aramaları doğrudan RAM’den mikrosaniyeler içinde çözülür; NVMe diske sadece asıl veri I/O’su için gidilir.
Günün CLI İpucu: BlueStore Yavaşlıklarını ve Kilit Sürelerini Canlı Yakalamak
Bir OSD’nin diske mi takıldığını yoksa RocksDB commit kuyruğunda mı beklediğini anlamak için doğrudan soket üzerinden performans sayaçlarını dökebilirsiniz:
# osd.0'ın BlueStore iç gecikme sayaçlarını JSON olarak çekin
ceph daemon osd.0 perf dump | jq '.bluestore'
Hangi değerlere bakmalısınız?
- kv_commit_lat: RocksDB’nin diske meta veri yazarken harcadığı ortalama süre. NVMe disklerde bu değer 1000 µs (1 ms) altında olmalıdır. Eğer 5-10 ms görüyorsanız,
rocksdb_write_buffer_sizeveyamin_alloc_sizeparametrelerinizde sorun var demektir. - state_deferred_cleanup: Ertelenmiş yazma kuyruğu. Sıfıra yakın kalmalıdır; aksi halde OSD arkadan gelen yükü yetiştiremiyordur.