如果进程 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
而不是cp
,rsync
默认情况下使用此策略:
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/