如下是rsync系列篇:
1.rsync(一):基本命令和用法
2.rsync(二):inotify+rsync詳細說明和sersync
3.rsync算法原理和工做流程分析
4.rsync技術報告(翻譯)
5.rsync工做機制(翻譯)
6.man rsync翻譯(rsync命令中文手冊)html
rsync官方網站: https://www.samba.org/ftp/rsync/rsync.htmllinux
rsync是能夠實現增量備份的工具。配合任務計劃,rsync能實現定時或間隔同步,配合inotify或sersync,能夠實現觸發式的實時同步。web
rsync能夠實現scp的遠程拷貝(rsync不支持遠程到遠程的拷貝,但scp支持)、cp的本地拷貝、rm刪除和"ls -l"顯示文件列表等功能。但須要注意的是,rsync的最終目的或者說其原始目的是實現兩端主機的文件同步,所以實現的scp/cp/rm等功能僅僅只是同步的輔助手段,且rsync實現這些功能的方式和這些命令是不同的。事實上,rsync有一套本身的算法,其算法原理以及rsync對算法實現的機制可能比想象中要複雜一些。平時使用rsync實現簡單的備份、同步等功能足以,沒有多大必要去深究這些原理性的內容。可是想要看懂rsync命令的man文檔、使用"-vvvv"分析rsync執行過程,以及實現rsync更強大更完整的功能,沒有這些理論知識的支持是絕對不可能實現的。本篇文章將簡單介紹rsync的使用方法和它經常使用的功能。在本篇文章以後的下幾篇文章中,將介紹inotify+rsync和sersync,再以後將詳細解釋rsync相關的原理,其中包括官方技術報告的翻譯(即算法原理)、rsync同步的整個過程(也是官方推薦文章的翻譯),而後專門使用一篇文章經過示例來詳細解釋rsync算法原理,最後給出rsync的man文檔翻譯。但願各位朋友能藉此深刻rsync。算法
迴歸正題,如下是rsync相關基礎內容。shell
rsync的目的是實現本地主機和遠程主機上的文件同步(包括本地推到遠程,遠程拉到本地兩種同步方式),也能夠實現本地不一樣路徑下文件的同步,但不能實現遠程路徑1到遠程路徑2之間的同步(scp能夠實現)。數據庫
不考慮rsync的實現細節,就文件同步而言,涉及了源文件和目標文件的概念,還涉及了以哪邊文件爲同步基準。例如,想讓目標主機上的文件和本地文件保持同步,則是以本地文件爲同步基準,將本地文件做爲源文件推送到目標主機上。反之,若是想讓本地主機上的文件和目標主機上的文件保持同步,則目標主機上的文件爲同步基準,實現方式是將目標主機上的文件做爲源文件拉取到本地。固然,要保持本地的兩個文件相互同步,rsync也同樣能實現,這就像Linux中cp命令同樣,以本地某文件做爲源,另外一文件做爲目標文件,但請注意,雖然rsync和cp能達到相同的目的,但它們的實現方式是不同的。bash
既然是文件同步,在同步過程當中必然會涉及到源和目標兩文件之間版本控制的問題,例如是否要刪除源主機上沒有但目標上多出來的文件,目標文件比源文件更新(newer than source)時是否仍要保持同步,遇到軟連接時是拷貝軟連接自己仍是拷貝軟連接所指向的文件,目標文件已存在時是否要先對其作個備份等等。服務器
rsync同步過程當中由兩部分模式組成:決定哪些文件須要同步的檢查模式以及文件同步時的同步模式。網絡
(1).檢查模式是指按照指定規則來檢查哪些文件須要被同步,例如哪些文件是明確被排除不傳輸的。默認狀況下,rsync使用"quick check"算法快速檢查源文件和目標文件的大小、mtime(修改時間)是否一致,若是不一致則須要傳輸。固然,也能夠經過在rsync命令行中指定某些選項來改變quick check的檢查模式,好比"--size-only"選項表示"quick check"將僅檢查文件大小不一樣的文件做爲待傳輸文件。rsync支持很是多的選項,其中檢查模式的自定義性是很是有彈性的。ssh
(2).同步模式是指在文件肯定要被同步後,在同步過程發生以前要作哪些額外工做。例如上文所說的是否要先刪除源主機上沒有但目標主機上有的文件,是否要先備份已存在的目標文件,是否要追蹤連接文件等額外操做。rsync也提供很是多的選項使得同步模式變得更具彈性。
相對來講,爲rsync手動指定同步模式的選項更常見一些,只有在有特殊需求時才指定檢查模式,由於大多數檢查模式選項均可能會影響rsync的性能。
如下是rsync的語法:
Local: rsync [OPTION...] SRC... [DEST] Access via remote shell: Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST] Push: rsync [OPTION...] SRC... [USER@]HOST:DEST Access via 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
由此語法可知,rsync有三種工做方式:
(1).本地文件系統上實現同步。命令行語法格式爲上述"Local"段的格式。
(2).本地主機使用遠程shell和遠程主機通訊。命令行語法格式爲上述"Access via remote shell"段的格式。
(3).本地主機經過網絡套接字鏈接遠程主機上的rsync daemon。命令行語法格式爲上述"Access via rsync daemon"段的格式。
前二者的本質是經過管道通訊,即便是遠程shell。而方式(3)則是讓遠程主機上運行rsync服務,使其監聽在一個端口上,等待客戶端的鏈接。
可是,還有第四種工做方式:經過遠程shell也能臨時啓動一個rsync daemon,這不一樣於方式(3),它不要求遠程主機上事先啓動rsync服務,而是臨時派生出rsync daemon,它是單用途的一次性daemon,僅用於臨時讀取daemon的配置文件,當這次rsync同步完成,遠程shell啓動的rsync daemon進程也會自動消逝。此通訊方式的命令行語法格式同"Access via rsync daemon",但要求options部分必須明確指定"--rsh"選項或其短選項"-e"。
如下是對rsync語法的簡單說明,因爲rsync支持一百多個選項,因此此處只介紹幾個經常使用選項。完整的選項說明以及rsync的使用方法見我翻譯的"man rsync"。
Local: rsync [OPTION...] SRC... [DEST]
Access via remote shell:
Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST]
Push: rsync [OPTION...] SRC... [USER@]HOST:DEST
Access via 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
其中,第一個路徑參數必定是源文件路徑,即做爲同步基準的一方,能夠同時指定多個源文件路徑。最後一個路徑參數則是目標文件路徑,也就是待同步方。路徑的格式能夠是本地路徑,也能夠是使用user@host:path或user@host::path的遠程路徑,若是主機和path路徑之間使用單個冒號隔開,表示使用的是遠程shell通訊方式,而使用雙冒號隔開的則表示的是鏈接rsync daemon。另外,鏈接rsync daemon時,還提供了URL格式的路徑表述方式rsync://user@host/path。
若是僅有一個SRC或DEST參數,則將以相似於"ls -l"的方式列出源文件列表(只有一個路徑參數,總會認爲是源文件),而不是複製文件。
若是對rsync不熟悉,可暫先只瞭解本地以及遠程shell格式的user@host:path路徑格式。例如:
[root@xuexi ~]# rsync /etc/fstab /tmp # 在本地同步 [root@xuexi ~]# rsync -r /etc 172.16.10.5:/tmp # 將本地/etc目錄拷貝到遠程主機的/tmp下,以保證遠程/tmp目錄和本地/etc保持同步 [root@xuexi ~]# rsync -r 172.16.10.5:/etc /tmp # 將遠程主機的/etc目錄拷貝到本地/tmp下,以保證本地/tmp目錄和遠程/etc保持同步 [root@xuexi ~]# rsync /etc/ # 列出本地/etc/目錄下的文件列表 [root@xuexi ~]# rsync 172.16.10.5:/tmp/ # 列出遠程主機上/tmp/目錄下的文件列表
另外,使用rsync必定要注意的一點是,源路徑若是是一個目錄的話,帶上尾隨斜線和不帶尾隨斜線是不同的,不帶尾隨斜線表示的是整個目錄包括目錄自己,帶上尾隨斜線表示的是目錄中的文件,不包括目錄自己。例如:
[root@xuexi ~]# rsync -a /etc /tmp
[root@xuexi ~]# rsync -a /etc/ /tmp
第一個命令會在/tmp目錄下建立etc目錄,而第二個命令不會在/tmp目錄下建立etc目錄,源路徑/etc/中的全部文件都直接放在/tmp目錄下。
接下來是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:要求刪除源端已經成功傳輸的文件。
rsync的選項很是多,可以實現很是具備彈性的功能,以上選項僅僅只是很小一部分經常使用的選項,關於更完整更詳細的選項說明,見個人rsync man手冊翻譯。
雖然選項很是多,但最經常使用的選項組合是"avz",即壓縮和顯示部分信息,並以歸檔模式傳輸。
如下是幾個本地同步示例和經過遠程shell實現的同步示例,示例中沒有使用"-a"選項,目的是爲了更清晰地說明各選項的做用。
(1).將/etc/fstab拷貝到/tmp目錄下。
[root@xuexi ~]# rsync /etc/fstab /tmp
(2).將/etc/cron.d目錄拷貝到/tmp下。
[root@xuexi ~]# rsync -r /etc/cron.d /tmp
該命令會在目標主機上建立/tmp/cron.d目錄,並將/etc/cron.d/中的文件放入到/tmp/cron.d/目錄中,也就是說默認狀況下,是不會在目錄路徑下建立上層目錄/etc的。
(3).將/etc/cron.d目錄拷貝到/tmp下,但要求在/tmp下也生成etc子目錄。
[root@xuexi ~]# rsync -R -r /etc/cron.d /tmp
其中"-R"選項表示使用相對路徑,此相對路徑是以目標目錄爲根的。對於上面的示例,表示在目標上的/tmp下建立etc/cron.d目錄,即/tmp/etc/cron.d,etc/cron.d的根"/"表明的就是目標/tmp。
若是要拷貝的源路徑較長,但只想在目標主機上保留一部分目錄結構,例如要拷貝/var/log/anaconda/*到/tmp下,但只想在/tmp下保留從log開始的目錄,如何操做?使用一個點表明相對路徑的起始位置便可,也就是將長目錄進行劃分。
[root@xuexi ~]# rsync -R -r /var/./log/anaconda /tmp
這樣,從點開始的目錄都是相對路徑,其相對根目錄爲目標路徑。因此對於上面的示例,將在目標上建立/tmp/log/anaconda/*。
(4).對遠程目錄下已存在文件作一個備份。
[root@xuexi ~]# rsync -R -r --backup /var/./log/anaconda /tmp
這樣在目標目錄下,已存在的文件就被作一個備份,備份文件默認使用"~"作後綴,可使用"--suffix"指定備份後綴。
[root@xuexi tmp]# ll log/anaconda/ total 3112 -rw------- 1 root root 6668 Jul 14 12:45 anaconda.log -rw------- 1 root root 6668 Jul 14 11:44 anaconda.log~ -rw------- 1 root root 3826 Jul 14 12:45 ifcfg.log -rw------- 1 root root 3826 Jul 14 11:44 ifcfg.log~ -rw------- 1 root root 1102699 Jul 14 12:45 journal.log -rw------- 1 root root 1102699 Jul 14 11:44 journal.log~ -rw------- 1 root root 0 Jul 14 12:45 ks-script-1uLekR.log -rw------- 1 root root 0 Jul 14 11:44 ks-script-1uLekR.log~ -rw------- 1 root root 0 Jul 14 12:45 ks-script-iGpl4q.log -rw------- 1 root root 0 Jul 14 11:44 ks-script-iGpl4q.log~ -rw------- 1 root root 160420 Jul 14 12:45 packaging.log -rw------- 1 root root 160420 Jul 14 11:44 packaging.log~ -rw------- 1 root root 27906 Jul 14 12:45 program.log -rw------- 1 root root 27906 Jul 14 11:44 program.log~ -rw------- 1 root root 78001 Jul 14 12:45 storage.log -rw------- 1 root root 78001 Jul 14 11:44 storage.log~ -rw------- 1 root root 197961 Jul 14 12:45 syslog -rw------- 1 root root 197961 Jul 14 11:44 syslog~
可使用"--backup-dir"指定備份文件保存路徑,但要求保存路徑必須存在。
[root@xuexi ~]# mkdir /tmp/log_back [root@xuexi ~]# rsync -R -r --backup --backup-dir=/tmp/log_back /var/./log/anaconda /tmp
指定備份路徑後,默認將不會加備份後綴,除非使用"--suffix"顯式指定後綴,如"--suffix=~"。
[root@xuexi tmp]# tree /tmp/log_back/ /tmp/log_back/ └── log └── anaconda ├── anaconda.log ├── ifcfg.log ├── journal.log ├── ks-script-1uLekR.log ├── ks-script-iGpl4q.log ├── packaging.log ├── program.log ├── storage.log └── syslog
(5).指定ssh鏈接參數,如端口、鏈接的用戶、ssh選項等。
[root@xuexi tmp]# >~/.ssh/known_hosts # 先清空host key以便下面的測試 [root@xuexi tmp]# rsync -e "ssh -p 22 -o StrictHostKeyChecking=no" /etc/fstab 172.16.10.5:/tmp Warning: Permanently added '172.16.10.5' (RSA) to the list of known hosts. root@172.16.10.5's password:
可見直接指定ssh參數是生效的。
(6)."--existing"和"--ignore-existing"
"--existing"是隻更新目標端已存在的文件。
目前/tmp/{a,b}目錄中內容以下,bashrc在a目錄中,crontab在b目錄中,且a目錄中多了一個c子目錄。
[root@xuexi ~]# tree /tmp/{a,b} /tmp/a ├── bashrc ├── c │ └── find ├── fstab ├── profile └── rc.local /tmp/b ├── crontab ├── fstab ├── profile └── rc.local 1 directory, 9 files
使用"--existing"選項使得只更新目標端已存在的文件。
[root@xuexi ~]# rsync -r -v --existing /tmp/a/ /tmp/b sending incremental file list fstab profile rc.local sent 2972 bytes received 70 bytes 6084.00 bytes/sec total size is 204755 speedup is 67.31
結果只有3個目標上已存在的文件被更新了,因爲目標上沒有c目錄,因此c目錄中的文件也沒有進行傳輸。
而"--ignore-existing"是更新目標端不存在的文件。
[root@xuexi ~]# rsync -r -v --ignore-existing /tmp/a/ /tmp/b sending incremental file list bashrc c/ c/find sent 202271 bytes received 54 bytes 404650.00 bytes/sec total size is 204755 speedup is 1.01
"--existing"和"--ignore-existing"結合使用時,有個特殊功效,當它們結合"--delete"使用的時候,文件不會傳輸,但會刪除receiver端額外多出的文件。
$ mkdir a b $ touch a/{1..4}.txt $ touch b/a.log $ rsync -nrv --delete a/ b/ sending incremental file list deleting a.log 1.txt 2.txt 3.txt 4.txt sent 118 bytes received 33 bytes 302.00 bytes/sec total size is 0 speedup is 0.00 (DRY RUN) $ rsync -nrv --existing --ignore-existing --delete a/ b/ sending incremental file list deleting a.log sent 106 bytes received 21 bytes 254.00 bytes/sec total size is 0 speedup is 0.00 (DRY RUN)
實際上,"--existing"和"--ingore-existing"是傳輸規則,只會影響receiver要求讓sender傳輸的文件列表,在receiver決定哪些文件須要傳輸以前的過程,是這兩個選項沒法掌控的,因此各類規則、"--delete"等操做都不會被這兩個選項影響。
(7)."--remove-source-files"刪除源端文件。
使用該選項後,源端已經更新成功的文件都會被刪除,源端全部未傳輸或未傳輸成功的文件都不會被移除。未傳輸成功的緣由有多種,如exclude排除了,"quick check"未選項該文件,傳輸中斷等等。
總之,顯示在"rsync -v"被傳輸列表中的文件都會被移除。以下:
[root@xuexi ~]# rsync -r -v --remove-source-files /tmp/a/anaconda /tmp/a/audit /tmp sending incremental file list anaconda/anaconda.log anaconda/ifcfg.log anaconda/journal.log anaconda/ks-script-1uLekR.log anaconda/ks-script-iGpl4q.log anaconda/packaging.log anaconda/program.log anaconda/storage.log anaconda/syslog audit/audit.log sent 4806915 bytes received 204 bytes 9614238.00 bytes/sec total size is 4805676 speedup is 1.00
上述顯示出來的文件在源端所有被刪除。
使用"--exclude"選項指定排除規則,排除那些不須要傳輸的文件。
[root@xuexi tmp]# rsync -r -v --exclude="anaconda/*.log" /var/log/anaconda /var/log/audit /tmp sending incremental file list anaconda/ anaconda/syslog audit/ audit/audit.log sent 3365629 bytes received 58 bytes 6731374.00 bytes/sec total size is 3365016 speedup is 1.00
上例中只排除了anaconda目錄中的log文件,可是audit目錄中的log文件是正常傳輸的。
注意,一個"--exclude"只能指定一條規則,要指定多條排除規則,須要使用多個"--exclude"選項,或者將排除規則寫入到文件中,而後使用"--exclude-from"選項讀取該規則文件。
另外,除了"--exclude"排除規則,還有"--include"包含規則,顧名思義,它就是篩選出要進行傳輸的文件,因此include規則也稱爲傳輸規則。它的使用方法和"--exclude"同樣。若是一個文件即能匹配排除規則,又能匹配包含規則,則先匹配到的當即生效,生效後就再也不進行任何匹配。
最後,關於規則,最重要的一點是它的做用時間。當發送端敲出rsync命令後,rsync將當即掃描命令行中給定的文件和目錄(掃描過程當中還會按照目錄進行排序,將同一個目錄的文件放在相鄰的位置),這稱爲拷貝樹(copy tree),掃描完成後將待傳輸的文件或目錄記錄到文件列表中,而後將文件列表傳輸給接收端。而篩選規則的做用時刻是在掃描拷貝樹時,因此會根據規則來匹配並決定文件是否記錄到文件列表中(嚴格地說是會記錄到文件列表中的,只不過排除的文件會被標記爲hide隱藏起來),只有記錄到了文件列表中的文件或目錄纔是真正須要傳輸的內容。換句話說,篩選規則的生效時間在rsync整個同步過程當中是很是靠前的,它會影響不少選項的操做對象,最典型的如"--delete"。也許,你看完這一整篇文章都沒感受到這一點的重要性,但若是你閱讀rsync的man文檔或者學習rsync的原理,你必定會深有體會。
實際上,排除規則和包含規則都只是"--filter"篩選規則的兩種特殊規則。"--filter"比較複雜,它有本身的規則語法和匹配模式,因爲篇幅有限,以及考慮到本文的難度定位,"--filter"規則不便在此多作解釋,僅簡單說明下規則類,幫助理解下文的"--delete"。
如下是rsync中的規則種類,不解之處請結合下文的"--delete"分析:
(1).exclude規則:即排除規則,只做用於發送端,被排除的文件不會進入文件列表(其實是加上隱藏規則進行隱藏)。
(2).include規則:即包含規則,也稱爲傳輸規則,只做用於發送端,被包含的文件將明確記錄到文件列表中。
(3).hide規則:即隱藏規則,只做用於發送端,隱藏後的文件對於接收端來講是看不見的,也就是說接收端會認爲它不存在於源端。
(4).show規則:即顯示規則,只做用於發送端,是隱藏規則的反向規則。
(5).protect規則:即保護規則,該規則只做用於接收端,被保護的文件不會被刪除掉。
(6).risk規則:即取消保護規則。是protect的反向規則。
除此以外,還有一種規則是"clear規則",做用是刪除include/exclude規則列表。
不少人寫不來規則,總髮現寫出來後沒有生效,要寫成功一次規則得要不斷地進行調試、調試、調試,使人無比心煩。
其實不少工具的規則寫法是相似的,好比tar也同樣。規則寫好後不生效的緣由通常有兩種:絕對路徑和相對路徑的問題、尾隨斜線的問題。
通常來講,操做的路徑是絕對路徑,那麼規則裏必須也寫絕對路徑,並且必須寫完整的絕對路徑。操做的路徑是相對路徑,那麼規則裏必須寫相對路徑,從哪裏開始相對可能和工具備關。好比要操做路徑"/abc/def",想要篩選def下的全部txt文件,必須寫成"/abc/def/*.txt",若是操做路徑是"abc/def",那麼要篩選這個目錄下的全部txt文件,可能須要寫成"abc/def/*.txt",也有可能寫成"*.txt",甚至寫成"def/*.txt",寫成哪一種形式依賴於這個軟件如何解析相對路徑。
對於rsync來講,要更復雜一些,由於除了bash的相對路徑外,它自身還提供了一個相對路徑的解析規則,並且尾隨斜線也會影響規則的寫法。這就是爲何寫rsync規則很是麻煩的緣由。
我這裏提供一個判斷規則寫法的方式,純屬我我的的經驗總結:使用"-n"選項是dry run模式,也就是隻測試不傳輸,"-i"選項是輸出要傳輸文件的路徑。"-i"只是一個便捷性選項,能夠替換成其它選項來自定義輸出格式,有時候經過這些信息來作一些判斷是很是有用的,具體的能夠翻man手冊。
root:~$ rsync -nr -i a b/ cd+++++++++ a/ >f+++++++++ a/1.txt >f+++++++++ a/2.txt >f+++++++++ a/3.txt >f+++++++++ a/4.txt
這裏已經顯示了傳輸文件的路徑"a/*",也就是說包括了目錄a,且是相對路徑的。因此要寫規則時,須要加上這個a路徑,好比下面的排除規則。
root:~$ rsync -nr -i --exclude="a/2.txt" a b/ cd+++++++++ a/ >f+++++++++ a/1.txt >f+++++++++ a/3.txt >f+++++++++ a/4.txt root:~$ rsync -nr -i --exclude="a/*.txt" a b/ cd+++++++++ a/
若是上面的傳輸路徑a加上尾隨斜線,再看-i的輸出路徑信息,發現已經改變了:
root:~$ rsync -nr -i a/ b/ >f+++++++++ 1.txt >f+++++++++ 2.txt >f+++++++++ 3.txt >f+++++++++ 4.txt
因此這時的排除規則中不該該包含a目錄前綴:
root:~$ rsync -nr -i --exclude="2.txt" ./a/ b/ >f+++++++++ 1.txt >f+++++++++ 3.txt >f+++++++++ 4.txt
使用"--delete"選項後,接收端的rsync會先刪除目標目錄下已經存在,但源端目錄不存在的文件。也就是"多則刪之,少則補之"。
例如,先實現一次同步,再向目標目錄中拷貝一個新文件,這樣目標目錄中就比源目錄多出一個文件。
[root@xuexi ~]# rsync -r /etc/cron.d /tmp/ [root@xuexi ~]# cp /etc/fstab /tmp/cron.d/ [root@xuexi ~]# ls /tmp/cron.d/ 0hourly fstab raid-check sysstat
再使用"--delete"選項,這時會將目標端多出的文件給刪除掉,而後進行同步。
[root@xuexi ~]# rsync -r -v /etc/cron.d /tmp --delete sending incremental file list deleting cron.d/fstab cron.d/0hourly cron.d/raid-check cron.d/sysstat sent 704 bytes received 70 bytes 1548.00 bytes/sec total size is 471 speedup is 0.61
這樣的行爲實現了遠程刪除的功能,對於做用於本地的rsync,也就實現了rm的本地刪除功能。並且,若是使用空目錄做爲源目錄,則它的做用是清空目錄上的整個目錄。
若是將"--delete"選項和"--exclude"選項一塊兒使用,則被排除的文件不會被刪除。例如:
[root@xuexi ~]# rsync -r /var/log/anaconda /var/log/audit /tmp # 先進行一次同步以便測試 [root@xuexi ~]# cp /etc/fstab /tmp/anaconda/ # 拷貝一個新文件到目標目錄以便測試 [root@xuexi ~]# rsync -r -v --exclude="anaconda/*.log" /var/log/anaconda /var/log/audit /tmp --delete sending incremental file list deleting anaconda/fstab anaconda/syslog audit/audit.log sent 3406190 bytes received 52 bytes 6812484.00 bytes/sec total size is 3405579 speedup is 1.00
結果發現只刪除了"anaconda/fstab"文件,被"--exclude"規則匹配的anaconda/*.log文件都沒有被刪除。也就是網上所說的言論:exclude排除的文件不會被刪除。
結論是沒錯的,但我想不少人不知道爲什麼會如此,也可能歷來沒想過爲什麼會如此,因此我簡單地作個說明。
在發送端將文件列表發送給接收端後,接收端的generator(要是不知道,你認爲是某個就行了)進程會掃描每一個文件列表中的信息,而後對列表中的每一個信息條目都計算數據塊校驗碼,最後將數據庫校驗碼發給發送端,發送端經過校驗碼來匹配哪些數據塊是須要傳輸的,這樣就實現了增量傳輸的功能——只傳輸改變的部分,不會傳輸整個文件。而delete刪除的時間點是generator進程處理每一個文件列表時、生成校驗碼以前進行的,先將目標上存在但源上不存在的多餘文件刪除,這樣就無需爲多餘的文件生成校驗碼。
因此,delete動做是比"--exclude"規則更晚執行的,被"--exclude"規則排除的文件不會進入文件列表中,在執行了delete時會認爲該文件不存在於源端,從而致使目標端將這些文件刪除。但這是想固然的,儘管理論上確實是這樣的,可是rsync爲了防止衆多誤刪除狀況,提供了兩種規則:保護規則(protect)和取消保護規則(risk)。默認狀況下,"--delete"和"--exclude"一塊兒使用時,雖然發送端的exclude規則將文件標記爲隱藏,使得接收端認爲這些被排除文件在源端不存在,但rsync會將這些隱藏文件標記爲保護文件,使得它們不受delete行爲的影響,這樣delete就刪除不了這些被排除的文件。若是仍是想要強行刪除被exclude排除的文件,可使用"--delete-excluded"選項強制取消保護,這樣即便被排除的文件也會被刪除。
那麼如今,是否理解了網上的言論"exclude排除的文件不會被刪除"?
除了"--delete",相關的選項還有"--delete-before"、"--delete-during"、"--delete-delay"等,它們都隱含了"--delete"選項,它們分別表示generator處理各個文件列表以前一次性所有刪除待刪除文件、處理文件列表時處理到哪一個文件列表就刪除該文件列表中的待刪除文件,以及同步完全部數據後一次性刪除全部待刪除文件。
舉個例子,假如源端要傳輸3個目錄a、b、c,在目標端a目錄中有a一、a二、a3共3個文件須要被刪除,b目錄中有b一、b二、b3須要刪除,同理c目錄也同樣c一、c二、c3須要被刪除。
若是是"--delete-before",則在目標端rsync剛啓動時,就會把a1-a三、b1-b三、c1-c3一次性刪除,而後纔會處理文件列表中的a目錄,處理完a後處理b,再是c。
若是是"--delete-during",則在目標端rsync剛啓動時,先處理文件列表中的a目錄,處理a目錄時發現此目錄中有待刪除文件a1-a3,順手就刪除它們,而後完成a目錄的相關操做,再處理文件列表中的b目錄,發現也有待刪除文件b1-b3,順手刪除它們,同理c1-c3也如此。
若是是"--delete-delay",則同步完文件列表中的a/b/c目錄後,最後一次性刪除a1-a三、b1-b三、c1-c3。
其實"--delete"選項大多數狀況下默認採用的就是"--delete-during"。
既然rsync經過遠程shell就能實現兩端主機上的文件同步,還要使用rsync的服務幹啥?試想下,你有的機器上有一堆文件須要時不時地同步到衆多機器上去,好比目錄a、b、c是專門傳輸到web服務器上的,d/e、f、g/h是專門傳輸到ftp服務器上的,還要對這些目錄中的某些文件進行排除,若是經過遠程shell鏈接方式,不管是使用排除規則仍是包含規則,甚至一條一條rsync命令地傳輸,這都沒問題,但太過繁瑣且每次都要輸入一樣的命令顯得太死板。使用rsync daemon就能夠解決這種死板問題。並且,rsync daemon是向外提供服務的,這樣只要告訴了別人rsync的url路徑,外人就能向ftp服務器同樣獲取文件列表並進行選擇性地下載,因此,你所制定的列表,你的同事也能夠獲取到並使用。
舉個簡單的例子,Linux內核官網www.kernel.org提供rsync的下載方式,官方給出的地址是rsync://rsync.kernel.org/pub,能夠根據這個地址找出你想下載的內核版本。例如要找出linux-3.0.15版本的內核相關文件。
[root@xuexi ~]# rsync --no-motd -r -v -f "+ */" -f "+ linux-3.0.15*" -f "- *" -m rsync://rsync.kernel.org/pub/ receiving file list ... done drwxr-xr-x 124 2017/07/14 20:27:22 . drwxr-xr-x 178 2014/11/12 05:50:10 linux drwxr-xr-x 4096 2017/06/27 05:46:27 linux/kernel drwxr-xr-x 237568 2017/07/05 20:49:33 linux/kernel/v3.x -rw-r--r-- 76803806 2012/01/04 03:00:31 linux/kernel/v3.x/linux-3.0.15.tar.bz2 -rw-r--r-- 96726195 2012/01/04 03:00:31 linux/kernel/v3.x/linux-3.0.15.tar.gz -rw-r--r-- 836 2012/01/04 03:00:31 linux/kernel/v3.x/linux-3.0.15.tar.sign -rw-r--r-- 63812604 2012/01/04 03:00:31 linux/kernel/v3.x/linux-3.0.15.tar.xz sent 59 bytes received 80.19K bytes 12.35K bytes/sec total size is 237.34M speedup is 2957.66
你無需關注上面的規則表明什麼意思,須要關注的重點是經過rsync能夠向外提供文件列表並提供相應的下載。
一樣,你還能夠根據路徑,將rsync daemon上的文件拉取到本地實現下載的功能。
[root@xuexi ~]# rsync --no-motd -avzP rsync://rsync.kernel.org/pub/linux/kernel/v3.x/linux-3.0.15.tar.bz2 /tmp receiving incremental file list linux-3.0.15.tar.bz2 2834426 3% 300.51kB/s 0:40:22
下面就來介紹下rsync daemon。
rsync daemon是"rsync --daemon"或再加上其餘一些選項啓動的,它會讀取配置文件,默認是/etc/rsyncd.conf,並默認監聽在873端口上,當外界有客戶端對此端口發起鏈接請求,經過這個網絡套接字就能夠完成鏈接,之後與該客戶端通訊的全部數據都經過該網絡套接字傳輸。
rsync daemon的通訊方式和傳輸通道與遠程shell不一樣。遠程shell鏈接的兩端是經過管道完成通訊和數據傳輸的,即便鏈接的一端是遠程主機,當鏈接到目標端時,將在目標端上根據遠程shell進程fork出rsync進程使其成爲rsync server。而rsync daemon是事先在server端上運行好的rsync後臺進程(根據啓動選項,也能夠設置爲非後臺進程),它監聽套接字等待client端的鏈接,鏈接創建後全部通訊方式都是經過套接字完成的。
注意,rsync中的server的概念歷來就不表明是rsync daemon,server在rsync中只是一種通用稱呼,只要不是發起rsync請求的client端,就是server端,你能夠認爲rsync daemon是一種特殊的server,其實daemon更應該稱之爲service。(之因此解釋這一點,是避免各位初學的朋友在閱讀man rsync過程當中產生誤解)
如下是rsync client鏈接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
鏈接命令有兩種類型,一種是rsync風格使用雙冒號的"rsync user@host::src dest",一種是url風格的"rsync://user@host:port/src dest"。對於rsync風格的鏈接命令,若是想要指定端口號,則須要使用選項"--port"。
上述語法中,其中daemon端的路徑,如user@host::src,它的src表明的是模塊名,而不是真的文件系統中的路徑。關於rsync中的模塊,相信見了下面的配置文件就會知道是什麼意思。
默認"rsync --daemon"讀取的配置文件爲/etc/rsyncd.conf,有些版本的系統上可能該文件默認不存在。rsyncd.conf的配置見man rsyncd.conf。如下是部份內容:
[root@xuexi ~]# cat /etc/rsyncd.conf # /etc/rsyncd: configuration file for rsync daemon mode # See rsyncd.conf man page for more options. # configuration example: # uid = nobody # gid = nobody # use chroot = yes # max connections = 4 # pid file = /var/run/rsyncd.pid # exclude = lost+found/ # transfer logging = yes # timeout = 900 # ignore nonreadable = yes # dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2 # [ftp1] # path = /home/ftp # comment = ftp export area
在上述示例配置文件中,先定義了一些全局選項,而後定義了[ftp1],這個用中括號包圍的"[ftp1]"就是rsync中所謂的模塊,ftp1爲模塊ID,必須保證惟一,每一個模塊中必須定義一項"path",path定義的是該模塊表明的路徑,例如此示例文件中,若是想請求ftp1模塊,則在客戶端使用"rsync user@host::ftp1",這表示訪問user@host上的/home/ftp目錄,若是要訪問/home/ftp目錄下的子目錄www,則"rsync user@host::ftp1/www"。
如下是常見的配置項,也算是一個配置示例:
######### 全局配置參數 ##########
port=888 # 指定rsync端口。默認873
uid = rsync # rsync服務的運行用戶,默認是nobody,文件傳輸成功後屬主將是這個uid
gid = rsync # rsync服務的運行組,默認是nobody,文件傳輸成功後屬組將是這個gid
use chroot = no # rsync daemon在傳輸前是否切換到指定的path目錄下,並將其監禁在內
max connections = 200 # 指定最大鏈接數量,0表示沒有限制
timeout = 300 # 確保rsync服務器不會永遠等待一個崩潰的客戶端,0表示永遠等待
motd file = /var/rsyncd/rsync.motd # 客戶端鏈接過來顯示的消息
pid file = /var/run/rsyncd.pid # 指定rsync daemon的pid文件
lock file = /var/run/rsync.lock # 指定鎖文件
log file = /var/log/rsyncd.log # 指定rsync的日誌文件,而不把日誌發送給syslog
dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2 # 指定哪些文件不用進行壓縮傳輸
###########下面指定模塊,並設定模塊配置參數,能夠建立多個模塊###########
[longshuai] # 模塊ID
path = /longshuai/ # 指定該模塊的路徑,該參數必須指定。啓動rsync服務前該目錄必須存在。rsync請求訪問模塊本質就是訪問該路徑。
ignore errors # 忽略某些IO錯誤信息
read only = false # 指定該模塊是否可讀寫,即可否上傳文件,false表示可讀寫,true表示可讀不可寫。全部模塊默認不可上傳
write only = false # 指定該模式是否支持下載,設置爲true表示客戶端不能下載。全部模塊默承認下載
list = false # 客戶端請求顯示模塊列表時,該模塊是否顯示出來,設置爲false則該模塊爲隱藏模塊。默認true
hosts allow = 10.0.0.0/24 # 指定容許鏈接到該模塊的機器,多個ip用空格隔開或者設置區間
hosts deny = 0.0.0.0/32 # 指定不容許鏈接到該模塊的機器
auth users = rsync_backup # 指定鏈接到該模塊的用戶列表,只有列表裏的用戶才能鏈接到模塊,用戶名和對應密碼保存在secrts file中,
# 這裏使用的不是系統用戶,而是虛擬用戶。不設置時,默認全部用戶都能鏈接,但使用的是匿名鏈接
secrets file = /etc/rsyncd.passwd # 保存auth users用戶列表的用戶名和密碼,每行包含一個username:passwd。因爲"strict modes"
# 默認爲true,因此此文件要求非rsync daemon用戶不可讀寫。只有啓用了auth users該選項纔有效。
[xiaofang] # 如下定義的是第二個模塊
path=/xiaofang/
read only = false
ignore errors
comment = anyone can access
注意:
(1).客戶端推到服務端時,文件的屬主和屬組是配置文件中指定的uid和gid。可是客戶端從服務端拉的時候,文件的屬主和屬組是客戶端正在操做rsync的用戶身份,由於執行rsync程序的用戶爲當前用戶。
(2).auth users和secrets file這兩行不是必定須要的,省略它們時將默認使用匿名鏈接。可是若是使用了它們,則secrets file的權限必須是600。客戶端的密碼文件也必須是600。
(3).關於secrets file的權限,實際上並不是必定是600,只要知足除了運行rsync daemon的用戶可讀便可。是否檢查權限的設定是經過選項strict mode設置的,若是設置爲false,則無需關注文件的權限。但默認是yes,即須要設置權限。
配置完後,再就是提供模塊相關目錄、身份驗證文件等。
[root@xuexi ~]# useradd -r -s /sbin/nologin rsync [root@xuexi ~]# mkdir /{longshuai,xiaofang} [root@xuexi ~]# chown -R rsync.rsync /{longshuai,xiaofang}
提供模塊longshuai身份驗證文件,因爲rsync daemon是以root身份運行的,因此要求身份驗證文件對非root用戶不可讀寫,因此設置爲600權限。
[root@xuexi ~]# echo "rsync_backup:123456" >> /etc/rsyncd.passwd [root@xuexi ~]# chmod 600 /etc/rsyncd.passwd
而後啓動rsync daemon,啓動方式很簡單。
[root@xuexi ~]# rsync --daemon
若是是CentOS 7,則自帶啓動腳本。
[root@xuexi ~]# systemctl start rsyncd
看看該腳本的內容。
[root@xuexi ~]# cat /usr/lib/systemd/system/rsyncd.service [Unit] Description=fast remote file copy program daemon ConditionPathExists=/etc/rsyncd.conf [Service] EnvironmentFile=/etc/sysconfig/rsyncd ExecStart=/usr/bin/rsync --daemon --no-detach "$OPTIONS" [Install] WantedBy=multi-user.target
能夠看到啓動方法也僅僅只是多了一個"--no-detach",該選項表示rsync不將本身從終端上剝離。
總之,啓動好rysnc daemon後,它就監聽在指定的端口上,等待客戶端的鏈接。
因爲上述示例中的模塊longshuai配置了身份驗證功能,因此客戶端鏈接時會詢問密碼。若是不想手動輸入密碼,則可使用"--password-file"選項提供密碼文件,密碼文件中只有第一行纔是傳遞的密碼,其他全部的行都會被自動忽略。
例如在客戶端上:
[root@xuexi ~]# echo "123456" > /tmp/rsync_passwd
而後使用該"--password-file"鏈接須要身份驗證的longshuai模塊。
[root@xuexi ~]# echo "123456" > /tmp/rsync_passwd
若是須要訪問模塊中的某個文件,則:
[root@xuexi ~]# rsync --list-only --port 888 rsync_backup@172.16.l0.6::longshuai/a/b --password-file=/tmp/rsync_passwd
還可使用url格式語法:
[root@xuexi ~]# rsync --list-only rsync://rsync_backup@172.16.l0.6:888/longshuai/a/b --password-file=/tmp/rsync_passwd
在前文說了rsync有三種工做方式:本地同步模式、遠程shell模式和rsync daemon模式。前二者是使用管道進行通訊和傳輸數據的,後者是經過網絡套接字進行通訊和傳輸數據的,且rsync daemon要求在server端必須已經運行好rsync且監聽在指定端口上。
但rsync支持第4種工做方式:經過遠程shell方式鏈接rsync daemon。也就是將第二種和第三種方式結合起來。雖然這種方式用的很少,但仍是有必要稍微解釋下,爲你閱讀rsync的man文檔提供一些幫助。
爲了下面稱呼的方便,暫且將經過遠程shell鏈接使用daemon的方式成爲"遠程shell daemon",固然,官方並無這樣的術語,僅僅只是本人在此爲了方便而如此稱呼。
遠程shell daemon的方式嚴格地說是"遠程shell通訊方式+使用rsync daemon的功能"。因此它的通訊方式和遠程shell是同樣的,在客戶端發起遠程shell鏈接,在server端fork遠程shell進程以啓動rsync進程,但這個rsync進程是臨時的rsync daemon,它只讀取配置文件中client所請求的模塊部分,且只讀取模塊部分中的path和身份認證相關內容,(也就是說不會將全局配置項和其它模塊項加載到內存,該模塊下的其餘配置也不會生效),當rsync操做完成,該rsync daemon就消逝並從內存中被清理。並且,遠程shell daemon啓動的臨時daemon不會和已經在server端運行的rsync daemon衝突,它們能夠並存。因爲遠程shell鏈接的最終目標是rsync模塊,因此它只能使用rsync daemon語法。
如下是語法格式:爲了簡潔,沒有指定src仍是dest,且以ssh這個遠程shell爲例。
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
涉及了兩個用戶ssh_user和auth_user,因爲使用的是遠程shell通訊方式,因此client要和server端創建ssh鏈接,ssh_user就是ssh鏈接server的用戶。auth_user則是模塊中的身份認證用戶。若是不指定"ssh_user",則默認將使用auth_user,但不少時候auth_user都只是一個虛擬用戶,這樣就創建不了ssh鏈接致使失敗,因此建議明確指定ssh_user和auth_user。
舉個例子就能說明上面的一切。如下是server端配置文件/etc/rsyncd.conf中的一個模塊配置,稍後將從client端使用遠程shell方式請求該模塊。
[tmpdir] path=/tmp auth users=lisi secrets file=/tmp/lisi_passwd
當前server端是沒有rsync daemon在運行的。
[root@xuexi ~]# netstat -tnl Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN tcp6 0 0 :::22 :::* LISTEN tcp6 0 0 ::1:25 :::* LISTEN
在客戶端上使用如下命令:
[root@xuexi ~]# rsync --list-only -e "ssh -l root" lisi@172.16.10.6::tmpdir root@172.16.10.6's password: Password:
能夠看到要求輸入兩次密碼,第一次密碼是root@XXX的密碼,即創建ssh鏈接使用的密碼,只有創建了ssh鏈接,才能在server上啓動臨時rsync daemon。第二次輸入的密碼Password是"auth users=lisi"對應的密碼。