Posta Sunucusu Kapasite Planlaması: Disk I/O, IOPS ve Eşzamanlı Bağlantı Tavanını Ölçmek
Bir posta sunucusunu ilk diz çöktüren şey CPU değil; fsync gecikmesi, mesaj başına write amplification ve süreç tavanıdır. Tahmin etmeyi bırakıp fio, iostat ve doveadm ile gerçek sayılar üreterek kaç mesaj/saniye ve kaç eşzamanlı oturum kaldırabileceğinizi hesaplayan pratik bir rehber.
EvilMail Team31 Temmuz 202610 dk okuma
8 vCPU, 32 GB RAM'lik bir sunucu %15 CPU'da tembel tembel otururken Postfix kuyruğu şişiyor, IMAP oturumları "timeout" hatasıyla düşüyor ve müşteriler "mail gelmiyor" diye yazıyor. top açtığınızda hiçbir çekirdek yorulmuş görünmüyor. Sorun burada değil. Sorun, her mesaj teslimatının diske senkron yazma yaptırması ve o diskin saniyede yapabileceği senkron yazma sayısının sert bir tavana çarpmış olması.
Kapasite planlamasında çoğu ekip önce CPU ve RAM'e bakar. Oysa bir posta sunucusunda darboğaz neredeyse her zaman iki yerdedir: disk I/O (özellikle fsync gecikmesi) ve eşzamanlı bağlantı tavanı. Bu yazıda "kaç kullanıcı kaldırır" gibi belirsiz soruyu bırakıp kapasiteyi ölçülebilir üç sayıya indirgeyeceğiz — sürdürülebilir fsync IOPS, mesaj başına write amplification ve süreç/bağlantı tavanı — ve bunları tahminle değil fio, iostat ve doveadm ile gerçek rakama çevireceğiz.
Neden CPU değil, fsync sizi öldürür
Maildir formatı her mesajı ayrı bir dosya olarak yazar. Teslimat sırası şu: mesaj
tmp/
altına yazılır,
fsync()
ile diske sabitlenir, sonra
new/
dizinine atomik
rename()
ile taşınır. Buradaki kritik nokta
fsync()
. Bu çağrı, veri fiziksel olarak kalıcı depoya inene kadar geri dönmez. Yani darboğazınız MB/s cinsinden throughput değil —
senkron, düşük queue-depth, rastgele yazma gecikmesi
.
Rakamlar acımasız. SATA SSD'de tek bir senkron fsync tipik olarak 1-2 ms sürer; bu da diski pratikte saniyede ~500-1000 fsync'e sıkıştırır. NVMe'de aynı işlem 50-200 µs civarındadır, yani ~5.000-20.000 fsync/s. Ceph veya EBS gibi ağ blok depoda ise her fsync bir ağ round-trip'i demektir; gecikme 5-10 kat kötüleşir ve yerelde 3000 fsync/s veren bir kurulum ağ diskinde 300-600'e düşebilir.
Dikkat edin: bunların hiçbiri CPU'yla ilgili değil. Sunucunuz boşta görünürken tavana çarpmanızın sebebi tam olarak bu. Kapasiteyi "kullanıcı sayısı" ile değil, "saniyedeki teslimat oranı × mesaj başına fsync sayısı" ile ölçmek zorundasınız.
İş yükünüzü ölçün: teslimat oranı, boyut, okuma/yazma dengesi
# Saat bazında başarılı teslimat histogramı (pik saati bul)
grep 'status=sent' /var/log/mail.log \
| awk '{print $3}' | cut -d: -f1 \
| sort | uniq -c | sort -rn | head
# Günlük genel özet
pflogsumm -d today /var/log/mail.log | head -40
İki şeyi not edin: pik saatteki teslimat/saniye ve peak-to-average oranı. Posta trafiği hiçbir zaman düz değildir; tipik peak-to-average oranı 3-5x'tir. Ortalamaya göre planlarsanız sabah 09:00 patlamasında kuyruk şişer. Her zaman pik üstünden, üstüne de tampon koyarak planlayın.
Mesaj boyutu profilini de çıkarın — ortalama değil, 95. persentil önemli. evilmail.pro'nun temp-email tarafı gibi write-ağırlıklı iş yükleri klasik mailbox'tan tamamen farklıdır: çok yüksek create oranı, düşük ve kısa ömürlü read, neredeyse hiç kalıcı arşiv. Bu profilde darboğaz okuma cache'i değil, saf yazma IOPS'udur; RAM eklemek hiçbir işe yaramaz.
Eşzamanlı IMAP oturumunu da canlı ölçün:
bash
doveadm who | wc -l # anlık aktif oturum sayısı
doveadm who | awk '{print $1}' | sort | uniq -c | sort -rn | head
Diskin gerçek fsync tavanını fio ile ölçmek
Depolama satıcısı "100k IOPS" yazar, ama o rakam yüksek queue-depth'te, asenkron, büyük bloklu okuma içindir. Sizin umursadığınız tek metrik senkron, fsync'li, iodepth=1 rastgele yazmadır — çünkü Maildir teslimatı tam olarak budur. Onu birebir taklit eden fio profili:
Çıktıda write: IOPS= satırına ve sync percentiles bloğundaki p99'a bakın. Bu IOPS değeri, o diskin gerçek teslimat tavanınızdır — pazarlama sayısı değil. IMAP fetch tarafını da ayrı ölçün, çünkü okuma profili tamamen başkadır:
bash
# IMAP fetch: büyük blok, derin kuyruk, rastgele okuma
fio --name=imap-fetch --rw=randread --bs=64k \
--size=2G --numjobs=4 --iodepth=16 --runtime=60 --time_based
Sonucu bir yere kaydedin. Bu sizin baseline'ınız. Disk değiştiğinde, sanallaştırma katmanı güncellendiğinde veya bulut sağlayıcı sessizce depolamayı downgrade ettiğinde bu baseline'ı tekrar koşup regresyon olup olmadığını anlarsınız. Ölçmediğiniz bir tavanı savunamazsınız.
Mesaj başına gerçek maliyet: write amplification
"Bir mesaj = bir yazma" sezgisi yanlıştır. Tek bir mantıksal mesaj disk seviyesinde 4-6 senkron yazmaya dönüşür. Yolu izleyelim:
Bu amplification faktörünü tahmin etmeyin, ölçün. Canlı teslimat oranını iostat ile karşılaştırın:
bash
iostat -x 1
w/s sütunundaki yazma IOPS'unu, aynı anda loglardan saydığınız teslimat/saniye ile bölün. 40 msg/s teslim ederken disk 200 w/s görüyorsa amplification faktörünüz 5'tir. w_await (yazma gecikmesi, ms) ve %util de burada kritik: %util sürekli %80'in üstündeyse disk bound'sunuz demektir, başka hiçbir metriğe bakmanıza gerek yok.
Amplification'ı düşürmenin en etkili yolu mdbox formatına geçmektir. mdbox birçok mesajı tek bir dosyada toplar, fsync sayısını ve inode baskısını ciddi biçimde azaltır. Bedeli var: tek dosya bozulması daha geniş etki yapar ve düzenli doveadm purge bakımı gerektirir. Yüksek yazma hacimli, kısa ömürlü trafikte bu takas neredeyse her zaman mdbox lehinedir.
İkinci sert duvar: eşzamanlı bağlantı tavanı
Diski hallettiniz diyelim. İkinci tavan bağlantı sayısıdır ve tamamen ayrı bir limittir. Postfix tarafında global default_process_limit = 100 vardır; master.cf'teki smtp/submission satırlarının maxproc sütunu bunu servis bazında ezer:
# master.cf — sütunlar: service type private unpriv chroot wakeup maxproc command
smtp inet n - y - - smtpd
submission inet n - y - 100 smtpd
Dovecot'ta tavanlar daha ince ayarlıdır:
service imap {
process_limit = 1024
}
service imap-login {
process_limit = 128
client_limit = 1000
service_count = 0 # login process'i yeniden kullan (performans)
}
mail_max_userip_connections = 10
Her bağlantının RAM maliyeti ve bir file descriptor tüketimi vardır. Sistem seviyesinde üç limit sizi keser: systemd'deki LimitNOFILE, kernel'deki fs.file-max ve ephemeral port aralığı net.ipv4.ip_local_port_range. Yüksek eşzamanlılıkta 28.000-32.000 bağlantı civarında port havuzu tükenir ve yeni bağlantı EADDRNOTAVAIL ile reddedilir.
Kritik ayrıntı: bu iki tavan birbirini besler. Bir IMAP login'i index dosyalarını açar ve bu açılış fsync tetikler. Yani bağlantı fırtınası aynı anda fsync fırtınasıdır. Disk fsync tavanınıza yakınken gelen bir bağlantı dalgası her iki limiti birden zorlar ve login'ler zaman aşımına uğrar — sabah gördüğünüz "timeout" tam olarak budur.
Örnek: fio'dan 3000 fsync/s ölçtünüz, amplification faktörünüz 5. Ham tavan 600 msg/s. Ama tavanı hedef almazsınız — peak-to-average 3x tampon bırakınca güvenli hedefiniz ~200 msg/s olur. IMAP eşzamanlılık tavanı ise RAM ve process_limit'in küçük olanından türer: bağlantı başına 8 MB RAM ve 8 GB ayrılmış bellek → ~1000 bağlantı, ama process_limit = 1024 bunu zaten sınırlıyorsa gerçek tavan 1024'tür.
Neden %100 değil de tampon? Çünkü gecikme doğrusal artmaz.
Tavanın %70'ini geçtiğinizde kuyruk teorisi devreye girer: küçük bir yük artışı p99 gecikmesini katlar. Bu yüzden %70'i alarm eşiği yapın, %85'i acil müdahale. Yatırım kararı da buradan çıkar: fsync bound iseniz (yüksek w_await, yüksek %util) çözüm daha hızlı disk — NVMe'ye geçiş veya index'i ayrı diske alma. Bağlantı bound iseniz (process_limit doluyor, fd tükeniyor) çözüm RAM ve limit ayarı; disk değiştirmek para yakmaktır.
Index'i mesaj gövdesinden ayırmak en yüksek getirili tek müdahaledir. dovecot.index* dosyaları küçük ama sık ve senkron yazılır; onları hızlı NVMe'ye taşıyıp gövdeyi ucuz diskte tutabilirsiniz:
İzlemediğiniz her metrik, gece 03:00'te bir müşteri "mail çalışmıyor" yazdığında öğrenilir. fio baseline'ı, iostat grafiği ve kuyruk alarmı üçlüsü, kapasite tavanını çarpmadan haftalar önce görmenizi sağlar. Bir posta sunucusunda "yeterince güçlü sunucu aldık" cümlesi hiçbir şey ifade etmez; anlamlı olan tek cümle "diskimiz N fsync/s yapıyor, mesajımız 5x amplify ediyor, %70 tamponla M msg/s hedefliyoruz"dur.