摘要
运行 Sendmail 的服务器群集能够在有竞争力的价格上提供高性能和高可用性。对于经验丰富的系统管理员,这一贯是常用的做法。本文描述了我们的研究,量化和描述实现高可用/可伸缩 Sendmail 的方法。(2002-10-09 14:19:17)
By 风过留枫
关于作者
Jay D. Allen 白天在 IBM 从事于 IT 前沿技术,主要是使用 Linux。夜里,Jay 研究 IT 领域的一些没落技术,主要是使用 DEC PDP-11 和其它古董技术。可以通过 allen5@us.ibm.com 与他联系。
自 1992 年以来,Peter Bogdanovic 一直是一位软件工程师和 Unix 系统管理员。他目前在 IBM 的 Linux Competency Center 工作。可以通过 bognovic@us.ibm.com 与他联系。
Clifford White 是 IBM 的解决方案工程师,在 IBM 的 Linux Competency Center 工作。可以通过 cliffw@us.ibm.com 与他联系。
-------------------------------------------------
运行 Sendmail 的服务器群集能够在有竞争力的价格上提供高性能和高可用性。对于经验丰富的系统管理员,这一贯是常用的做法。本文描述了我们的研究,量化和描述实现高可用/可伸缩 Sendmail 的方法。
我们研究了 Linux 上 Sendmail 群集的几种配置,并对它们的相对性能进行了量化。我们通过调整 Sendmail 的配置以及 Linux 操作系统中的参数,研究并测试了公共性能。我们还没有一个共享磁盘用于这些测试,因此我们将项目的范围限定在只包括 SMTP 路由和排队。这是位于专用网的边缘或作为内部邮件存储的前端的 Sendmail 群集的常用配置。
虽然我们的硬件资源很普通,但我们相信这些相对差异会使我们的结果对于那些要实现基于 Linux 的 Sendmail 服务器群集的系统架构设计师是非常重要的,因为我们的结果说明了 Sendmail 群集的设计特性的相对重要性。
汇总结果
Sendmail、LDAP 和 DNS 有许多配置选项,但我们只考虑那些对于该应用程序很重要的选项。除非另有声明,否则我们使用标准软件和缺省设置。在这些选项中,我们发现有少数因素可以对性能产生巨大影响,或者是实现可伸缩性必不可少的,如 LogLevel 和 QueueDirectory。
最后,我们发现即使正确配置了 Sendmail,所有这些重要因素也会告诉我们两个事实:
Sendmail 是磁盘密集型的,磁盘速度越快,Sendmail 的速度就越快。
不受控因素也许会影响我们所感知到的性能。如,远程 DNS 服务器发生故障,路由失常、队列填满和其它第三方问题。
我们发现了什么
集群的服务器。通过集群两个服务器并在前端添加负载均衡器,我们发现了最佳消息吞吐量 — 大约每秒 100 条消息。这是最佳单服务器结果的性能的两倍,单服务器的最佳性能大约是每秒 50 条消息。当添加第三个服务器时,几乎看不到性能有所改进。
LogLevel。由于 Sendmail 日志记录的用途有时象审计跟踪,它显示了 SMTP 邮件的进入和外出,因此从磁盘 I/O 的角度来看,日志记录的代价比较昂贵。在某些情况下,允许或者应该关闭此审计功能,以便提供更高的吞吐量。但即使启用了完全日志记录(LogLevel 9),只要将日志文件移到更快的文件系统上,我们仍可以得到可接受的性能。
QueueDirectory。队列目录也是一个明显的争用点。通过使用多个队列以及将 QueueSortOrder 切换成文件名,我们找到了最佳性能。LogLevel 和 QueueDirectory 在使吞吐量增加中共同起着举足轻重的作用。
其它配置选项。我们还测试了关闭 Ident 查找、对于工作负载使用 SharedMem 键和传递模式(Delivery Mode)。这些的作用很小,但我们假设在真正的方案中它们也许会更重要。
OS。我们的 Linux 安装要求做很少的更改,它基本上是标准 Red Hat 7.1 并附带标准 kernel.org 2.4.4 内核。
网络。我们找出了一些网络问题,但在更改了简单的运行时配置之后已经解决了这些问题。注:我们没有尝试网络 syslog 程序(syslogger)。
测试方案
我们评估了几种测试方案:
单服务器
循环 DNS
负载均衡器
基于 MX 的故障转移
对于负载均衡器方案,我们尝试了 Alteon 180 设备和运行均衡软件的专用 Linux 服务器。我们使用一台主机逐一调整重要的配置因子来寻找最优的 Sendmail 配置。通过使用此测试的结果,我们得到了最优化的配置,并将它用于其它不同的群集配置中。
循环 DNS
DNS 循环是将多路到来的因特网 SMTP 流量分配到多台机器上的一种简单方法。在其最简单的形式中,针对某一个邮件服务器主机名,会输入几个 A 记录。每个参与的 Sendmail 服务器都被配置成以这个主机名的名义接收邮件。当发送方要将邮件传递给接收方时,就生成了一个 DNS 查询。其结果将包含该主机的所有 A 记录的列表。缺省情况下,大多数 MTA 实现会采用列表中的第一个成员。同一主机名的重复查询会产生 IP 地址的循环列表(这是 BIND/DNS 的一个特性)。例如,如果在因特网上查找名称“us.ibm.com”,会返回以下 IP 地址列表:
Name: www.ibm.com
Addresses: 129.42.16.99, 129.42.17.99, 129.42.18.99, 129.42.19.99
重复查询,返回:
Name: www.ibm.com
Addresses: 129.42.19.99, 129.42.16.99, 129.42.17.99, 129.42.18.99
再查询一次,返回:
Name: www.ibm.com
Addresses: 129.42.17.99, 129.42.18.99, 129.42.19.99, 129.42.16.99
在图 1 中,我们看到一个循环 DNS 正在运行。Sendmail 服务器的所有外部接口都直接连接到因特网,并且在 DNS 中发布。每台机器都充当 SMTP 路由器/缓冲器,从因特网获取邮件并将邮件传递到专用网上的某种公共邮箱服务器。这种方案很容易实施,而且很便宜,如果正确实施,它可以是无故障的。
图 2 说明了使用循环 DNS 的问题。由于 DNS 的工作方式和高速缓存 DNS 记录的可能性,如果某台主机发生故障,邮件代理也许仍会尝试联系它。至少,邮件会被延迟,一直等待连接超时,然后被排入队列,并在补偿时间之后重新发送。
500) {this.resized=true; this.width=500;}" onmouseover="this.style.cursor='hand'" onclick="{window.open('http://www.linuxaid.com.cn/articles/3/4/344938498/fig1_small.gif');}" src="http://www.linuxaid.com.cn/articles/3/4/344938498/fig1_small.gif" onmousewheel="return bbimg(this)" width=256
图 1
500) {this.resized=true; this.width=500;}" onmouseover="this.style.cursor='hand'" onclick="{window.open('http://www.linuxaid.com.cn/articles/3/4/344938498/fig2_small.gif');}" src="http://www.linuxaid.com.cn/articles/3/4/344938498/fig2_small.gif" onmousewheel="return bbimg(this)" width=256
图 2
负载均衡器
在最近几年,越来越多地使用了外部的工作负载导向器。这些专用设备可以在几个服务器之间巧妙地分配工作负载,以及处理故障转移/故障恢复。我们对 Alteon 180 交换机进行了大量测试。它允许我们创建虚拟邮件服务器。到达此虚拟服务器的邮件被循环传送到这三个真正的服务器中的每一个。如果其中一个 Sendmail 服务器由于某种原因发生故障,Alteon 将停止发送新连接到该服务器(定期检查该服务器是否已恢复)。
这种配置的优点之一就是它不具有循环 DNS 解决方案的缺点。由于只向全球公布一个 IP 地址,因此当添加/除去群集的成员时,没有理由担心高速缓存的项。由使用诸如 Alteon 180 和 F5 Network 的 Big-IP 之类产品所知,这种做法通常是切实可行的。但是,该设备可能非常昂贵,此外当然会增加另一个维护点。要提供最大保护并且避免单点故障,应该至少安装两个这样的设备。
500) {this.resized=true; this.width=500;}" onmouseover="this.style.cursor='hand'" onclick="{window.open('http://www.linuxaid.com.cn/articles/3/4/344938498/fig3_small.gif');}" src="http://www.linuxaid.com.cn/articles/3/4/344938498/fig3_small.gif" onmousewheel="return bbimg(this)" width=256
图 3
500) {this.resized=true; this.width=500;}" onmouseover="this.style.cursor='hand'" onclick="{window.open('http://www.linuxaid.com.cn/articles/3/4/344938498/fig4_small.gif');}" src="http://www.linuxaid.com.cn/articles/3/4/344938498/fig4_small.gif" onmousewheel="return bbimg(this)" width=256
图 4
基于 MX 的故障转移
这是传统的 Sendmail/DNS 配置。DNS 中的主机名可以有一个或多个邮件交换(MX)记录。这些记录包括一个加权因子。当其它 SMTP 服务器试图将邮件传递到此主机时,它们首先寻找 MX 记录及其对应权重。当有多个 MX 记录时,会选择具有最低权重值的 MX 记录。邮件将被传递到第一个主机(该主机应答时,具有最低权重/数字)。
在下例中,某个域具有两个 MX 记录,一个指向芝加哥办事处,权重为 10,另一个指向纽约办事处,权重为 20。在正常情况下,所有邮件都会经过芝加哥办事处,流经公司的 WAN,进行内部传递。
如果芝加哥办事处发生故障,或者到芝加哥办事处的路由发生故障,邮件将自动经由纽约办事处传递。
如果芝加哥办事处在 SMTP 事务中发生故障,那么该事务就会失败(红线)。由于 SMTP 是一个事务,因此保证了消息完整性,发送方将超时、回退,并在以后重新发送整条消息。如果芝加哥办事处仍然停机,邮件会自动流经纽约办事处。
这种方法的主要优点是它是一种非常成熟的过程,有完善的文档,易于理解。另外,它只需要做少量的配置变动,而且不需要附加软件或硬件。遗憾的是,工作负载没有被平均分配,因此实际上在重负载情况下,服务也许会前后“变化不定”。MX 解决了可用性问题,但没有解决可伸缩性问题。其结果就是为了解决在高峰流量负载期间可能发生的故障,您最终要购买双份硬件。
500) {this.resized=true; this.width=500;}" onmouseover="this.style.cursor='hand'" onclick="{window.open('http://www.linuxaid.com.cn/articles/3/4/344938498/fig5_small.gif');}" src="http://www.linuxaid.com.cn/articles/3/4/344938498/fig5_small.gif" onmousewheel="return bbimg(this)" width=256
图 5
500) {this.resized=true; this.width=500;}" onmouseover="this.style.cursor='hand'" onclick="{window.open('http://www.linuxaid.com.cn/articles/3/4/344938498/fig6_small.gif');}" src="http://www.linuxaid.com.cn/articles/3/4/344938498/fig6_small.gif" onmousewheel="return bbimg(this)" width=256
图 6
混合/实际情况
实际解决方案趋向于上述所有技术的混合。例如,发送到 IBM 的因特网邮件被传递到以下三个地区中心之一:科罗拉多州、纽约州和北卡罗莱纳州。通过将用于故障转移的 MX 记录和循环 DNS 组合在一起,IBM 保证了快速/可靠的因特网邮件。以下是公开 DNS 记录:
us.ibm.com preference = 10, mail exchanger = e22.nc.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e23.nc.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e24.nc.us.ibm.com
us.ibm.com preference = 20, mail exchanger = e1.ny.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e2.ny.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e3.ny.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e4.ny.us.ibm.com
us.ibm.com preference = 20, mail exchanger = e31.co.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e32.co.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e33.co.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e34.co.us.ibm.com
us.ibm.com preference = 20, mail exchanger = e21.nc.us.ibm.com
重复的 DNS 查询生成了 MX 首选项的循环列表:
us.ibm.com preference = 10, mail exchanger = e2.ny.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e3.ny.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e4.ny.us.ibm.com
us.ibm.com preference = 20, mail exchanger = e31.co.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e32.co.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e33.co.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e34.co.us.ibm.com
us.ibm.com preference = 20, mail exchanger = e21.nc.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e22.nc.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e23.nc.us.ibm.com
us.ibm.com preference = 10, mail exchanger = e24.nc.us.ibm.com
us.ibm.com preference = 20, mail exchanger = e1.ny.us.ibm.com
结果
单个 SMTP 服务器
测试名称
队列位置
LogLevel
ShareMem
Ident
传递方式
提交秒数
stmpa-def
磁盘
9
否
是
异步
8.4
smpta-interactive
磁盘
9
否
是
交互式
10.0
smpta-noident
磁盘
9
否
否
交互式
9.7
smpta-sharedmem
磁盘
9
是
是
交互式
9.8
smpta-log4
磁盘
4
否
是
交互式
24.2
smtpa-ramdisk
RAM
9
否
是
交互式
19.4
smtpa-ramdisk-log4
RAM
4
否
是
交互式
48.4
smtpa-ramlog9
磁盘
9
否
是
交互式
25.8
smtpa-freshlog9
磁盘
9
否
是
交互式
10.1
smtpa-toeleven
RAM
9
是
否
交互式
49.0
由 MailStone 报告的单服务器解决方案的连接错误百分率始终是 0.0
多个 SMTP 服务器
对于多服务器测试,我们只使用单服务器测试的最高性能组合,观察当添加服务器时,其规模是如何增长的。对于所有多服务器测试,选项是:
RAM 上的队列
RAM 上的 LogLevel 9
启用共享内存
禁用 Ident
传递方式设置成交互式
测试名称
循环设备
服务器数量
提交数/秒
连接错误
bigmail2-allram
Alteon
2
95.9
43.1%
balance2-allram
Balance
2
74.6
30.1%
bigmail3-allram
Alteon
3
102.8
87.8%
balance3-allram
Balance
3
103.8
81.4%
结束语
通过使用现成的计算机设备,我们演示了可以构建高性能、高可用的 Sendmail 服务。在我们的测试中,磁盘 I/O 是 Sendmail 系统的总体性能中最重要的因素。将服务器配置成不记录日志,或者将日志记录到 RAM 磁盘,会大大提高性能。另外,邮件队列也是 Sendmail 服务器进程中另一个磁盘密集型的部分。将队列分配到多个目录、将队列目录放到最快的可用文件系统上或者将队列移到 RAM 磁盘也会大大提高性能。将邮件队列移动到 RAM 磁盘也许不适合许多安装,因为 — 在 OS 崩溃或服务器硬件故障的情况下 — 会损害 Sendmail 系统的消息传递完整性。
我们很惊奇地了解到,对于工作负载,我们可以将负载均衡管理器 Alteon 180 这个商业产品替换成运行 user-land 程序“balance”的专用 Linux 系统。这种 Linux 解决方案的经济效益是颇为引人注目的,而且使用设备也许会有操作上的好处。
我们看到,Sendmail 服务器由一个升到两个时,性能翻了一倍,但奇怪的是,添加第三个服务器却没有效果。我们的负载生成装置正在努力工作,因此也许是邮件生成装置已经达到了饱和。我们还发现在重负载情况下的一些 TCP/IP 问题,这些问题可能会造成连接出错率的上升。我们建议使用许多负载生成机器来处理每天一千万条消息以上的负载。
配置和注意事项
Sendmail 就象大多数传统 Unix 程序。它是高度专用的,而且是模块化的,因此可以很容易地与其它组件集成,组成更大的解决方案。Sendmail 群集就是这样一种解决方案,我们需要描述其它组件的配置。其中一些是为增加性能或可伸缩性、工作负载分派器和网络设计而设计的。其它组件是用于增加 Sendmail 群集的可管理性的,如 LDAP 和 rsync。最后,我们描述了为测试环境模拟真正工作负载所使用的工具。
Sendmail 配置
Sendmail 群集硬件/服务器
网络设置和检验
LDAP 服务器设置
名称服务设置
Mailstone SMTP 负载模拟器
如果您有问题、想要更多信息或者想要他们在此研究中使用的配置文件副本,尽请联系作者。
免责声明:上述文章是基于在实验室环境中进行的实验室测试。特殊定制安装中的结果也许会由于许多因素而发生变化,这些因素包括每个特殊安装中的工作负载和配置。因此,上述信息是在以“按现状”的基础上提供的。明确表示不承担适销性和适用于某特定用途的保证。使用本信息带来的风险将由您自行承担。