rsync 与仍在写入的文件的行为?

rsync 与仍在写入的文件的行为?

如果 Apache 正在写入一个大文件,并且 rsync cron 作业在该文件上运行,rsync 是否会尝试复制该文件?

例子

  • Apache-1:正在将较大的文件写入/var/www
  • Apache-2:Apache-1 的克隆。每五分钟 cron 运行 rsync 以同步/var/www

答案1

如果 Apache 正在将某种文件写入某个位置但尚未完成写入进而 rsync开始执行,rsync将复制那里的任何内容。

这意味着如果 Apache 正在处理一个 5MB 的文件,则只有 2MB 被写入并rsync启动,部分 2MB 文件将被复制。因此该文件在目标服务器上看起来就像是“损坏”的。

根据您使用的文件的大小,您可以使用选项--inplace执行rsync以下操作:

当文件数据需要更新时,此选项会更改 rsync 传输文件的方式:rsync 不会采用默认方法,即创建文件的新副本并在完成后将其移动到位,而是将更新的数据直接写入目标文件。

这样做的好处是,如果 5MB 文件在第一次运行时仅复制了 2MB,则下一次运行将从 2MB 开始继续复制文件,直到复制满 5MB。

缺点是,它可能会导致有人在复制文件时访问 Web 服务器,然后他们会看到部分文件。在我看来,rsync它默认的行为效果最好,即缓存“不可见”文件,然后立即将其移动到位。但--inplace对于大文件和带宽限制可能阻碍从头开始轻松复制大文件的情况,它很有用。

这就是说,你确实这么说过;重点是我的:

每五分钟有 cron 运行 rsync…

所以我假设您已经准备好一些 bash 脚本来管理这个 cron 作业?嗯,这个脚本rsync足够智能,只复制需要复制的文件。如果您有一个每 5 分钟运行一次的脚本,那么rsync当脚本运行得更快时,您似乎在试图避免互相干扰。这意味着,如果您每分钟运行一次,则存在一个或多个进程由于文件大小或网络速度而仍在运行的风险rsync,而下一个进程将与之竞争;这是一种竞争状态。

避免这种情况的一种方法是将整个rsync命令包装在检查文件锁的 bash 脚本中;下面是我用于此类情况的样板 bash 脚本框架。

请注意,有些人会建议使用flock,但由于flock在我使用的某些系统上没有安装 - 而且我经常在 Ubuntu(有它)和 Mac OS X(没有)之间切换 - 我使用这个简单的框架没有任何实际问题:

LOCK_NAME="MY_GREAT_BASH_SCRIPT"
LOCK_DIR='/tmp/'${LOCK_NAME}.lock
PID_FILE=${LOCK_DIR}'/'${LOCK_NAME}'.pid'

if mkdir ${LOCK_DIR} 2>/dev/null; then
  # If the ${LOCK_DIR} doesn't exist, then start working & store the ${PID_FILE}
  echo $$ > ${PID_FILE}

  echo "Hello world!"

  rm -rf ${LOCK_DIR}
  exit
else
  if [ -f ${PID_FILE} ] && kill -0 $(cat ${PID_FILE}) 2>/dev/null; then
    # Confirm that the process file exists & a process
    # with that PID is truly running.
    echo "Running [PID "$(cat ${PID_FILE})"]" >&2
    exit
  else
    # If the process is not running, yet there is a PID file--like in the case
    # of a crash or sudden reboot--then get rid of the ${LOCK_DIR}
    rm -rf ${LOCK_DIR}
    exit
  fi
fi

这个想法是,通用核心(我所指的echo "Hello world!")是脚本的核心所在。其余部分基本上是基于的锁定机制/逻辑mkdir。对概念的一个很好的解释在这个答案中

建立目录如果目录尚不存在,则创建目录;如果目录存在,则设置退出代码。更重要的是,它在一个原子操作中完成所有这些操作,非常适合此场景。

因此,对于您的rsync流程,我建议您使用此脚本,只需将命令更改echo为您的rsync命令即可。此外,将 更改LOCK_NAME为类似 的内容RSYNC_PROCESS,然后您就可以开始了。

现在,使用rsync此脚本,您可以将 cron 作业设置为每分钟运行一次,而不会出现两个或多个rsync进程争相执行相同操作的竞争情况。这将允许您提高速度或rsync更新,虽然这不会消除部分文件传输的问题,但它将有助于加快整个过程,以便可以在某个时候正确复制整个文件。

答案2

是的 - 如果 rsync 在写入文件的同时读取该文件,则该文件可能已损坏。

您可以尝试以下操作: https://unix.stackexchange.com/a/2558

您也可以使用 lsof 编写脚本:

lsof /path/to file

退出代码为 0 表示文件正在使用中,退出代码为 1 表示该文件没有活动。

相关内容