假设我使用 Dovecot 及其 maildir 格式来保存和访问服务器上的邮件。如何在复制 maildir 时避免竞争条件?
我确实读过一些关于备份和使用 maildir 的教程,但没有看到任何人写过这方面的内容。他们只是使用cp
或rsync
将目录复制到另一个地方。maildir 不可能通过复制变成不一致的状态,还是我需要某种锁定?
编辑:我想定期备份,但我认为这并不能真正解决这个问题。我知道我可以停止邮件服务器(Dovecot 和 Postfix),但我认为不这样做也可以。据我所知,maildir 支持不同应用程序的并发访问。
答案1
我刚刚读Dovecot 中的 Maildir 文档以及有关 Maildir 和 Maildir++ 的其他一些文档。我希望我没有遗漏任何重要内容。
Maildir 的设计目标是无需锁定即可工作。在现代文件系统上,大多数必需操作都是原子性的。这意味着您不必太在意诸如读取不一致之类的竞争条件。但是,如果您想在邮件服务器运行时备份 Maildir,仍存在一些问题。
问题
备份和恢复
tmp/
是没用的。每个 Maildir 包含目录new/
、cur/
和tmp/
。目录tmp/
包含当前正在写入磁盘的邮件。new/
成功写入后,它们将被移动到 。这意味着 中的文件tmp/
可能尚未完成。即使文件已完成,恢复备份后,写入文件的进程也不再运行。这意味着如果恢复此类文件,它将永远不会被添加到邮箱中,也可能永远不会被删除。从备份中排除可能是明智的
dovecot-uidlist.lock
。Dovecot 使用 Maildir 的扩展 Maildir++。此扩展需要锁定。此扩展不需要获取读取锁,但将锁定文件从备份中排除可能是明智的做法。获取
dovecot-uidlist.lock
或使用文件系统的快照。基本上,您可以只复制目录,但可能会因竞争条件而错过一些邮件。原因是列出和复制目录内容(递归)不是原子的。这意味着当用户更改标签(例如已看到/未看到)或移动邮件时,可能会在创建备份时错过电子邮件。为了处理这种情况,Dovecot 会为每个操作获取锁文件(与上述相同)。如果您使用的是 Dovecot,则可以通过在创建备份之前获取锁来解决问题。这可以通过 来完成/usr/lib/dovecot/maildirlock
。另一种可能性是使用文件系统的快照。由于创建快照是原子的,因此问题不会发生在快照上。
简单总结一下:如果您想在 Dovecot 运行时进行备份,您应该首先获取锁定文件dovecot-uidlist.lock
或创建文件系统的快照。然后,您可以复制 Maildir。从备份中排除tmp/
和可能是明智的做法。dovecot-uidlist.lock
答案2
该问题的最新答案是使用 dovecot 的 doveadm 或 dsync 命令。例如:
dsync -f -u <user> backup maildir:<backup_location>
有一个dovecot 备份shell 脚本添加了一些很好的围绕 dsync 的包装,以循环遍历所有用户邮箱、打包文件、修剪旧备份并在发生错误时发送电子邮件警报。