编程 mailq 里一堆 deferred 不是卡住:Postfix 的 300s/4000s 退避与 relayhost 单点吞吐

2026-11-07 00:04:42

Postfix 队列卡在 deferred:退避参数、relayhost 吞吐与 transport 分 lane

现象

新邮件迟迟进不了 active 队列,maillog 里同一批 queue ID 反复 deferred,所有投递进程都卡在连不可达站点上。容易走的弯路是把 queue_run_delay 调小,或者反复 postqueue -f。官方 TUNING_README 对此有明确警告:提高重试频率或频繁 flush deferred 队列,投递性能可能反而变差。

排查前先分清三件事:邮件是被 4xx 退避、被 5xx 退信,还是根本没建立起 SMTP 连接。

三类失败的处理路径

4xx(421/450/451/452,含灰名单):进指数退避循环,累计到 maximal_queue_lifetime(默认 5d)后退信。

5xx:通常直接对该收件人退信,不进退避。

连接层失败(TCP 超时、握手失败):不产生 4xx,走 default_destination_concurrency_failed_cohort_limit 的 dead 判定。该参数默认 1,只统计连接/握手失败,不统计 4xx,成功投递后计数重置。一个「伪队列」连接失败就可能把整个目的地判为 dead 并暂停投递。

另外 delay_warning_time 默认 0h,即不发「投递延迟」通知,发件人在第 5 天前收不到任何「已延迟」提醒;它不影响重试,也不影响队列寿命。

退避参数与默认值

参数默认值自 Postfix 2.4 起生效,2.4 之前 queue_run_delay 与 minimal_backoff_time 是 1000s。

参数默认值含义
queue_run_delay300sqmgr 扫描 deferred 队列的间隔
minimal_backoff_time300s一封 deferred 邮件最短冷却时间,也是不可达目的地留在 dead 列表的最短时间
maximal_backoff_time4000s投递失败后最长冷却时间
maximal_queue_lifetime5d临时错误累计超过该时长即判定不可投递并退信;设 0 表示首次失败立即退回
bounce_queue_lifetime5dMAILER-DAEMON 退信本身的存活时间
transport_retry_time60sqmgr 联系「故障的投递 transport 进程」的间隔,与 4xx 无关
qmgr_message_recipient_limit20000内存数据结构大小,同时限制短期 dead 目的地列表长度,装不下的目的地不进列表
delay_warning_time0h即不发投递延迟通知

约束关系:`queue_run_delay # 单封邮件的队列文件与最后一次失败信息
qshape deferred # 按域名与年龄看 deferred 分布
postqueue -f # flush,慎用
postsuper -r ALL # 重排队列并重置计时


配合 maillog 按 queue ID 追踪完整投递链路。

## 用 transport 分 lane

把 master.cf 的服务名当参数前缀,写在 main.cf:

```ini
# main.cf
smtp-fast_destination_concurrency_limit = 100
smtp-slow_destination_rate_delay = 20s
smtp-slow_destination_concurrency_failed_cohort_limit = 10

transport_maps 负责把收件地址映射到 (transport, next-hop)。并发与限速相关默认值:

  • initial_destination_concurrency 5:同一目的地初始并发,之后按 TCP 慢启动式反馈增长;
  • default_destination_concurrency_limit 20:同一目的地最大并发,smtp/lmtp/pipe/virtual 通用;
  • local_destination_concurrency_limit 2:同一本地收件人并发,投递到同一 mailbox 必须串行;
  • default_destination_recipient_limit 50:单次投递最大收件人数,设为 1 会把「目的地」从域名变成收件人,同时改变并发与 rate_delay 的语义;
  • default_destination_rate_delay 0s:同一目的地两次投递之间的延迟,非零时该 transport 实际按一封一封的节奏发出;
  • default_transport_rate_delay 0s(3.1+):不区分目的地,按整个 transport 限速,例如 smtp_transport_rate_delay = 20s 即每分钟最多 3 封;
  • default_destination_concurrency_failed_cohort_limit 1;
  • default_process_limit 100:投递进程总数上限;
  • qmgr_message_active_limit 20000:活跃队列上限。

官方提示:rate_delay 非零时应把 transport_destination_concurrency_failed_cohort_limit 设为 10 以上,避免一次连接错误就让该目的地所有邮件被 defer。rate_delay 的计时器由 qmgr 维护,状态不跨 postfix reload / stop。需要看细节时开 destination_concurrency_feedback_debug = yes。

边界说明

  • relayhost 单点 N=1 的换算是按官方公式推得,文档只给了 2 MX 的算例,实际吞吐还受对端限速、TLS 握手与 DNS 影响。
  • dead 列表长度受 qmgr_message_recipient_limit(20000)限制,装不下的目的地不会进列表,这条上限对大规模多目的地场景的实际影响需要在目标版本上实测。

文档:、、。

推荐文章

程序员茄子在线接单