我可以安全地读取由另一个进程附加的文件吗?

我可以安全地读取由另一个进程附加的文件吗?

如果进程 A 将文件复制到某个位置 loc,并且进程 B 定期将文件从 loc 复制到其他位置,则 B 是否可以读取当前正由 A 复制到 loc 的过程中的文件?

如果这很重要的话,我正在使用 Ubuntu Linux 12.04。


背景信息:我想持续备份 PostgreSQL 集群。 PostgreSQL 为此提供了 WAL 归档。它的工作原理是让数据库调用一个脚本,将完整的 WAL 文件复制到某个备份位置。

我想要另一个进程定期将备份的 WAL 文件复制到另一台服务器。如果数据库当前正在复制 WAL 文件,第二个进程是否仍然可以读取该文件,而不会在整个文件复制之前遇到某些 EOF 条件?

换句话说:我可以在 A 和 B 之间不同步的情况下执行以下操作吗?

A                                   B
cp pg_xlog/some_wal_file /backup/   scp /backup/* user@remote-machine:/backups/

答案1

在这种情况下,唯一的保证是 B 不会复制该文件,或者复制该文件的前缀。 B 无法知道文件正在被写入,因此它将读取到文件的(当前)末尾,然后停止。

避免这种陷阱的常见方法是将文件复制到临时名称下,然后重命名:

dest=$(TMPDIR=/backup mktemp)
trap 'rm -f "$dest"' INT HUP ERR
cp -p pg_xlog/some_wal_file "$dest"
mv "$dest" "/backup/some_wal_file"

在消费者中,安排不复制临时文件。在您的场景中,您可以通过将其设为点文件来实现这一点 - 使用dest=$(TMPDIR=/backup mktemp .XXXXXXXXXX)上面的方法。一种更简单的方法是调用rsync而不是cprsync默认情况下使用此策略:

rsync -a pg_xlog/some_wal_file /backup/

在步骤 B 中,确保排除这些临时文件,例如:

rsync -a --exclude='/.*' /backup/ user@remote-machine:/backups/

如果您不想依赖点文件,可以使用暂存目录。只要两个目录位于同一文件系统上,将文件从一个目录移动到另一个目录就是原子的。

mkdir -p /backup/incoming
cp -p pg_xlog/some_wal_file /backup/incoming/
mv /backup/incoming/some_wal_file /backup/
rsync -a --exclude=/staging  /backup/ user@remote-machine:/backups/

答案2

我认为最好的办法是确保进程 B 只复制进程 A 已完全传输的文件。实现此目的的一种方法是在进程 A 中使用cp和的组合mv,因为该mv进程使用rename系统调用(前提是文件位于同一文件系统上),这是原子的。这意味着从进程 B 的角度来看,文件显示为完全形成的状态。

实现此目的的一种方法是partial在目录中创建一个被进程 B 忽略的目录/backup。对于进程 A,您可以执行以下操作:

file="some_wal_file"
cp pg_xlog/"$file" /backup/partial
mv /backup/partial/"$file" /backup

对于流程 B(使用bash):

shopt -s extglob
scp /backup/!(partial) user@remote-machine:/backups/

尽管您可能想要研究进程 A 和进程 B 的程序是rsync.rsync创建部分文件并默认自动移动到位(尽管部分文件通常是隐藏文件而不是位于特定目录中)。 Rsync 还将避免传输不需要的文件,并且具有特殊的增量算法,用于仅传输需要通过网络更新的文件的相关部分(rsync必须安装在两个位置,尽管ssh默认情况下传输仍然会进行) )。用于rsync进程A:

rsync -a --partial-dir=/backup/partial pg_xlog/some_wal_file /backup/

对于流程B:

rsync -a --exclude=/partial/ /backup/ user@remote-machine:/backups/

相关内容