使用rsync

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

增量同步算法

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

1. 分塊Checksum算法

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

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

2. 傳輸算法

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

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

3. checksum查找算法

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

4. 比對算法

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

5. 傳輸

最終在同步源這端,咱們的rsync算法可能會獲得這個樣子的一個數據數組,同步源這端把這個數組位置和數據壓縮傳到目的端,在目的端的rsync會根據這個表從新生成文件,這樣,同步完成。ssh

rsync使用

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

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

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

rsync四種工做方式

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

rsync支持的參數高達一百多個,最經常使用的選項組合是"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:path或user@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

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

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

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

參考資料

rsync核心算法原理
rsync基本命令和用法

相關文章
相關標籤/搜索