Postfix Kuyruğunu Gerçek Zamanlı İzlemek: postfix_exporter, Prometheus ve Grafana ile Erken Uyarı Sistemi
Deferred kuyruğu ve reddetme oranı, bir teslimat sorununu alıcı tarafındaki reputation sistemleri fark etmeden 15-20 dakika önce haber verir. mailq'yu cron'la parse eden kırılgan script'leri bırakın; postfix_exporter + Prometheus + Grafana ile kuyruk derinliği, teslimat hızı ve reddetme oranını saniye bazında panolaştırın. Gerçek metric adları, gerçek systemd izinleri, gerçek PromQL ve gerçek eşiklerle çalışan bir kurulum.
EvilMail Team29 Temmuz 202610 dk okuma
Cuma gecesi saat 23:40. Upstream'deki bir DNS sağlayıcısı MX çözümlemesinde takılıyor, sizin smtp transport'unuz komşu domainlere bağlanamıyor ve normalde 200 mesaj civarında gezinen deferred kuyruğu sessizce 8.000'e tırmanıyor. Kimsenin haberi yok, çünkü elinizdeki tek gözlem aracı ekranın köşesinde açık duran bir watch mailq. Sabah bounce raporları geldiğinde iş işten geçmiş, birkaç büyük sağlayıcı IP'nizi throttle etmeye başlamış oluyor.
Buradaki asıl sorun teknik değil, yapısal: bir mail sunucusunun sağlığını anlatan üç metrik üç ayrı yerde yaşıyor. Kuyruk derinliği showq soketinde, teslimat hızı teslimat loglarında, reddetme oranı cleanup loglarında. Hiçbiri tek ekranda değil, hiçbiri geçmişe dönük değil, hiçbiri eşik geçince sizi uyandırmıyor. mailq | grep -c ile yazılmış cron script'leri bu üçünden yalnızca birini, o da anlık ve tarihsiz şekilde görebiliyor.
Çözüm bu üç kaynağı tek bir /metrics endpoint'inde birleştirmek. kumina/postfix_exporter tam olarak bunu yapıyor: showq soketini ve Postfix loglarını okuyup Prometheus'un anlayacağı sayaç ve histogramlara çeviriyor. Üstüne Grafana ve Alertmanager koyduğunuzda, deferred kuyruğu 500'ü geçtiği anda — reputation sistemleri daha farkına varmadan — telefonunuz çalıyor.
Exporter neyi, nereden okur
postfix_exporter'ın iki tamamen ayrı veri kaynağı var ve aralarındaki farkı anlamak panonuzun doğru okunması için kritik:
`/var/spool/postfix/public/showq` unix soketi — Postfix'in kuyruk yöneticisiyle aynı binary protokolü konuşur ve o an kuyrukta bekleyen her mesajın boyutunu ve yaşını verir. Bu anlık bir gauge: "şu anda deferred kuyruğunda 812 mesaj var". mailq'nun kaynağıyla aynı veri, ama metin parse etmeden.
Postfix logları — journald (--systemd.enable) ya da düz /var/log/mail.log. Exporter satırları izler ve olayları kümülatif sayaçlara çevirir: kaç mesaj teslim edildi, kaç tanesi reddedildi, kaç SASL auth denemesi başarısız oldu. Bunlar hep artan counter'lardır; anlamlı hale gelmeleri için rate() ile türevini almanız gerekir.
mailq çıktısını neden parse etmiyoruz? Çünkü showq binary protokolü hem daha ucuz hem de kırılmaz — Postfix sürümü kuyruk çıktısının formatını değiştirdiğinde script'iniz ölmez. Ve loglar olmadan reddetme/teslimat olaylarını hiç göremezsiniz; bunlar kuyrukta durmaz, akıp geçer.
Kurulum: binary, systemd unit ve izinler
Exporter Go ile yazılı, tek bir statik binary. Release'ten indirin ya da go build ile derleyin, sonra yerine koyun:
Kritik nokta izinler. Exporter'ın hem showq soketini okuması hem de journald'a erişmesi gerekir. showq soketi postfix grubuna, journald ise systemd-journal grubuna aittir. En temiz çözüm exporter'ı doğrudan postfix kullanıcısıyla çalıştırıp systemd-journal'ı ek grup olarak vermektir; böylece ayrı bir servis kullanıcısı için ACL uğraşına girmezsiniz:
--web.listen-address=127.0.0.1:9154 ile endpoint'i sadece localhost'a bağladık; Prometheus aynı makinede ya da tünel arkasında scrape etsin, dışarı asla açılmasın — metric'ler kuyruk içeriğine dair sinyaller ve SASL kullanıcı adları sızdırabilir. journald yerine düz log dosyası okuyacaksanız --systemd.enable'ı çıkarıp --postfix.logfile_path=/var/log/mail.log verin, ama o zaman exporter kullanıcısının o dosyayı okuyabildiğinden emin olun.
postfix_up 1 görüyorsanız iş tamam. 0 görüyorsanız ya soket izni ya journald grup üyeliği eksiktir; journalctl -u postfix_exporter size hangisi olduğunu söyler. En sık takılınan yer showq soketinin postfix grubuna kısıtlı olması — exporter'ı postfix kullanıcısıyla çalıştırmanızın sebebi tam olarak bu.
Prometheus'a bağlama ve saklama
scrape config sade. Kuyruk metrikleri düşük kardinaliteli olduğundan 15 saniyelik aralık hem yeterince granüler hem de sunucuya yük bindirmiyor:
postfix_up metriğini kendi scrape sağlığınız için de kullanın: exporter çökerse up{job="postfix"} == 0 olur ve bunu ayrı bir "exporter down" alarmıyla yakalarsınız — panonuzun kör kalmasını izleyen bir bekçi. showq histogramları üzerinde sık sorgu atacaksanız, ağır histogram_quantile hesaplarını bir recording rule ile önceden hesaplayın ki Grafana her yenilemede TSDB'yi baştan taramasın:
Exporter onlarca metrik üretir ama panonuz birkaç tanesinin etrafında döner. İşte gerçek adlarıyla önemli olanlar:
`postfix_showq_message_size_bytes` — showq'dan gelen histogram, queue label'ıyla (active, deferred, hold, incoming, maildrop). Kuyruktaki mesaj sayısı için histogram değerini değil _count son ekini kullanın: postfix_showq_message_size_bytes_count. Bu, en çok yapılan hatanın da cevabı — histogram'ın kendisi boyut dağılımıdır, sayım _count'tadır.
`postfix_qmgr_messages_removed_total` — kuyruk yöneticisinin mesajı kuyruktan kaldırması, yani başarılı teslimatın proxy'si. Teslimat hızınızın kalbi.
`postfix_cleanup_messages_processed_total` ve `postfix_cleanup_messages_rejected_total` — girişte işlenen ve reddedilen mesajlar. Reddetme oranının payı ve paydası.
`postfix_smtp_status_deferred` — giden teslimatta geçici hata (4xx) sayacı. Deferral hızının kaynağı.
`postfix_smtp_delivery_delay_seconds` — teslimat gecikmesi histogramı, stage label'ıyla alt aşamalara bölünmüş (before_queue_manager, queue_manager, connection_setup, transmission). p95 gecikmenizi buradan çıkarırsınız.
`postfix_smtpd_sasl_authentication_failures_total` — SASL auth başarısızlıkları; ani sıçraması bir credential-stuffing saldırısının habercisidir.
Bu metriklerin üçü bir arada bir mail sunucusunun anlık sağlığını tam olarak tarif eder ve ben buna sağlık üçgeni diyorum: derinlik (deferred kuyruğu ne kadar dolu), hız (saniyede kaç mesaj çıkıyor) ve red oranı (girişte ne kadar reddediyoruz). Üçü aynı anda kötüyse sunucu ölmüş demektir; biri bozulup diğerleri iyiyse elinizde spesifik bir teşhis vardır. Aşağıdaki diyagram her kuyruk geçişini onu ölçen metriğe bağlıyor:
Grafana panelleri ve PromQL
Beş panel bir mail sunucusunun tüm operasyonel hikâyesini anlatır. Hepsi doğrudan kopyala-yapıştır:
promql
# 1) Kuyruğa göre derinlik (time series, deferred/active stacked)
sum by (queue) (postfix_showq_message_size_bytes_count)
# 2) Teslimat hızı (mesaj/sn — time series)
sum(rate(postfix_qmgr_messages_removed_total[5m]))
# 3) Reddetme oranı (0-1 arası, stat panel, birim: percent 0.0-1.0)
sum(rate(postfix_cleanup_messages_rejected_total[5m]))
/ sum(rate(postfix_cleanup_messages_processed_total[5m]))
# 4) Deferral hızı (geçici hata/sn — time series)
sum(rate(postfix_smtp_status_deferred[5m]))
# 5) p95 teslimat gecikmesi (saniye — time series)
histogram_quantile(0.95,
sum(rate(postfix_smtp_delivery_delay_seconds_bucket[5m])) by (le))
Derinlik panelini queue label'ına göre stacked area yapın; deferred'ın active'in üstünde birikmesini görsel olarak yakalamak, sayının kendisinden daha hızlı alarm verir. Teslimat hızı ile deferral hızını aynı grafiğe koyun — biri düşerken diğeri yükseliyorsa hikâye netleşir. Reddetme oranını ve p95 gecikmeyi ekranın üstünde birer stat panel olarak tutun; renk eşiği koyup 0.20 ve 300s üstünde kırmızıya dönmelerini sağlayın, böylece panoya bakar bakmaz durumu okursunuz.
Alarm kuralları
Pano güzeldir ama kimse 7/24 ona bakmaz. Asıl iş alarmlarda ve for: sürelerinde — bir eşiğin anlık ihlali gürültüdür, süregelen ihlali olaydır. for: süresi flapping'i keser:
En değerli alarm PostfixQmgrStalled. Kuyruk doluyken teslimat hızının sıfıra düşmesi neredeyse her zaman yapısal bir arızadır: transport tıkanmış, DNS çözülmüyor ya da qmgr'ın process limiti dolmuş. for: 5m ile geçici bir dalgalanmayı olaydan ayırır. Bu kuralları Alertmanager'a bağlayıp severity: critical olanları Slack yerine gerçekten uyandıran bir kanala (PagerDuty, telefon) yönlendirin — cuma gecesi senaryosunu tam olarak bu yakalar.