本文完整阅读约需 12 分钟,如时间较长请考虑收藏后慢慢阅读~

最近,我将所租用服务器上所有的数据(接近500G)使用crontab+rsync同步到了Time4VPS的存储服务器,以防硬件故障造成数据丢失。
然而在同步过程中,却出现了消耗掉服务器所有资源(内存&CPU&磁盘)的问题。

首先附上我的crontab配置:

0  *  *  *  * root       echo `date` >> /home/rsync.log && rsync -avu --progress --delete --checksum --compress /home/lurenjia [email protected]:/home/backup/ >> /home/rsync.log

这个配置看起来没有任何问题,但是一旦运行,就会出现如下图所示的情况:

图中可以看到,磁盘延迟已经高达3000ms,除此之外同时还伴随着备份服务器(虚拟机)Linux内存耗尽的警告,终端不响应任何操作,CPU占用率为100%。

发现问题后,我立刻关闭虚拟机的电源,重启后删除掉crontab,开始着手排查原因。

最开始我认为问题出在crontab本身的配置,但在确认crontab之后,发现crontab并没有出现问题,上面0 * * * *的配置即每小时0分执行命令。

我尝试执行crontab中的命令(当时写了之后忘了尝试性执行一下,实在是失策),却发现卡在了sending incremental file list上。

使用screen退出当前session,运行top发现rsync正在疯狂地使用CPU资源,而运行iotop发现rsync正在疯狂地读取磁盘。

$ iotop

Total DISK READ :     102.55 M/s | Total DISK WRITE :       0.00 B/s
Actual DISK READ:     102.55 M/s | Actual DISK WRITE:       0.00 B/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
 6726 be/4 root      102.55 M/s    0.00 B/s  0.00 % 48.84 % rsync -avu --progress --delete --compress --checksum /home/lurenjia [email protected]:/home/backup/
...

问题来了:同步只需要读取文件列表与摘要,那么rsync到底在做什么操作,造成如此大的磁盘IO开销呢?

我使用man rsync阅读rsync的文档,希望从文档中找到造成如此大磁盘IO开销的『罪魁祸首』。这时候我突然发现一段参数说明:

OPTIONS SUMMARY
       Here is a short summary of the options available in rsync. Please refer to the detailed description below for a complete description.

        -v, --verbose               increase verbosity
            --info=FLAGS            fine-grained informational verbosity
            --debug=FLAGS           fine-grained debug verbosity
            --msgs2stderr           special output handling for debugging
        -q, --quiet                 suppress non-error messages
            --no-motd               suppress daemon-mode MOTD (see caveat)
        -c, --checksum              skip based on checksum, not mod-time & size
        -a, --archive               archive mode; equals -rlptgoD (no -H,-A,-X)
            --no-OPTION             turn off an implied OPTION (e.g. --no-D)
        -r, --recursive             recurse into directories
        -R, --relative              use relative path names

注意--checksum参数的说明:根据文件校验值进行文件比对,而非修改时间与文件体积。

就是这里!造成巨大磁盘IO的罪魁祸首就是这个参数,500G文件在本地和备份服务器端全部读取&校验需要很长的时间,而前一个任务尚未执行完毕,后一个任务又来了,如此往复,造成Linux磁盘高IO的同时,也让系统由于内存不足而崩溃。

既然找到了罪魁祸首,那么解决这一问题就非常简单:在命令中删除--checksum参数即可。

删除该参数后,同步时间果然飞快。但这时候我想到了另一个问题:如果只校验修改时间与文件体积,是否能保证文件真正得到同步呢?

我尝试了在修改文件内容(保持大小不变)后将修改时间恢复原状的情况,结论是:在修改时间和文件体积不变的情况下,rsync会漏掉该文件,导致同步不完全。但是这种情况实在是少之又少,所以说一般我们不需要考虑漏掉文件的问题。

如果实在担心漏掉文件的话,可以使用两种方式解决:
1. 加上--checksum参数。这种方式尽管极慢,而且对磁盘可能有损伤,但是是最万无一失的,如果存在很重要(例如数据库、日志)、但是不是很大(差不多1G以内)的文件,可以使用该方式进行同步。
2. 隔一段时间删除备份服务器上所有数据,并重新进行全量同步。该方式适合文件较大较多的情况,定期的全量同步也可以解决同步不完全的情况。