rsync做爲一個簡便的同步工具,在linux環境中應用較多。可以實現比較簡單的文件或目錄傳輸。至於配置相關部分這裏不作過多的講解。html
+++++++++++++++++++++++++++++++++++++++++++++++node
這裏說下rsync大文件時遇到的傳輸慢的問題,以及應該如何合理的解決這個問題。linux
現實場景以下,線上環境中須要同步一個15G的文件,服務器都是千兆網卡,正常同步也就150s左右。可是線上環境中同步有時候須要一個多小時,讓人很崩潰。算法
分析過程:開始懷疑網絡問題,查了網絡環境 以及使用nc傳輸文件都沒有問題,基本都在150s左右傳輸完成。也就考慮是同步軟件rsync的致使慢。數組
而後找了下rsync的傳輸校驗覈心算法,大體掃了一遍,基本懂了。服務器
問題緣由:簡單描述爲:根據rsync傳輸原理,rsync傳輸文件是利用查找文件中不一樣的數據塊進行傳輸(減小數控傳輸)。rsync校驗已經存在的文件與原文件的差異,而後更新耗時較久。更爲具體的參見詳解 rsync傳輸算法。網絡
解決辦法1 :rsync忽略校驗,直接傳輸覆蓋,rsync --help 能夠看到有這麼個參數: -W, --whole-file copy files whole (without delta-xfer algorithm) 使用該參數。數據結構
該參數的優勢節省時間不進行校驗,直接覆蓋本地或者遠程文件。缺點,比較消耗帶寬。ide
解決辦法2 : 使用 nc 或者其餘的傳輸方式,跳過校驗。具體如何操做,參見。。 行我簡單寫一個吧:源: #nc -l 1.1.1.1 999 < bigfile 目的: #nc 1.1.1.1 999 > bigfile工具
優缺點,參看法決辦法1 ,有利有弊。
+++++++++++++++++++++++++++++++++++++++++++++++
親身實測有效:
圖1 將文件刪除,模擬初次同步,本地無文件,不須要進行校驗,2分多同步完成。
圖2 服務器帶寬狀況:
圖3 模擬遇到的問題,將文件倒敘,製造文件更新的假象。而後同步,能夠看到同步進行了57分鐘。
圖4 服務器網卡上流量遠低於千兆:
圖 5 模擬遇到的問題,將文件倒敘,製造文件更新的假象。跳過校驗同步:
帶寬不想貼了 參照圖 2
+++++++++++++++++++++++++++++++++++++++++++
rsync的算法以下:(假設咱們同步源文件名爲fileSrc,同步目的文件叫fileDst)
1)分塊Checksum算法。首先,咱們會把fileDst的文件平均切分紅若干個小塊,好比每塊512個字節(最後一塊會小於這個數),而後對每塊計算兩個checksum,
一個叫rolling checksum,是弱checksum,32位的checksum,其使用的是Mark Adler發明的adler-32算法,
另外一個是強checksum,128位的,之前用md4,如今用md5 hash算法。
爲何要這樣?由於若干年前的硬件上跑md4的算法太慢了,因此,咱們須要一個快算法來鑑別文件塊的不一樣,可是弱的adler32算法碰撞機率過高了,因此咱們還要引入強的checksum算法以保證兩文件塊是相同的。也就是說,弱的checksum是用來區別不一樣,而強的是用來確認相同。(checksum的具體公式能夠參看這篇文章)
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中的某個整數值。(對於hash table,若是你不清楚,建議回去看大學時的數據結構教科書)
順便說一下,網上看到不少文章說,「要對rolling checksum作排序」(好比這篇和這篇),這兩篇文章都引用並翻譯了原做者的這篇文章,可是他們都理解錯了,不是排序,就只是把fileDst的checksum數據,按rolling checksum作存到2^16的hash table中,固然會發生碰撞,把碰撞的作成一個鏈表就行了。這就是原文中所說的第二步——搜索有碰撞的狀況。
4)比對算法。這是最關鍵的算法,細節以下:
4.1)取fileSrc的第一個文件塊(咱們假設的是512個長度),也就是從fileSrc的第1個字節到第512個字節,取出來後作rolling checksum計算。計算好的值到hash表中查。
4.2)若是查到了,說明發如今fileDst中有潛在相同的文件塊,因而就再比較md5的checksum,由於rolling checksume太弱了,可能發生碰撞。因而還要算md5的128bits的checksum,這樣一來,咱們就有 2^-(32+128) = 2^-160的機率發生碰撞,這過小了能夠忽略。若是rolling checksum和md5 checksum都相同,這說明在fileDst中有相同的塊,咱們須要記下這一塊在fileDst下的文件編號。
4.3)若是fileSrc的rolling checksum 沒有在hash table中找到,那就不用算md5 checksum了。表示這一塊中有不一樣的信息。總之,只要rolling checksum 或 md5 checksum 其中有一個在fileDst的checksum hash表中找不到匹配項,那麼就會觸發算法對fileSrc的rolling動做。因而,算法會住後step 1個字節,取fileSrc中字節2-513的文件塊要作checksum,go to (4.1) – 如今你明白什麼叫rolling checksum了吧。
4.4)這樣,咱們就能夠找出fileSrc相鄰兩次匹配中的那些文本字符,這些就是咱們要往同步目標端傳的文件內容了。
上面的算法再作個示意圖:
這樣,最終,在同步源這端,咱們的rsync算法可能會獲得下面這個樣子的一個數據數組,圖中,紅色塊表示在目標端已匹配上,不用傳輸(注:我專門在其中顯示了兩塊chunk #5,相信你會懂的),而白色的地方就是須要傳輸的內容(注意:這些白色的塊是不定長的),這樣,同步源這端把這個數組(白色的就是實際內容,紅色的就放一個標號)壓縮傳到目的端,在目的端的rsync會根據這個表從新生成文件,這樣,同步完成。
最後想說一下,對於某些壓縮文件使用rsync傳輸可能會傳得更多,由於被壓縮後的文件可能會很是的不一樣。對此,對於gzip和bzip2這樣的命令,記得開啓 「rsyncalbe」 模式。
last : 看起來感受rsync很簡單,可是你肯定你瞭解rsync的參數的意義麼,在那些場景應該使用那些參數麼
雞湯一碗:學無止境,只要還有頭髮就繼續搬磚!