18.13 sendmail的性能
sendmail有几个配置选项是专为改善性能而设计的。虽然我们已经在本章中间分散介绍了它们,但是我们还是要在这一节对最重要的几项展开来阐述一下。如果您所运行的是个容量很大的
邮件系统(无论哪一个方向),那么都应该考虑这些选项和功能。实际上,如果您真的需要在一小时内发送100万封邮件,而您又不是在发垃圾邮件,那么您最好求助于sendmail的商业一面,即Sendmail,Inc.。
18.13.1 投递方式
sendmail有4种基本的投递方式:后台(background)、交互(interactive)、队列(queue)和推迟(defer)。每种方式都代表着在延迟和吞吐量之间的一种折衷。后台方式会立即投递邮件,但要求sendmail派生出一个新的进程来完成投递。交互方式也立即投递邮件,但是由同一个进程完成投递,而且要让远端等待结果。队列方式把传入的邮件排入队列,在稍晚些的时候由一个队列运行器(queue runner)来投递。推迟方式和队列方式类似,但是它推迟映射、
DNS、别名和转发的查找操作。交互方式很少用。后台方式延迟最低,而推迟或者队列方式吞吐量较高。投递方式是用confDELIVERY_MODE这个选项设置的,它默认为后台方式。
18.13.2 队列分组和信封分割
队列组(queue group)是在sendmail 8.12里出现的新功能,它能让您为传入邮件创建多个队列,并且分别控制每个队列组的属性。队列组包括一个或者几个队列目录。例如,如果您的
Linux主机是一个ISP的邮件枢纽主机,您可能会给拨号用户定义一个队列组,而且允许拨号用户在他们连接上来
下载自己的邮件时,发起一次队列运行操作(使用SMTP命令ETRN)。队列组可以配合信封分割(envelope-splitting)的功能使用,后者可以把带有多个收件人的信封划分到多个队列组中。这一功能加上为每个队列组使用多个队列目录,就能有助于缓解在一个文件系统中有太多文件所造成的性能问题34。
当一条消息进入邮件系统的时候,它就分到了一个或者几个队列组中。每个收件人的队列组是独立决定的。信封要根据队列组的分配情况重新写。如果使用多个队列目录,那么消息会随机地分配到正确队列组的若干个队列中。
如果一个队列组对每个信封上收件人的最大数目有限制,那么sendmail就把消息的信封分割为几个能够符合队列组的参数小信封。
队列组是用.mc文件里的指令声明的,但却是由LOCAL_RULESETS选项在原始配置文件里配置的,我们根本没有在本书里介绍过这个选项。如果您想要使用队列组来改善性能,或者向不同的目的地提供不同的服务
质量,那么就可以用下面的例子作为起点。
表18.16列举了可以为一个队列组指定的属性。在定义队列组的时候,只需要指定属性名字的第一个字母。
表18.16 队列组的属性
属
性
| 含
义
|
Flags | 多用于未来的控制功能;必须设置f标志才能有多个队列运行器
|
Nice | 这个队列组的优先级;优先级较低,则以nice系统调用的方式运行
|
Interval | 在队列运行之间等待的时间
|
Path | 和队列组相关联的队列目录的路径(必须要有)
|
Runners | 在队列组上并发运行的sendmail进程数目
|
Recipients | 每个信封上最大的收件人数目
|
下面是一个例子,它有针对本地邮件、发送到aol.com的邮件、发送到其他远程
站点的邮件、以及其余所有邮件的默认队列的队列组。下面这几行将会放到.mc文件的正规部分里面:
|
[tr][/tr]
然后在.mc文件的末尾加上:
|
[tr][/tr]
在本例中,当我们定义AOL的队列组时,我们特别限制每个消息最多有100个收件人。如果一则传出的消息有10 000个收件人,其中1 234个收件人是在AOL,那么就会分割信封,在aol队列组中放入13条消息,其中12条消息有100个收件人,而1条消息有剩下的34个收件人。
为了提高速度,可以尝试采用快速分割,它会在分类处理期间推迟做MX查询:
| define(‘confFAST_SPLIT', ‘1') |
18.13.3 队列运行器
sendmail派生出自己的若干个副本执行实际的邮件传输操作。您可以控制在任何指定的时间,可以有多少个sendmail的副本在同时运行,甚至还可以控制每个队列组上关联多少个sendmail的副本。这个功能能够让系统管理员在他们繁忙的邮件枢纽主机上达到sendmail和操作系统之间的平衡。
sendmail的3个选项控制着每个队列上队列运行器守护进程的数目。
MAX_DAEMON_CHILDREN选项指定了在任何时刻允许运行的sendmail守护进程的副本数量,其中包括那些正在队列上运行的以及那些正在接受传入邮件的副本。
MAX_QUEUE_CHILDREN选项设置一次所能允许的队列运行器的最大数目。
如果在队列组的定义中没有用Runners=(或者R=)明确设置一个值的话,那么MAX_RUNNERS_PER_QUEUE选项设置每个队列上默认的运行器数的上限。
如果您设置的值有冲突(例如,总共最多有50个队列运行器,但是10个用于本地队列、30个用于mydomain队列、还有50个用于AOL队列),那么sendmail会把队列分成工作组(workgroup),在工作组间进行循环。在本例中,本地和mydomain队列都在一个工作组里,而AOL队列在第二个工作组里。如果您
选择的限制必须发生冲突(例如,max=50但是AOL=100),那么sendmail会使用MAX_QUEUE_CHILDREN作为它的队列运行器数量的绝对上限。
18.13.4 负载均衡控制
在系统平均负载太大的时候,sendmail一直能够拒绝连接或者把消息排入队列,而不会投递它们。遗憾的是,平均负载的时间粒度只是一分钟,所以它不是一个能精确刻画sendmail所占资源的工具。新的DELAY_LA原语可以让您设定一个负载平均值,在达到这个值的时候,sendmail就会放慢执行的速度,它在为当前连接执行SMTP命令之后到接受新的连接之前要睡上一秒钟。默认值是0,意味着关闭这一机制。
18.13.5 队列中无法投递的消息
在繁忙的邮件
服务器上,在邮件队列中无法投递的消息实际上是性能杀手。sendmail有几项功能能够帮助解决消息无法投递造成的问题。最有效果的就是FALLBACK_MX选项,它把第一次尝试无法投递出去的消息转给另一台机器。这项功能可以让您的主邮件
服务器选择发送地址正确的消息,而把问题留给第二台后援(fallback)主机。另一项有帮助的功能是主机状态目录,它保存有在运行队列上的远程主机的状态。
对于有大型邮递列表的站点来说,由于这些站点不可避免会包含许多暂时或者永远无法投递的地址,采用FALLBACK_MX选项就可以在性能上取得很大收效。要使用这个选项,您必须为推迟处理的邮件指定后援主机。例如,
| define(‘confFALLBACK_MX', ‘mailbackup.atrust.com') |
会把所有第一次投递失败的消息转发给中央服务器mailbackup.xor.com,由它做进一步的处理。在8.12版的sendmail上,如果在DNS中给多台指定的主机设定了多条MX记录,那么就可以有多台后援主机。
在后援机器上,您可以使用HOST_STATUS_DIRECTORY选项帮助处理多起投递失败的消息。这个选项指导sendmail给每台接受邮件的后援主机维护一个状态文件,并且在每次运行队列的时候使用那个状态信息确定该主机的优先级。这个状态信息有效地实现对失败结果的高速缓存,并且可以在多个运行的队列上共享这一信息。在处理带有许多错误地址的邮递列表的主机上,这项功能会在性能上取得成效,但是在文件I/O方面的开销相当大。
下面是一个例子,它使用目录/var/spool/mqueue/.hoststat(要先创建这个目录):
| define(‘confHOST_STATUS_DIRECTORY', ‘/var/spool/mqueue/.hoststat') |
如果采用相对路径指定.hoststat目录,那么它就会保存在队列目录下面。sendmail根据目的主机名创建它自己内部的子目录层次结构。
例如,如果邮件无法发送到
evi@anchor.cs.colorado.edu,那么状态信息就进入到目录/var/spool/mqueue/
.hoststat/edu./colorado./cs./下的一个叫做anchor的文件里,因为主机anchor就是它自己的优先级最高的MX记录。如果DNS MX把anchor的邮件指向了主机foo,那么文件名就会变成foo,而不是anchor。
繁忙主机所能采用的第三项改善性能的措施是把排队的时间设定到一个最小值,让首次投递失败的任何消息都被排入队列,在队列中发送它的尝试时间间隔最短。这项技术通常要配合sendmail频繁运行sendmail的命令行标志(例如,-q5m)一起使用。如果一个队列运行器在一则消息上被耽搁了,那么另一个队列运行器就会在5分钟内启动起来,从而提高了投递消息的性能。整个队列根据哪些消息已经到了所要求的最短时间来成批运行。带上标志-bd -q5m运行sendmail时,把下面这个选项:
| define(‘confMIN-QUEUE_AGE', ‘27m') |
包括在配置文件中可以带来响应速度更快的系统。
18.13.6 内核调优
如果您计划用一台Linux机器作为大容量的
邮件服务器,那么应该修改内核连网配置参数中的几个暗示,或许还要构造一个定制的内核(取决于您的硬件配置和预计的负载)。删掉任何不必要的驱动程序,就可以从一个改进后的内核启动,这个内核只适用于您自己的硬件配置。
如果主机有一个以上的处理器的时候,定制的内核应该包括对多处理器(SMP)的支持(我们认识到,对于真正的Linux迷来说,这条
建议可以比作是“不要忘记喘气”这样几乎不需要提醒的提醒。但是,既然Linux用户在构造内核上的技能参差不齐,所以我们就没有理会审稿人的意见,把这段提醒的话保留了下来)。
要重新设置连网协议栈的参数,需使用shell的echo命令重新设置/proc文件系统中的适当变量。第12章里介绍了这个过程总体性的知识。表18.17给出了在高容量的邮件服务器上要改的参数,以及它们的建议和默认值。这些更改操作或许应该放在一个shell脚本里,在系统引导的时刻运行,执行相应的echo命令。
表18.17 在大容量的邮件服务器上需改动的内核参数
变量(相对于/proc/sys)
| 默
认
值
| 建
议
值
|
net/ipv4/tcp_fin_timeout
| 180 | 30 |
net/ipv4/tcp_keepalive_time
| 7 200 | 1 800 |
net/core/netdev_max_backlog
| 300 | 1 024 |
fs/file_max
| 4 096 | 16 384 |
fs/inode_max
| 16 384 | 65 536 |
例如,您可以使用命令:
| echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout |
改变TCP的FIN超时值。