Saat 03:00, izleme sistemi "deferred queue > 5000" diye alarm veriyor. Nöbetteki mühendisin ilk refleksi neredeyse her zaman aynı: postfix flush. Bu tek komut, zaten bir sebepten teslim edilemeyen binlerce mesajı aynı anda active kuyruğuna alır, hepsini eşzamanlı retry'a sokar ve durumu düzeltmek yerine kötüleştirir. Alıcı MX'ler bu ani yükü görünce geçici hatayı (4xx) kalıcı rete (5xx) çevirir, greylisting sayaçları sıfırlanır, IP reputation'ınız düşer.
Deferred kuyruğunun dolu olması bir problem değildir; kuyruğun neden takıldığını bilmemek problemdir. Postfix'in kendi retry zamanlayıcısı çoğu geçici sorunu siz hiçbir şey yapmadan çözer. Flush, teşhisten sonra ve yalnızca doğru alt kümeye uygulanan cerrahi bir müdahaledir. Bu yazı o teşhis-müdahale zincirini komut komut kuruyor.
Deferred neden "dolu" değil, "takılı" — ilk 60 saniye
Panikten önce iki sayıyı ayırın: kuyrukta kaç mesaj var ve bunların kaçı aynı sebepten takılı. 8000 mesajın 50 farklı domain'e dağılmış olması ile hepsinin tek bir bozuk alıcı domain'de birikmiş olması tamamen farklı iki olaydır ve tamamen farklı müdahale gerektirir.
# Toplam kuyruk ve son özet satırı (byte + istek sayısı)
postqueue -p | tail -1
# active vs deferred hızlı sayım (disk üzerinden, qmgr'ı meşgul etmeden)
find /var/spool/postfix/active -type f | wc -l
find /var/spool/postfix/deferred -type f | wc -lactive kuyruğu qmgr tarafından bellekte tutulan, o an teslim denemesi yapılan mesajlardır ve qmgr_message_active_limit ile varsayılan olarak 20.000'e sınırlıdır. deferred ise en az bir kez başarısız olmuş, backoff zamanlayıcısını bekleyen mesajlardır. Deferred'ın büyümesi normaldir — asıl soru, büyümenin hızı ve tek bir sebebe mi bağlı olduğudur.
Refleks flush'ın neden zarar verdiğini üç maddeyle netleştirelim: thundering herd — binlerce eşzamanlı bağlantı hem sizin hem alıcının kaynağını tüketir; 4xx→5xx eskalasyonu — rate-limit uygulayan MX'ler agresif retry'ı abuse olarak yorumlar; greylist penceresinin sıfırlanması — bazı greylist implementasyonları erken denemede bekleme sayacını baştan başlatır, yani flush teslimatı hızlandırmaz, geciktirir.
Kuyruğu sınıflandırmak: qshape ve sebep dağılımı
qshape, Postfix kaynağıyla gelen ama çoğu dağıtımda postfix-doc paketinde ya da /usr/sbin altında duran bir Perl aracıdır. Kuyruğu domain × yaş matrisine döker ve "tek domain mi, yayılmış mı" sorusunu saniyeler içinde yanıtlar.
qshape deferred | head -20 T 5 10 20 40 80 160 320 640 1280 1280+
TOTAL 8042 3 7 12 41 88 190 402 690 980 5629
slowmx.example.com 7810 0 1 3 10 20 60 150 400 700 5466
gmail.com 61 1 2 4 8 15 20 11 0 0 0Satırlar alıcı domain, sütunlar dakika cinsinden yaş kovaları (5, 10, 20, 40 ... katlanarak artar), TOTAL en yaşlıdan en yeniye. Yukarıdaki tabloda hikâye tek bakışta okunuyor: 8042 mesajın 7810'u tek bir domain'de (slowmx.example.com) ve büyük kısmı 1280 dakikadan yaşlı — yani sorun sizin sunucunuz değil, o tek alıcıdır. Geri kalan trafik (gmail vb.) sağlıklı. Bu durumda genel flush felaket olurdu; doğru hamle o tek domain'i izole etmek.
Gönderen bazlı bakış, ele geçirilmiş hesap veya spam patlaması avlamak için birebirdir:
qshape -s deferred | headTek bir sender adresi kuyruğun yarısını oluşturuyorsa, elinizde deliverability sorunu değil, güvenlik olayı vardır.
Gerçek sebebi loglardan çıkarmak
qshape "kim" ve "ne kadar eski" sorularını yanıtlar; "neden" sorusu mail.log'da yaşar. status=deferred satırlarını sebep metnine göre gruplayan tek satırlık bir pipeline, dağılımı çıkarır:
grep 'status=deferred' /var/log/mail.log \
| grep -oP '\(.*\)$' \
| sed -E 's/[0-9]{2,}/N/g' \
| sort | uniq -c | sort -rn | headPratikte beş sınıfla karşılaşırsınız, her birinin ayırt edici imzası ve "flush işe yarar mı" cevabı farklıdır:
- DNS / MX çözümlenemiyor —
Host or domain name not found. Name service error for name=.... Resolver ya da alıcı DNS'i bozuk. Flush, resolver düzelene kadar anlamsız; düzeldikten sonra yararlı. - Greylisting —
450 4.2.0 ... greylistedveya421 4.7.0. Alıcı bilerek geciktiriyor. Pencere (tipik 300 sn) dolmadan flush işe yaramaz, sayacı sıfırlayabilir. Doğru davranış: bekle. - Alıcı rate-limit —
421 4.7.0 too many connections/try again later. Çok hızlı gönderiyorsunuz. Çözüm flush değil, tam tersi — yavaşlatma ve izolasyon. - TLS handshake —
Cannot start TLS: handshake failure. Sertifika/policy uyumsuzluğu. Config düzelmeden flush her seferinde aynı duvara toslar. - Loop / transport hatası —
mail for X loops back to myself. Yanlışmydestination
Bir de daha az görünen ama kritik olanı: 451 4.3.0 queue file write error — disk dolu ya da /var/spool/postfix izin sorunu. Bu tamamen kendi tarafınızdaki bir arızadır ve flush ile hiç ilgisi yoktur.
Tek mesajın iç hikâyesi: postqueue -j ve postcat
Sebep dağılımını çıkardıktan sonra tek tek mesajlara inmeniz gerekebilir. Postfix 3.1'den beri postqueue -j kuyruğu satır başına bir JSON nesnesi olarak döker; bu, jq ile filtrelemeyi mümkün kılar ve tüm seçici flush stratejisinin temelidir.
postqueue -j \
| jq -r '"\(.queue_id)\t\(.recipients[0].delay_reason // "-")"' | headBelirli bir mesajın tam envelope'ını ve son deferral sebebini görmek için postcat:
postcat -q 4F2aB7x3zKBu komut kuyruk dosyasını decode eder; en altta Postfix'in yazdığı son teslim denemesi sebebini bulursunuz. Bir mesajın gerçekten neden asılı kaldığını "tahmin etmeden" görmek istiyorsanız yer burasıdır.
Seçici flush: doğru alet, doğru kapsam
Aletleri karıştırmamak kritik, çünkü isimleri benzer ama davranışları farklı:
postqueue -f— tüm deferred'ı active'e alır. Bu, felaket komutudur; teşhis olmadan asla.postqueue -i QUEUEID— yalnızca tek mesajı flush eder.postqueue -s example.com— yalnızca tek hedef domain'i flush eder (klasiksendmail -qRkarşılığı). qshape'te tek domain sorununu çözdüyseniz doğru alet budur.postsuper -r QUEUEID— mesajı requeue eder: yeni bir queue ID alır vecleanup+header_checks'ten yeniden geçer. Transport map'i, header rewrite'ı ya da içeriği değiştirdiyseniz flush değil requeue gerekir, çünkü flush eski cleanup çıktısını yeniden dener.postsuper -dsiler,postsuper -h/-Hhold/release yapar.
Asıl güç, postqueue -j'nin çıktısını sebebe göre filtreleyip sadece ilgili alt kümeye işlem uygulamakta. Greylist sınıfı, penceresi dolduktan sonra topluca flush edilebilir:
# Yalnızca greylist kaynaklı mesajları flush et (pencere dolduysa)
postqueue -j \
| jq -r 'select(any(.recipients[]; (.delay_reason // "") | test("greylist"; "i"))) | .queue_id' \
| while read -r q; do postqueue -i "$q"; doneAynı deseni test("Name service") ile DNS sınıfına (resolver'ı düzelttikten sonra) ya da postsuper -r ile transport değiştirdiğiniz mesajlara uygulayabilirsiniz. Fark her zaman şudur: genel flush kör bir çekiçtir, jq ile filtrelenmiş flush neşterdir.
Kuyruğu izole tutmak: per-destination concurrency ve backoff
qshape'te gördüğümüz senaryoyu — tek slowmx.example.com bütün kuyruğu doldurmuş — kalıcı olarak çözmek için o domain'i ayrı bir transport'a alıp kendi concurrency ve rate limitleriyle kutuya koyarsınız. Böylece bozuk domain kendi kanalında beklerken sağlıklı trafik akmaya devam eder.
/etc/postfix/transport:
slowmx.example.com slow:/etc/postfix/master.cf (yeni transport tanımı):
slow unix - - n - 5 smtp/etc/postfix/main.cf:
transport_maps = hash:/etc/postfix/transport
slow_destination_concurrency_limit = 2
slow_destination_rate_delay = 5spostmap /etc/postfix/transport && postfix reloadBu üçlüyle o domain'e aynı anda en fazla 2 bağlantı ve her mesaj arası 5 saniye bekleme uygularsınız — rate-limit yiyen bir MX'i mutlu etmenin en temiz yolu budur.
Retry davranışını yöneten global parametreleri ve tipik değerlerini bilmek, "elle mi müdahale etmeli, Postfix'e mi güvenmeli" kararını netleştirir:
queue_run_delay = 300s— qmgr'ın deferred'ı ne sıklıkta tarayacağı.minimal_backoff_time = 300s,maximal_backoff_time = 4000s— bir mesajın retry aralığı bu iki değer arasında katlanarak büyür.maximal_queue_lifetime = 5d,bounce_queue_lifetime = 5d— bu süre sonunda mesaj bounce edilir.smtp_destination_concurrency_limit = 20,default_destination_rate_delay = 0(throttle gerekirse örn.1s).
Bu default'lar çoğu kurulum için doğrudur. Geçici bir sorunda hiçbir şey yapmazsanız, Postfix backoff eğrisini kendisi yürütür ve sorun çözülünce mesajlar teslim olur. Elle flush yalnızca sebep zaten çözülmüşse ve backoff bir sonraki denemeyi gereksiz yere geciktiriyorsa kazanç sağlar.
Pratik kontrol listesi
Flush tuşuna basmadan önce sırayla:
- Say ve ayır:
postqueue -p | tail -1+ deferred/active dosya sayımı. Büyüme hızlı mı, tek sebep mi? - qshape çek:
qshape deferred | head. Tek domain mi, yayılmış mı?qshape -sile gönderen bazlı kontrol (ele geçirilmiş hesap avı). - Logdan sebebi çıkar:
status=deferredsatırlarını sebebe göre grupla. Sınıfı belirle: DNS / greylist / rate-limit / TLS / loop. - Karar ağacını uygula:
- Tek domain kuyruğu kilitliyor →
transport_mapsile izole et, concurrency ve rate_delay ver. - Greylist → hiçbir şey yapma, pencere dolsun.
- DNS → resolver'ı düzelt, sonra
postqueue -s domainya da jq filtreli flush.
evilmail.pro'da temp-email ve transactional trafiği aynı Postfix üzerinden akarken en sık gördüğümüz arıza, tek bir yavaş alıcı MX'in bütün kuyruğu domino gibi kilitlemesidir. Çözüm hiçbir zaman genel flush olmadı; her seferinde qshape ile domain'i bulmak, transport'a izole etmek ve sağlıklı trafiği akar tutmak oldu. Flush bir buton değil, teşhis raporunun son satırıdır.


