Qmail邮件队列工作原理

Qmail邮件队列工作原理1 概述 以下是 qmail 的数据流简图 qmail smtpd gt gt qmail queue gt gt qmail send lt lt qmail rspawn lt lt qmail remote qmail inject qmail clean qmail lspawn lt lt

大家好,我是讯享网,很高兴认识大家。

qmail-smtpd --- >>qmail-queue --->> qmail-send <<--- qmail-rspawn <<--- qmail-remote
/ |
qmail-inject _/ qmail-clean /_ qmail-lspawn <<--- qmail-local

qmail中,每一条消息都发送到中央队列等待发送,由qmail-queue进程控制。它在以下情况被调用:
1、当产生本地消息时,qmail-inject进程调用qmail-queue。
2、qmail-smtpd准备SMTP协议下的投递邮件任务时调用它。
3、向前(forwarded)发送邮件时,qmail-local调用它。
4、退回邮件时,qmail-send调用它。

每封邮件接着由qmail-lspawn 和qmail-rspawn协助qmail-sned进程完成投递,最后由qmail-clean清除邮件队列。这四个进程是系统由始至终都在运行的,十分重要。

qmail的队列被设计成很强的鲁棒性,并假定基础的文件系统也是强健的。所有的cleanups清除队列操作都由qmail-send独立控制,无须人为干预。详细请看第六部分。

2. 队列结构

队列里的每条消息都由唯一的号码标识,假定某条消息是的标识码是457。队列被组织成几个目录,每个目录都可能包含和这条消息相关的文件:

mess/457: 消息正文
todo/457: 信封: 消息的来源地址和目的地址。实际是指向intd/457的链接。
intd/457: 信封,由qmail-queue生成。
info/457: 信封上的发送者地址,预处理后生成。
local/457: 本地接受地址,预处理后生成。
remote/457: 远程接受地址,预处理后生成。
bounce/457: 传输错误信息。

以下是一条消息所有可能的状态。“+”号表示该目录下文件存在,“-”表示该目录下文件不存在,“?”表示未知。
S1. -mess -intd -todo -info -local -remote -bounce
S2. +mess -intd -todo -info -local -remote -bounce
S3. +mess +intd -todo -info -local -remote -bounce
S4. +mess ?intd +todo ?info ?local ?remote -bounce (queued,表示已经进入队列)
S5. +mess -intd -todo +info ?local ?remote ?bounce (preprocessed,表示已通过预处理)

重点:如果消息457存在,那么它也对应一个inode结点号457。

添加一条消息到队列里,qmail-queue首先创建一个单独的目录,命名为 pid/。然后在这个目录下为这条消息创建一个独立文件。文件系统为这个文件分配唯一的标识,暂时记做457。qmail-queue监视这个文件标识,并保证这条消息进入状态S1。
qmail-queue接着把pid/ 更名为mess/457,进入状态S2。然后写一些相关的信息到mess/457目录下,创建目录intd/457,进入状态S3,并在intd/457下写入相关的信封信息。
最后,qmail-queue创建一个指向 intd/457 的链接 :todo/457 ,进入状态S4。到此为止,这条消息已经被处理到队列中,等待qmail-send的处理。
qmail-queue在处理任何文件之前,会启动一个24小时的超时记时器。一旦等待处理超过24小时,qmail-queue将中止当前进程。

4. 队列中的消息如何预处理


讯享网

5. 预处理后,消息如何被投递。

处在S5状态的消息将被做如下处理。每个 local/457 和 remote/457 目录下的邮件地址将被标记NOT DONE 或 DONE:

qmail-send 会在空闲的时间尝试给标记了NOT DONE 的地址发送邮件。如果邮件被成功处理,qmail-send将在该地址标记DONE。如果遇到永久性错误,它首先发送一条错误通知到bounce/457目录(如果该目录不存在,就自动创建),然后将邮件地址标记为DONE。

注意:bounce/457被设计成不强健的。

qmail-send会在任意的时刻处理 bounce/457目录 ,可能如下:
1)从 bounce/457 和 mess/457目录创建一条新的bounce消息
2)删除bounce/457目录。

当local/457中所有的邮件地址都被标记DONE后,qmail-send将删除local/457。同样的,remote/457也做此处理。随后,qmail-send删除队列里的邮件:
第一步、如果 bounce/457存在,qmail-send按照上述的方法处理。
第二步、如果 bounce/457已删除,qmail-send删除 info/457目录,进入状态S2;然后删除 mess/457 ,进入状态S1。

6. Cleanups清除操作。

如果在qmail-queue处理邮件队列时,或者qmail-send正删除邮件时,系统因故障崩溃,当时处理的邮件就会处在S2或者S3状态。
如果qmail-send检查到有邮件处在S2或者S3状态(不是正在删除的邮件),而mess/457的创建时间已经过了36小时,它就相续删除 intd/457 (如果存在)和 mess/457。此时,正在处理该邮件的qmail-queue将被挂起。
同样的,如果qmail-send发现 pid/ 目录下的文件创建时间超过36小时,也将删除该目录。
如果在qmail-send投递邮件时发生系统崩溃故障,Cleanups则无须运行。最遭情况下,邮件可能会被投递两次。其实,在分布式邮件系统上,目前并没有一种有效的方法来降低邮件重复投递的可能。不妨试想一下,如果在接受方的邮件服务器响应之前,投递邮件的SMTP链接发生断路错误,该怎么办?显然,用户必须考虑到这种最坏情况,并再次发送邮件。同样的,如果在qmail-send进程为邮件做DONE标记之前,计算机崩溃了。那么,重启后的新进程必须再次发送该邮件。通常的方法是,利用日志文件。反正,删除重复邮件是接受方的事情,无须顾虑。

7. 更多

目前,info/457的存在有两种作用:
1、它记录了邮件信封中,发送人的信息。
2、守护进程通过它的修改时间来判断该邮件在队列中是否超时。
将来,随着系统改进, info/457 可能会存储更多的信息。任何改变都是向后兼容的,并将由版本号标识。
当qiaml-queue成功的将一条邮件加入到队列中时,它将启动一个由qmail-send设定的触发器。该触发器的工作机制是:命名管道锁触发-- lock/trigger 。在扫描 todo/ 之前,qmail-send 打开 lock/trigger下的管道O_NDELAY 设定可读。qiaml-queue通过向O_NDELAY写一个字节来触发qmail-send。这使得 locks/trigger 可读并唤醒qmail-send进程。在再次扫描 todo/ 之前,qmail-send 先关闭lock/trigger再打开它。

小讯
上一篇 2025-03-02 21:23
下一篇 2025-03-20 10:25

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/27761.html