rsync算法原理及使用

若是服務器之間須要保持某些文件的一致,咱們可使用scp來複制,若是須要長期保持一致,能夠配合crontab腳原本使用。可是此時咱們有更優的方式,就是rsync+crontab來實現定時增量傳輸保持文件一致。html

rsync功能很強大,網上的資料也都很全,這裏作一些簡單的彙總。linux

rsync原理

這一小節內容大幅度轉載了 RSYNC 的核心算法 的內容,由於原文章寫的太好,就再也不狗尾續貂了,感興趣的能夠直接查看原文。他的翻譯原文是: The rsync algorithm

rsynclinux下同步文件的一個高效算法,用於同步更新兩處計算機的文件和目錄,並適當利用查找文件中的不一樣塊以減小數據傳輸。rsync的主要特色就是增量傳輸,只對變動的部分進行傳送。算法

增量同步算法

假如咱們如今須要同步兩個文件保持一致,而且只想傳送不一樣的部分,那麼咱們就須要對兩邊的文件作diff,可是這兩個問題在兩臺不一樣的機器上,沒法作diff。若是咱們作diff,就要把一個文件傳到另外一臺機器上作diff,但這樣一來,咱們就傳了整個文件,這與咱們只想傳輸不一樣部的初衷相背。因而咱們就要想一個辦法,讓這兩邊的文件見不到面,但還能知道它們間有什麼不一樣。這就是rsync的算法。shell

rsync同步算法

咱們將同步源文件名稱爲fileSrc,同步目的文件叫fileDst數組

1. 分塊Checksum算法

首先,咱們會把fileDst的文件平均切分紅若干個小塊,好比每塊512個字節(最後一塊會小於這個數),而後對每塊計算兩個checksum:服務器

  1. 一個叫rolling checksum,是弱checksum32位的checksum
  2. 另外一個是強checksum128位的,之前用md4,如今用md5 hash算法。

爲何要這樣?由於若干年前的硬件上跑md4的算法太慢了,因此,咱們須要一個快算法來鑑別文件塊的不一樣,可是弱的adler32算法碰撞機率過高了,因此咱們還要引入強的checksum算法以保證兩文件塊是相同的。也就是說,弱的checksum是用來區別不一樣,而強的是用來確認相同。網絡

2. 傳輸算法

同步目標端會把fileDst的一個checksum列表傳給同步源,這個列表裏包括了三個東西,rolling checksum(32bits),md5 checksume(128bits),文件塊編號。數據結構

同步源機器拿到了這個列表後,會對fileSrc作一樣的checksum,而後和fileDstchecksum作對比,這樣就知道哪些文件塊改變了。ssh

可是,聰明的你必定會有如下兩個疑問:工具

若是我fileSrc這邊在文件中間加了一個字符,這樣後面的文件塊都會位移一個字符,這樣就徹底和fileDst這邊的不同了,但理論上來講,我應該只須要傳一個字符就行了。這個怎麼解決?
若是這個checksum列表特別長,而個人兩邊的相同的文件塊可能並非同樣的順序,那就須要查找,線性的查找起來應該特別慢吧。這個怎麼解決?
很好,讓咱們來看一下同步源端的算法。

3. checksum查找算法

同步源端拿到fileDstchecksum數組後,會把這個數據存到一個hash table(特殊的數據結構體,能夠快速檢索)中,用rolling checksumhash,以便得到O(1)時間複雜度的查找性能。這個hash table16bits的,因此,hash table的尺寸是2的16次方,對rolling checksumhash會被散列到0 到 2^16 – 1中的某個整數值。

4. 比對算法

圖片描述

  1. fileSrc的第一個文件塊(咱們假設的是512個長度),也就是從fileSrc的第1個字節到第512個字節,取出來後作rolling checksum計算。計算好的值到hash表中查。
  2. 若是查到了,說明發如今fileDst中有潛在相同的文件塊,因而就再比較md5checksum,由於rolling checksume太弱了,可能發生碰撞。因而還要算md5128bitschecksum,這樣一來,咱們就有 2^-(32+128) = 2^-160的機率發生碰撞,這過小了能夠忽略。若是rolling checksummd5 checksum都相同,這說明在fileDst中有相同的塊,咱們須要記下這一塊在fileDst下的文件編號。
  3. 若是fileSrcrolling checksum 沒有在hash table中找到,那就不用算md5 checksum了。表示這一塊中有不一樣的信息。總之,只要rolling checksummd5 checksum 其中有一個在fileDstchecksum hash表中找不到匹配項,那麼就會觸發算法對fileSrcrolling動做。因而,算法會住後step 1個字節,取fileSrc中字節2-513的文件塊要作checksum,go to (1.) – 如今你明白什麼叫rolling checksum了吧。
  4. 這樣,咱們就能夠找出fileSrc相鄰兩次匹配中的那些文本字符,這些就是咱們要往同步目標端傳的文件內容了。

5. 傳輸

圖片描述
最終在同步源這端,咱們的rsync算法可能會獲得這個樣子的一個數據數組,圖中,紅色塊表示在目標端已匹配上,不用傳輸(注:我專門在其中顯示了兩塊chunk #5,表明數據中有複製的地方,不用傳輸),而白色的地方就是須要傳輸的內容(注意:這些白色的塊是不定長的),這樣,同步源這端把這個數組(白色的就是實際內容,紅色的就放一個標號)壓縮傳到目的端,在目的端的rsync會根據這個表從新生成文件,這樣,同步完成。

最後想說一下,對於某些壓縮文件使用rsync傳輸可能會傳得更多,由於被壓縮後的文件可能會很是的不一樣。對此,對於gzipbzip2這樣的命令,記得開啓 「rsyncalbe」 模式。

rsync的使用

一樣的,這一小節內容也是大幅度轉載了 第2章 rsync(一):基本命令和用法 的內容,由於原文章很全面,感興趣的能夠直接查看原文。

rsync是實現增量備份的工具。配合任務計劃,rsync能實現定時或間隔同步,配合inotifysersync,能夠實現觸發式的實時同步。它的目的是實現本地主機和遠程主機上的文件同步(包括本地推到遠程,遠程拉到本地兩種同步方式),也能夠實現本地不一樣路徑下文件的同步,但不能實現遠程路徑1到遠程路徑2之間的同步(scp能夠實現)。

rsync同步過程當中由兩部分組成:決定哪些文件須要同步的檢查模式以及文件同步時的同步模式。

  1. 檢查模式是指按照指定規則來檢查哪些文件須要被同步,例如哪些文件是明確被排除不傳輸的。默認狀況下,rsync使用"quick check"算法快速檢查源文件和目標文件的大小、mtime(修改時間)是否一致,若是不一致則須要傳輸。固然,也能夠經過在rsync命令行中指定某些選項來改變quick check的檢查模式,好比"--size-only"選項表示"quick check"將僅檢查文件大小不一樣的文件做爲待傳輸文件。rsync支持很是多的選項,其中檢查模式的自定義性是很是有彈性的。
  2. 同步模式是指在文件肯定要被同步後,在同步過程發生以前要作哪些額外工做。例如上文所說的是否要先刪除源主機上沒有但目標主機上有的文件,是否要先備份已存在的目標文件,是否要追蹤連接文件等額外操做。rsync也提供很是多的選項使得同步模式變得更具彈性。

相對來講,爲rsync手動指定同步模式的選項更常見一些,只有在有特殊需求時才指定檢查模式,由於大多數檢查模式選項均可能會影響rsync的性能。

rsync四種工做方式

rsync的基礎語法爲:rsync [OPTION...] SRC... [DEST]

支持的參數高達一百多個,最經常使用的選項組合是"avz",即壓縮和顯示部分信息,並以歸檔模式傳輸。詳細的能夠參考 博客園-man rsync翻譯(rsync命令中文手冊),下面是部分參數說明:

-v:顯示rsync過程當中詳細信息。可使用"-vvvv"獲取更詳細信息。
-P:顯示文件傳輸的進度信息。(實際上"-P"="--partial --progress",其中的"--progress"纔是顯示進度信息的)。
-n --dry-run  :僅測試傳輸,而不實際傳輸。常和"-vvvv"配合使用來查看rsync是如何工做的。
-a --archive  :歸檔模式,表示遞歸傳輸並保持文件屬性。等同於"-rtopgDl"。
-r --recursive:遞歸到目錄中去。
-t --times:保持mtime屬性。強烈建議任什麼時候候都加上"-t",不然目標文件mtime會設置爲系統時間,致使下次更新
          :檢查出mtime不一樣從而致使增量傳輸無效。
-o --owner:保持owner屬性(屬主)。
-g --group:保持group屬性(屬組)。
-p --perms:保持perms屬性(權限,不包括特殊權限)。
-D        :是"--device --specials"選項的組合,即也拷貝設備文件和特殊文件。
-l --links:若是文件是軟連接文件,則拷貝軟連接自己而非軟連接所指向的對象。
-z        :傳輸時進行壓縮提升效率。
-R --relative:使用相對路徑。意味着將命令行中指定的全路徑而非路徑最尾部的文件名發送給服務端,包括它們的屬性。用法見下文示例。
--size-only :默認算法是檢查文件大小和mtime不一樣的文件,使用此選項將只檢查文件大小。
-u --update :僅在源mtime比目標已存在文件的mtime新時才拷貝。注意,該選項是接收端判斷的,不會影響刪除行爲。
-d --dirs   :以不遞歸的方式拷貝目錄自己。默認遞歸時,若是源爲"dir1/file1",則不會拷貝dir1目錄,使用該選項將拷貝dir1但不拷貝file1。
--max-size  :限制rsync傳輸的最大文件大小。可使用單位後綴,還能夠是一個小數值(例如:"--max-size=1.5m")
--min-size  :限制rsync傳輸的最小文件大小。這能夠用於禁止傳輸小文件或那些垃圾文件。
--exclude   :指定排除規則來排除不須要傳輸的文件。
--delete    :以SRC爲主,對DEST進行同步。多則刪之,少則補之。注意"--delete"是在接收端執行的,因此它是在
            :exclude/include規則生效以後才執行的。
-b --backup :對目標上已存在的文件作一個備份,備份的文件名後默認使用"~"作後綴。
--backup-dir:指定備份文件的保存路徑。不指定時默認和待備份文件保存在同一目錄下。
-e          :指定所要使用的遠程shell程序,默認爲ssh。
--port      :鏈接daemon時使用的端口號,默認爲873端口。
--password-file:daemon模式時的密碼文件,能夠從中讀取密碼實現非交互式。注意,這不是遠程shell認證的密碼,而是rsync模塊認證的密碼。
-W --whole-file:rsync將再也不使用增量傳輸,而是全量傳輸。在網絡帶寬高於磁盤帶寬時,該選項比增量傳輸更高效。
--existing  :要求只更新目標端已存在的文件,目標端還不存在的文件不傳輸。注意,使用相對路徑時若是上層目錄不存在也不會傳輸。
--ignore-existing:要求只更新目標端不存在的文件。和"--existing"結合使用有特殊功能,見下文示例。
--remove-source-files:要求刪除源端已經成功傳輸的文件。

1. 本地文件系統上實現同步

rsync [OPTION...] SRC... [DEST]

2. 本地主機使用遠程shell和遠程主機通訊

Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST]
  Push: rsync [OPTION...] SRC... [USER@]HOST:DEST

3. 本地主機經過網絡套接字鏈接遠程主機上的rsync daemon

Pull: rsync [OPTION...] [USER@]HOST::SRC... [DEST]
        rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST]
  Push: rsync [OPTION...] SRC... [USER@]HOST::DEST
        rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST

前二者的本質是經過管道通訊,即便是遠程shell。而方式(3)則是讓遠程主機上運行rsync服務,使其監聽在一個端口上,等待客戶端的鏈接。

路徑的格式能夠是本地路徑,也能夠是使用user@host:pathuser@host::path的遠程路徑,若是主機和path路徑之間使用單個冒號隔開,表示使用的是遠程shell通訊方式,而使用雙冒號隔開的則表示的是鏈接rsync daemon。另外,鏈接rsync daemon時,還提供了URL格式的路徑表述方式rsync://user@host/path

4. 遠程shell臨時啓動一個rsync daemon

rsync [options] --rsh=ssh auth_user@host::module
rsync [options] --rsh="ssh -l ssh_user" auth_user@host::module
rsync [options] -e "ssh -l ssh_user" auth_user@host::module
rsync [options] -e "ssh -l ssh_user" rsync://auth_user@host/module

這不一樣於方式(3),它不要求遠程主機上事先啓動rsync服務,而是臨時派生出rsync daemon,它是單用途的一次性daemon,僅用於臨時讀取daemon的配置文件,當這次rsync同步完成,遠程shell啓動的rsync daemon進程也會自動消逝。此通訊方式的命令行語法格式同"Access via rsync daemon",但要求options部分必須明確指定"--rsh"選項或其短選項"-e"

一些用法示例

# 將/etc/fstab拷貝到/tmp目錄下
rsync /etc/fstab /tmp
# 將/etc/cron.d目錄拷貝到/tmp下
rsync -r /etc/cron.d /tmp
# 將/etc/cron.d目錄拷貝到/tmp下,但要求在/tmp下也生成etc子目
rsync -R -r /etc/cron.d /tmp
# 拷貝源路徑較長,但只保留一部分目錄結構,使用一個點表明相對路徑的起始位置
rsync -R -r /var/./log/anaconda /tmp
# 對遠程目錄下已存在文件作備份,備份後綴爲"~",使用"--suffix"指定後綴
rsync -R -r --backup /var/./log/anaconda /tmp
# 指定備份文件保存路徑,默認將不會加備份後綴,使用"--suffix"顯式指定後綴
rsync -R -r --backup --backup-dir=/tmp/log_back /var/./log/anaconda /tmp
# .指定ssh鏈接參數,如端口、鏈接的用戶、ssh選項等
rsync -e "ssh -p 22 -o StrictHostKeyChecking=no" /etc/fstab 172.16.10.5:/tmp
# 使用"--existing"選項使得只更新目標端已存在的文件
rsync -r -v --existing /tmp/a/ /tmp/b           
# "--ignore-existing"更新目標端不存在的文件
rsync -r -v --ignore-existing /tmp/a/ /tmp/b
# "--remove-source-files"刪除源端文件
rsync -r -v --remove-source-files /tmp/a/anaconda /tmp/a/audit /tmp
# 使用"--exclude"選項指定排除規則,排除那些不須要傳輸的文件。
rsync -r -v --exclude="anaconda/*.log" /var/log/anaconda /var/log/audit /tmp

若是僅有一個SRCDEST參數,則將以相似於"ls -l"的方式列出源文件列表(只有一個路徑參數,總會認爲是源文件),而不是複製文件。

源路徑若是是一個目錄的話,帶上尾隨斜線和不帶尾隨斜線是不同的,不帶尾隨斜線表示的是整個目錄包括目錄自己,帶上尾隨斜線表示的是目錄中的文件,不包括目錄自己。

# 在/tmp目錄下建立etc目錄
[root@xuexi ~]# rsync -a /etc /tmp
# 不會在/tmp目錄下建立etc目錄,源路徑/etc/中的全部文件都直接放在/tmp目錄下
[root@xuexi ~]# rsync -a /etc/ /tmp

參考資料

  1. 酷殼-RSYNC 的核心算法:https://coolshell.cn/articles...
  2. The rsync algorithm:https://rsync.samba.org/tech_...
  3. 博客園-rsync(一):基本命令和用法:http://www.cnblogs.com/f-ck-n...
  4. 博客園-man rsync翻譯(rsync命令中文手冊): http://www.cnblogs.com/f-ck-n...
相關文章
相關標籤/搜索