rsync 用法詳細解釋

提要

  1. 熟悉 rsync 的功能及其特點
  2. 掌握 rsync 語法及常用選項的功能
  3. 掌握 rsync 命令的三種基本使用方法
  4. 掌握如何篩選 rsync 的傳輸目標
  5. 掌握使用 rsync 進行鏡像和增量備份的方法

rsync 簡介

rsync(remote synchronize)是一個遠程數據同步工具,可通過 LAN/WAN 快速同步多臺主機之間的文件。也可以使用 rsync 同步本地硬盤中的不同目錄。
rsync 是用於替代 rcp 的一個工具,rsync 使用所謂的 rsync 算法 進行數據同步,這種算法只傳送兩個文件的不同部分,而不是每次都整份傳送,因此速度相當快。 您可以參考 How Rsync Works A Practical Overview 進一步瞭解 rsync 的運作機制。
rsync 的初始作者是 Andrew Tridgell 和 Paul Mackerras,目前由 http://rsync.samba.org 維護。
rsync 支持大多數的類 Unix 系統,無論是 Linux、Solaris 還是 BSD 上 都經過了良好的測試。 CentOS 系統默認就安裝了 rsync 軟件包。 此外,在 windows 平臺下也有相應的版本,如 cwrsync 和 DeltaCopy 等。
rsync 具有如下的基本特性:

  1. 可以鏡像保存整個目錄樹和文件系統
  2. 可以很容易做到保持原來文件的權限、時間、軟硬鏈接等
  3. 無須特殊權限即可安裝
  4. 優化的流程,文件傳輸效率高
  5. 可以使用 rsh、ssh 方式來傳輸文件,當然也可以通過直接的 socket 連接
  6. 支持匿名傳輸,以方便進行網站鏡象

在使用 rsync 進行遠程同步時,可以使用兩種方式:遠程 Shell 方式(建議使用 ssh,用戶驗證由 ssh 負責)和 C/S 方式(即客戶連接遠程 rsync 服務器,用戶驗證由 rsync 服務器負責)。
無論本地同步目錄還是遠程同步數據,首次運行時將會把全部文件拷貝一次,以後再運行時將只拷貝有變化的文件(對於新文件)或文件的變化部分(對於原有文件)。
本節重點介紹 rsync 客戶命令的使用,有關 rsync 服務器的配置和使用請參見下節
rsync 在首次複製時沒有速度優勢,速度不如 tar,因此當數據量很大時您可以考慮先使用 tar 進行首次複製,然後再使用 rsync 進行數據同步。

鏡像、備份和歸檔

實施備份的兩種情況:

rsync 命令

rsync 是一個功能非常強大的工具,其命令也有很多功能選項。rsync 的命令格式爲:

1)本地使用:
rsync [OPTION...] SRC... [DEST]

2)通過遠程 Shell 使用:
拉: rsync [OPTION...] [USER@]HOST:SRC... [DEST]
推: rsync [OPTION...] SRC... [USER@]HOST:DEST

3)訪問 rsync 服務器:
拉: rsync [OPTION...] [USER@]HOST::SRC... [DEST]
推: rsync [OPTION...] SRC... [USER@]HOST::DEST
拉: rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST]
推: rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST

其中:

下面列出常用選項: cr4ymL

rsync 的基本使用

在本地磁盤同步數據

# rsync -a --delete /home /backups
# rsync -a --delete /home/ /backups/home.0

在指定複製源時,路徑是否有最後的 “/” 有不同的含義,例如:

使用基於 ssh 的 rsync 遠程同步數據

  1. 同步靜態主機表文件
# 執行“推”複製同步(centos5 是可解析的遠程主機名)
[root@soho ~]# rsync /etc/hosts centos5:/etc/hosts

# 執行“拉”複製同步(soho 是可解析的遠程主機名)
[root@centos5 ~]# rsync soho:/etc/hosts /etc/hosts
  1. 同步用戶的環境文件
# 執行“推”複製同步
[osmond@soho ~]$ rsync ~/.bash* centos5:

# 執行“拉”複製同步
[osmond@cnetos5 ~]$ rsync soho:~/.bash* .
  1. 同步站點根目錄
# 執行“推”複製同步
[osmond@soho ~]$ rsync -avz --delete /var/www root@192.168.0.101:/var/www

# 執行“拉”複製同步
[osmond@cnetos5 ~]$ rsync -avz --delete root@192.168.0.55:/var/www /var/www

使用 rsync 從遠程 rsync 服務器同步數據

下面以鏡像 CentOS 和 Ubuntu 的軟件庫爲例來說明。
您可以到如下站點查找離自己最近的提供 rsync 服務的鏡像站點

然後執行類似如下命令:

rsync -aqzH --delete --delay-updates \
rsync://mirror.centos.net.cn/centos /var/www/mirror/centos
rsync -azH --progress --delete --delay-updates \
rsync://ubuntu.org.cn/ubuntu /var/www/mirror/ubuntu/
rsync -azH --progress --delete --delay-updates \
rsync://ubuntu.org.cn/ubuntu-cn /var/www/mirror/ubuntu-cn/

爲了每天不斷更新,可以安排一個 cron 任務:

# crontab -e
# mirror centos at 0:10AM everyday
10 0 * * * rsync -aqzH --delete --delay-updates rsync://mirror.centos.net.cn/centos /var/www/mirror/centos/
# mirror ubuntu at 2:10AM everyday
10 2 * * * rsync -azH --progress --delete --delay-updates rsync://ubuntu.org.cn/ubuntu /var/www/mirror/ubuntu/
# mirror ubuntu-cn at 4:10AM everyday
10 4 * * * rsync -azH --progress --delete --delay-updates rsync://ubuntu.org.cn/ubuntu-cn /var/www/mirror/ubuntu-cn/

如果您安裝了自己的匿名 rsync 服務器請相應地更改 rsync URL。有關如何配置匿名 rsync 服務器的內容請參見下節。

篩選 rsync 的傳輸目標

使用 --exclude/--include 選項

可以使用 ––exclude 選項排除源目錄中要傳輸的文件;同樣地,也可以使用 ––include 選項指定要傳輸的文件。
例如:下面的 rsync 命令將 192.168.0.101 主機上的 /www 目錄(不包含 /www/logs 和 /www/conf 子目錄)複製到本地的 /backup/www/ 。

# rsync -vzrtopg --delete --exclude "logs/" --exclude "conf/" --progress \
backup@192.168.0.101:/www/ /backup/www/

又如:下面的 rsync 命令僅複製目錄結構而忽略掉目錄中的文件。

# rsync -av --include '*/' --exclude '*' \
backup@192.168.0.101:/www/ /backup/www-tree/

選項 ––include 和 ––exclude 都不能使用間隔符。例如:

--exclude "logs/" --exclude "conf/"

不能寫成

--exclude "logs/ conf/"

使用 --exclude-from/--include-from 選項

當 include/exclude 的規則較複雜時,可以將規則寫入規則文件。使用規則文件可以靈活地選擇傳輸哪些文件(include)以及忽略哪些文件(exclude)。

在 rsync 的命令行中使用 ––exclude-from=FILE 或 ––include-from=FILE 讀取規則文件。
規則文件 FILE 的書寫約定:

包含(include)和排除(exclude)規則的語法如下:

PATTERN 的書寫規則如下:

下面給出幾個使用規則的例子:
例 1:

# 不傳輸所有後綴爲 .o 的文件
- *.o

# 不傳輸傳輸根目錄下名爲 foo 的文件或目錄
- /foo

# 不傳輸名爲 foo 的目錄
- foo/

# 不傳輸 /foo 目錄下的名爲 bar 的文件或目錄
- /foo/bar

例 2:

# 傳輸所有目錄和C語言源文件並禁止傳輸其他文件
+ */
+ *.c
- *

例 3:

# 僅傳輸 foo 目錄和其下的 bar.c 文件
+ foo/
+ foo/bar.c
- *

將規則寫入規則文件之後,如何在命令行上使用它呢?下面給出一個例子:
首先將下面的規則存入名爲 www-rsync-rules 的文件

# 不傳輸 logs 目錄
- logs/

# 不傳輸後綴爲 .tmp 的文件
- *.tmp

# 傳輸 Apache 虛擬主機文檔目錄(/*/ 匹配域名)
+ /srv/www/
+ /srv/www/*/
+ /srv/www/*/htdocs/
+ /srv/www/*/htdocs/**

# 傳輸每個用戶的 public_html 目錄(/*/ 匹配用戶名)
+ /home/
+ /home/*/
+ /home/*/public_html/
+ /home/*/public_html/**
# 禁止傳輸其他
- *

然後即可使用類似如下的 rsync 命令:

rsync -av --delete --exclude-from=www-rsync-rules / remotehost:/dest/dir

rsync 應用示例

使用 rsync 鏡像

使用 rsync 對目錄做鏡像實際上就是做無歷史歸檔的完全備份。下面給出一個鏡像遠程 Web 站點例子。
筆者在 dreamhost 上維護了 3 個 Dokuwiki 站點。爲了備份這 3 個站點筆者使用 rsync 進行鏡像。遠程站點的目錄結構如下:

~
|-- sinosmond.com
| `-- dokuwiki
|-- smartraining.cn
| `-- dokuwiki
`-- symfony-project.cn
`-- dokuwiki

每個 Dokuwiki 的目錄結構如下:

dokuwiki
|-- bin
|-- inc
|-- conf --- 存放配置文件的目錄
| |-- acl.auth.php --- 訪問控制配置文件 ★
| |-- local.php --- 本地配置文件 ★
| |-- users.auth.php --- 用戶口令文件 ★
| `-- ………………
|-- data --- 存放數據的目錄
| |-- attic --- 存放WIKI版本信息 ★
| |-- cache --- 存放數據緩存
| |-- index --- 存放站內索引
| |-- locks --- 存放編輯頁面時的鎖定文件
| |-- media --- 存放圖片等 ★
| |-- meta --- 存放 meta 以便系統讀取這些信息生成頁面 ★
| `-- pages --- 存放 wiki 頁面 ★
`-- lib
|-- plugins --- 存放插件的目錄 ☆
|-- tpl --- 存放模版的目錄 ☆
`-- ………………

爲了減少網絡流量,只同步標有 ★ 的目錄或文件。若在站點運行過程中新安裝了插件或更換了模板,也應該同步標有 ☆ 的目錄。爲此編寫如下的規則文件 /root/bin/backup/dw-exclude.txt:

- dokuwiki/bin/
- dokuwiki/inc/
- dokuwiki/data/cache/
- dokuwiki/data/locks/
- dokuwiki/data/index/
+ dokuwiki/conf/acl.auth.php
+ dokuwiki/conf/local.php
+ dokuwiki/conf/users.auth.php
- dokuwiki/conf/*
+ dokuwiki/lib/plugins/

# 不同步系統默認安裝的插件
- dokuwiki/lib/plugins/acl/
- dokuwiki/lib/plugins/config/
- dokuwiki/lib/plugins/importoldchangelog/
- dokuwiki/lib/plugins/importoldindex/
- dokuwiki/lib/plugins/info/
- dokuwiki/lib/plugins/plugin/
- dokuwiki/lib/plugins/revert/
- dokuwiki/lib/plugins/usermanager/
- dokuwiki/lib/plugins/action.php
- dokuwiki/lib/plugins/admin.php
- dokuwiki/lib/plugins/syntax.php
+ dokuwiki/lib/tpl

# 不同步系統默認安裝的模板
- dokuwiki/lib/tpl/default/
- dokuwiki/lib/*
- dokuwiki/COPYING
- dokuwiki/doku.php
- dokuwiki/feed.php
- dokuwiki/index.php
- dokuwiki/install*
- dokuwiki/README
- dokuwiki/VERSION

下面是同步腳本 /root/bin/backup/rsync-dw.sh

#!/bin/bash
#####################################
# mirror dokuwiki website
# $1 --- domain (ex: smartraining.cn)
# $2 --- full or update
#####################################
# declare some variable
RmtUser=osmond
RmtIP=208.113.163.110
RmtPath=$1/dokuwiki
BackupRoot=/backups/$1
Excludes="--exclude-from=/root/bin/backup/dw-exclude.txt"

# use rsync for mirror
if [ "$2" == "full" ]
then

[ -d /backups/$1 ] || mkdir -p /backups/$1
excludesfile="/tmp/first-excludes"
cat > ${excludesfile} << EOF
+ dokuwiki/data/cache/_dummy
- dokuwiki/data/cache/*
+ dokuwiki/data/locks/_dummy
- dokuwiki/data/locks/*
+ dokuwiki/data/index/_dummy
- dokuwiki/data/index/*
EOF
/usr/bin/rsync -avzP --exclude-from=${excludesfile} \
$RmtUser@$RmtIP:$RmtPath $BackupRoot

else
/usr/bin/rsync -avzP --delete $Excludes \
$RmtUser@$RmtIP:$RmtPath $BackupRoot

fi

首次備份可以使用類似如下的命令(爲了在本地保留一個完整複本):

# /root/bin/backup/rsync-dw.sh smartraining.cn full
# /root/bin/backup/rsync-dw.sh sinosmond.com full
# /root/bin/backup/rsync-dw.sh symfony-project.cn full

可以安排 cron 任務以便日後更新:

# crontab -e
05 1 * * * /root/bin/backup/rsync-dw.sh smartraining.cn
25 1 * * * /root/bin/backup/rsync-dw.sh sinosmond.com
45 1 * * * /root/bin/backup/rsync-dw.sh symfony-project.cn

普通型增量備份

使用 rsync 可以做增量備份。rsync 提供了 -b ––backup-dir 選項,使用這個選項可以將有變化的文件進行更新同時將其舊版本保存在指定的目錄中,從而實現增量備份。 下面是對 /home 進行增量備份的步驟說明:

# 第0次備份
# 首先複製 /home 目錄的內容到備份目錄 /backups/daily/home.0,
# rsync -a /home/ /backups/daily/home.0
# /backups/daily/home.0 總是同步到最新的狀態,可以每隔一段時間(如一週)
# 對其內容進行打包壓縮生成歸檔文件(完全備份)存在 /backups/archive/。

# 第1次備份(此爲核心操作)
# 將 /home 目錄的內容同步到目錄 /backups/daily/home.0,
# 並將有變化的文件的舊版本保存到 /backups/daily/home.1,
# 若每天執行一次,則目錄 /backups/daily/home.1 保存了有變化文件一天前的狀態。
# rsync -a --delete -b --backup-dir=/backups/daily/home.1 /home/ /backups/daily/home.0

# 第2次備份
# 將備份目錄 /backups/daily/home.1 更名爲 /backups/daily/home.2
# mv /backups/daily/home.1 /backups/daily/home.2
# 執行第1次備份的核心操作

# 第n次備份
# 將早先的備份目錄 /backups/daily/home.n 到 /backups/daily/home.1
# 依次更名爲 /backups/daily/home.(n+1) 到 /backups/daily/home.2
# 執行第1次備份的核心操作

下面給出一個增量備份示例腳本。

#!/bin/bash
#========================
# 您可以安排 cron 任務執行本腳本
# > crontab -e
#
# daily : 1 1 * * * /path/to/script/rsync-backup.sh
#========================
mydate="`date '+%Y%m%d.%H%M'`"

# Define rmt location
RmtUser=root
RmtHost=192.168.0.55
RmtPath=/home/
BackupSource="${RmtUser}@${RmtHost}:${RmtPath}"
#BackupSource="/home/"             # 若進行本地備份則用本地路徑替換上面的行
# Define location of backup
BackupRoot="/backups/$RmtHost/"
# BackupRoot="/backups/localhost/" # 若進行本地備份則用本地路徑替換上面的行
LogFile="${BackupRoot}/backup.log"
ExcludeList="/root/backup/backup-exclude-list.txt"
BackupName='home'
BackupNum="7"                      # 指定保留多少個增量備份(適用於每週生成歸檔文件)
#BackupNum="31"                    # 指定保留多少個增量備份(適用於每月生成歸檔文件)

# 定義函數檢查目錄 $1 是否存在,若不存在創建之
checkDir() {
    if [ ! -d "${BackupRoot}/$1" ] ; then
        mkdir -p "${BackupRoot}/$1"
    fi
}
# 定義函數實現目錄滾動
# $1 -> 備份路徑
# $2 -> 備份名稱
# $3 -> 增量備份的數量
rotateDir() {
    for i in `seq $(($3 - 1)) -1 1`
    do
        if [ -d "$1/$2.$i" ] ; then
            /bin/rm -rf "$1/$2.$((i + 1))"
            mv "$1/$2.$i" "$1/$2.$((i + 1))"
        fi
    done
}

# 調用函數 checkDir ,確保目錄存在
checkDir "archive"
checkDir "daily"

#======= Backup Begin =================
# S1: Rotate daily.
rotateDir "${BackupRoot}/daily" "$BackupName" "$BackupNum"

checkDir "daily/${BackupName}.0/"
checkDir "daily/${BackupName}.1/"

mv ${LogFile} ${BackupRoot}/daily/${BackupName}.1/

cat >> ${LogFile} <<_EOF
===========================================
    Backup done on: $mydate
===========================================
_EOF

# S2: Do the backup and save difference in ${BackupName}.1
rsync -av --delete \
    -b --backup-dir=${BackupRoot}/daily/${BackupName}.1 \
    --exclude-from=${ExcludeList} \
    $BackupSource ${BackupRoot}/daily/${BackupName}.0 \
    1>> ${LogFile} 2>&1

# S3: Create an archive backup every week
if [ `date +%w` == "0" ] # 每週日做歸檔
# if [ `date +%d` == "01" ] # 每月1日做歸檔
then
    tar -cjf ${BackupRoot}/archive/${BackupName}-${mydate}.tar.bz2 \
      -C ${BackupRoot}/daily/${BackupName}.0 .
fi

您可以適當修該上述腳本中變量:

RmtPath="$1/"
#BackupSource="$1/"
Backup

然後傳遞腳本參數備份其他目錄,例如要備份 /www 可以使用如下命令:

./rsync-backup.sh /www

快照型增量備份

使用 rsync 可以做快照(Snapshot)型增量備份。每一個快照都相當於一個完全備份。其核心思想是:對有變化的文件進行復制;對無變化的文件創建硬鏈接以減少磁盤佔用。
下面是對 /home 進行快照型增量備份的步驟說明:

# 第0次備份
# 首先複製 /home 目錄的內容到備份目錄 /backups/home.0
# rsync -a /home/ /backups/home.0

# 第1次備份(此爲核心操作)
# 以硬鏈接形式複製 /backups/home.0 到 /backups/home.1
# cp -al /backups/home.0 /backups/home.1
# 將 /home 目錄的內容同步到目錄 /backups/home.0
# (rsync 在發現變化的文件時,先刪除之,然後在創建該文件)
# rsync -a --delete /home/ /backups/home.0

# 第2次備份
# 將備份目錄 /backups/home.1 更名爲 /backups/home.2
# mv /backups/home.1 /backups/home.2
# 執行第1次備份的核心操作

# 第n次備份
# 將早先的備份目錄 /backups/home.n 到 /backups/home.1
# 依次更名爲 /backups/home.(n+1) 到 /backups/home.2
# 執行第1次備份的核心操作

rsync 2.5.6 版本之後提供了 ––link-dest 選項,如下兩條核心操作命令:

cp -al /backups/home.0 /backups/home.1
rsync -a --delete /home/ /backups/home.0

可以簡化爲如下的一條命令:

rsync -a --delete --link-dest=/backups/home.1 /home/ /backups/home.0

下面給出一個快照型增量備份示例腳本,該腳本來自 http://www.mikerubel.org/computers/rsync_snapshots/contributed/peter_schneider-kamp

#!/bin/bash
# ----------------------------------------------------------------------
# mikes handy rotating-filesystem-snapshot utility
# ----------------------------------------------------------------------
# RCS info: $Id: make_snapshot.sh,v 1.6 2002/04/06 04:20:00 mrubel Exp $
# ----------------------------------------------------------------------
# this needs to be a lot more general, but the basic idea is it makes
# rotating backup-snapshots of /home whenever called
# ----------------------------------------------------------------------

# ------------- system commands used by this script --------------------
ID='/usr/bin/id';
ECHO='/bin/echo';

MOUNT='/bin/mount';
RM='/bin/rm';
MV='/bin/mv';
CP='/bin/cp';
TOUCH='/usr/bin/touch';

RSYNC='/usr/bin/rsync';

# ------------- file locations -----------------------------------------

MOUNT_DEVICE=/dev/hdb1;
SNAPSHOT_RW=/root/snapshots;
EXCLUDES=/etc/snapshot_exclude;

# ------------- backup configuration------------------------------------

BACKUP_DIRS="/etc /home"
NUM_OF_SNAPSHOTS=3
BACKUP_INTERVAL=hourly

# ------------- the script itself --------------------------------------

# make sure we're running as root
if (( `$ID -u` != 0 )); then { $ECHO "Sorry, must be root. Exiting..."; exit; } fi

echo "Starting snapshot on "`date`

# attempt to remount the RW mount point as RW; else abort
$MOUNT -o remount,rw $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
	$ECHO "snapshot: could not remount $SNAPSHOT_RW readwrite";
	exit;
}
fi;

# rotating snapshots
for BACKUP_DIR in $BACKUP_DIRS
do
	NUM=$NUM_OF_SNAPSHOTS
	# step 1: delete the oldest snapshot, if it exists:
	if [ -d ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}.$NUM ] ; then \
	$RM -rf ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}.$NUM ; \
	fi ;
	NUM=$(($NUM-1))
	# step 2: shift the middle snapshots(s) back by one, if they exist
	while [[ $NUM -ge 1 ]]
	do
		if [ -d ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}.$NUM ] ; then \
			$MV ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}.$NUM ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_IN}
		fi;
		NUM=$(($NUM-1))
	done

	# step 3: make a hard-link-only (except for dirs) copy of the latest snapshot,
	# if that exists
	if [ -d ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}.0 ] ; then \
		$CP -al ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}.0 ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}
	fi;
	# step 4: rsync from the system into the latest snapshot (notice that
	# rsync behaves like cp --remove-destination by default, so the destination
	# is unlinked first. If it were not so, this would copy over the other
	# snapshot(s) too!
	$RSYNC \
		-va --delete --delete-excluded \
		--exclude-from="$EXCLUDES" \
		${BACKUP_DIR}/ ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}.0 ;
	# step 5: update the mtime of ${BACKUP_INTERVAL}.0 to reflect the snapshot time
	$TOUCH ${SNAPSHOT_RW}${BACKUP_DIR}/${BACKUP_INTERVAL}.0 ;
done

# now remount the RW snapshot mountpoint as readonly

$MOUNT -o remount,ro $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
	$ECHO "snapshot: could not remount $SNAPSHOT_RW readonly";
	exit;
} fi;

參考

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://www.cnblogs.com/noxy/p/8986164.html