跳转到主要内容

于 2025年04月22日 摘录自 Postfix Connection Cache

简介

本文档描述了 Postfix 连接缓存的实现,该功能自 Postfix 2.2 版本起可用。

本文档涵盖的主题:

SMTP 连接缓存能为您带来什么

通过 SMTP 连接缓存,Postfix 可以通过同一 SMTP 连接发送多条消息。默认情况下,Postfix 2.2 会自动复用一个明文 SMTP 连接,当目标的 活动队列 中邮件量较大时。

SMTP 连接缓存是一项性能优化功能。其实际性能提升效果取决于具体条件:

  • 当向拥有多个邮件服务器的目的地发送邮件时,SMTP 连接缓存可显著提升性能,因为它能帮助 Postfix 跳过未响应的服务器。
  • SMTP 连接缓存还能帮助应对对新连接设置速率限制的接收方。
  • 否则,SMTP 连接缓存的优势微乎其微:它消除了 TCP 握手(SYN、SYN+ACK、ACK)的延迟,以及 SMTP 初始握手(220 问候、EHLO 命令、EHLO 响应)的延迟。对于 TLS 加密连接,这可额外节省两个往返时间,否则需要发送 STARTTLS 并恢复 TLS 会话。
  • SMTP 连接缓存对 SMTP 会话关闭没有提升。Postfix 的 smtp(8) 客户端通常不会等待服务器对 QUIT 命令的响应,也不会等待 TCP 最终握手完成。
  • SMTP 连接缓存会引入一些开销:客户端需要发送一个 RSET 命令来确定连接是否仍可使用,然后才能发送下一个 MAIL FROM 命令。这会引入一次额外的往返延迟。

有关 SMTP 连接缓存的其他潜在问题,请参阅本文末尾的 限制 部分。

连接缓存实现

有关 Postfix 邮件投递的概述,请参阅 Postfix 架构 OVERVIEW 文档。

Postfix 连接缓存由 Postfix 邮件投递进程共享。这最大限度地提高了重用打开连接的机会。某些 MTA(如 Sendmail)具有非共享连接缓存。在此情况下,连接只能由创建该连接的邮件投递进程重用。为了获得与共享连接缓存相同的性能提升,非共享连接需要保持打开状态更长时间。

scache(8) 服务器(在 Postfix 2.2 版本中引入)维护共享连接缓存。在 Postfix 2.2 版本中,仅 smtp(8) 客户端支持访问此缓存。

当启用 SMTP 连接缓存(见下一节)时,smtp(8) 客户端在邮件传输完成后不会断开连接,而是将连接交由 scache(8) 服务器,该服务器会保持连接打开一段时间。

在将打开的连接交由scache(8)服务器后,smtp(8)客户端将继续处理其他邮件投递请求。同时,任何smtp(8)客户端进程都可以向scache(8)服务器请求该缓存连接并重复使用它进行邮件投递。

 /-- smtp(8)--> Internet
qmgr(8) |
|
|
|
v
 \-- smtp(8) 
  ^
|
 scache(8)

使用 TLS 连接重用(Postfix 3.4 及更高版本),Postfix smtp(8) 客户端连接到远程 SMTP 服务器并发送明文 EHLO 和 STARTTLS 命令,然后将 tlsproxy(8) 进程到连接中,如下所示。

发送邮件后,smtp(8) 客户端将打开的 smtp(8)-to-tlsproxy(8) 连接给 scache(8) 服务器,并继续处理其他邮件投递请求。同时,任何 smtp(8) 客户端进程都可以向 scache(8) 服务器请求该缓存连接并重复使用它进行邮件投递。

 /-- smtp(8)--> tlsproxy(8)--> Internet
qmgr(8) |
|
|
|
v
 \-- smtp(8) 
  ^
|
 scache(8)

连接缓存可通过目标域名(收件人地址的右侧)或连接另一端主机的 IP 地址进行搜索。这使 Postfix 即使在远程主机是不同域名邮件服务器时也能复用连接。

连接缓存配置

Postfix smtp(8) 客户端支持两种连接缓存策略:

连接缓存安全机制

连接缓存必须谨慎使用。长时间保持未使用的 SMTP 连接打开是不礼貌的,通过同一连接发送大量消息也是不明智的。为了避免 SMTP 连接缓存问题,Postfix 实现了以下安全机制:

  • Postfix 的 scache(8) 服务器仅在有限时间内保持连接打开。时间限制通过 smtp_connection_cache_time_limitconnection_cache_ttl_limit 配置参数指定。这可防止恶意行为。
  • Postfix 的 smtp(8) 客户端仅在有限次数内重用会话。这避免了在无法正确处理单个会话中多次投递的实现中触发错误。

    从 Postfix 2.3 开始,建议使用 smtp_connection_reuse_time_limit 参数限制连接复用。此外,Postfix 2.11 提供了 smtp_connection_reuse_count_limit 限制连接可被重用的次数,但此功能存在安全隐患,因为它会引入"致命吸引子"故障模式(当目标有两个或更多入站 MTA 时,最慢的入站 MTA 会吸引 Postfix 的大部分连接到该目标)。

    Postfix 2.3 会记录多次使用的连接使用计数,如下例所示:

    Nov 3 16:04:31 myname postfix/smtp[30840]: 19B6B2900FE:
    to=<[email protected]>, orig_to=<wietse@test>,
    relay=mail.example.com[1.2.3.4], conn_use=2, delay=0.22,
    delays=0.04/0.01/0.05/0.1, dsn=2.0.0, status=sent (250 2.0.0 Ok)
  • 连接缓存会显式标记每个缓存连接的目标域名和 IP 地址信息。连接缓存查找仅在指定正确信息时成功。这可防止邮件误送。

连接缓存限制

Postfix SMTP 连接缓存与某些应用程序冲突:

  • 在 Postfix 版本 <3.4 中,Postfix 共享连接缓存无法与 TLS 一起使用,因为打开的 TLS 连接只能在创建它的进程中重用。因此,Postfix smtp(8) 客户端在通过 TLS 尝试投递邮件后,历史上有关闭连接的习惯。
  • Postfix 连接缓存目前不支持每个邮件服务器使用多个 SASL 账户。具体来说,Postfix 连接缓存假设 SASL 凭据对通过同一邮件服务器 IP 地址和 TCP 端口发送邮件的所有主机名或域名均有效,且假设 SASL 凭据不依赖于消息发送者。

连接缓存统计信息

scache(8) 连接缓存服务器记录关于缓存峰值大小和缓存命中率的统计信息。这些信息每 connection_cache_status_update_time 秒记录一次,当进程在最大空闲时间后终止时,或当 Postfix 重新加载时。

  • 按域的连接缓存查找命中率将告诉您连接缓存的有用性。
  • 按网络地址的连接缓存查找始终会失败,除非您正在向共享相同 MX 主机的不同域发送邮件。
  • 当未尝试访问连接缓存时,不会记录任何统计信息。