上周我們的一個GitLab服務頻繁出現web頁面卡死問題,得重啟虛擬機才可恢復,但重啟之后沒多久又會卡死。后來發現是虛擬機的磁盤大小超過了2T,而虛擬機管理那層的文件系統是ext3,最大單文件只能支持到2T(也不知道當初這個3T的虛擬磁盤鏡像是怎么建立起來的,難道Xen不會給出警告?)。由於該機房沒有可調動的磁盤了,於是只能另外找機房重新搭建一個環境,將數據遷過去。
只同步指定的子目錄
場景:
0) 要遷移的是gitlab里面的git庫數據
- 要遷移的數據很多(大約2T),由於跨機房網絡速度一般,我們期望先遷移部分重點用戶的,但fork出來的git庫是在不同的子目錄下的(比如
ssmp/ssmp.git
會有zhangsan/ssmp.git
,lisi/ssmp.git
),這些都得一並遷移過去。
首先,像下面這樣直接將ssmp, zhangsan, lisi
三個目錄全拷貝過去,肯定是不行的
rsync -a ssmp/ssmp.git zhangsan/ssmp.git lisi/ssmp git@new-repo:/home/git/repositories
因為不僅原來的目錄結構丟了,三個ssmp.git還混到一起了。
解決方法是用rsync的 filter 特性
rsync -a --delete --filter="merge /tmp/gitlabFilter" repositories/ git@new-repo:/home/git/repositories/
但寫這個filter內容的寫法跟我們原來在tar
那里習慣了的目錄排除不一樣,比如上面的場景寫成下面這樣是不能工作的:
+ ssmp/ssmp.git
+ zhangsan/ssmp.git
+ lisi/ssmp.git
- *
這是因為最后那個- *
就已經把頂層的ssmp, zhangsan, lisi
這幾個目錄排除掉了,於是ssmp
下面的子目錄是沒法加進來的。
對於這個問題,rsync的man page說得很清楚(只不過我看見大段的英文就有些暈頭),需要寫成下面這樣:
+ ssmp/
- ssmp/*
+ ssmp/ssmp.git
+ zhangsan/
- zhangsan/*
+ zhangsan/ssmp.git
+ lisi/
- lisi/*
+ lisis/smp.git
- *
這里還有一個詳細的描述: Rsync backups: excluding directories
linux的磁盤cache導致拷貝速度逐漸下降
用rsync拷貝數據過程中發現一個現象:開始拷貝的時候速度很快,每秒有40MB左右,但拷貝幾十分鍾之后就降到10MB左右了,兩邊機器都沒有跑什么應用,網絡用netcat測也沒有問題…
然后我觀察到的一個問題是兩邊的free
命令都顯示出內存占用很高,並且是buffered/cache
一欄很高,因為這個緩存是可以手工釋放的,就抱着試試看的想法試了一下:
sync; echo 3 > /proc/sys/vm/drop_caches
ssh root@new-repos 'sh -c "sync; echo 3 > /proc/sys/vm/drop_caches"'
沒想到速度馬上恢復了!
於是我改了腳本,每次調用一次rsync同步完一個git庫及其fork,就調上面的語句將cache清掉,速度基本上不受影響。
補充說明
- linux操作系統會將文件系統的內容緩存起來,以便后面用到時加速,但在數據遷移場景下,基本上沒有“后面用到時”這個場景,這個緩存反而礙事(TODO: 為什么導致網絡io下降)
- 對於本機內大量拷貝文件,有人提供了一個
nocache
命令(https://github.com/Feh/nocache Debian/Ubuntu已經收錄了這個工具 https://packages.debian.org/search?keywords=nocache )。它的功能是臨時禁用cache,用法是將要執行的命令用nocache
包住,比如:nocache cp -a ~/ /mnt/backup/home-$(hostname)
,但rsync會使用網絡通訊,所以nocache rsync
對遠端沒有作用( *Note however, that rsync uses sockets, so if you try a nocache rsync, only the local process will be intercepted.) - 也有人在多年以前給rsync提交了一個補丁(https://bugzilla.samba.org/show_bug.cgi?id=9560 ),增加了
--drop-cache
選項,但遺憾的是沒被接納,說是過於linux-specific,開發人員的意見(見comment 3 )是改用nocache
:nocache rsync -aiv --rsync-path='nocache rsync' some-host:/src/ /dest/
. P.S. nocache工具的主頁最后在acknowledgements部分 說,其實它是衍生自rsync的這個補丁的。
參考資料:
- kernel - Can I copy large files faster without using the file cache? - Ask
- linux - How can I limit the cache used by copying so there is still memory
已經備份過的文件不再重復拷貝(從舊備份硬鏈接未修改過的文件)
場景:要求每天建立一個備份。因為數據量很大,所以從備份速度、空間占用上來說,期望重復文件就不要重復拷貝了
第一個版本是這樣的:
rm -rf backup.2
mv backup.1 backup.2
cp -al backup.0 backup.1
rsync -a -l --delete source_dir backup.0
在上面的腳本中,多個備份之間的硬鏈接是依靠cp -a -l
來建立的,而新增的文件依靠rsync -a -l
也可以盡量硬鏈接已有的文件。
但這個腳本有點問題: 如果文件內容沒變,只是文件屬性(屬主、修改時間、權限)發生變化的話,rsync不會重新拷貝文件,而是直接修改原文件的屬性,而由於采用了硬鏈接,backup.1
和backup.2
等舊備份目錄里面的文件屬性也發生了變化!
解決這個問題的方法是改為:
rm -rf backup.2
mv backup.1 backup.2
mv backup.0 backup.1
rsync -a --link-dest=backup.1 source_dir backup.0
注意這里的--link-dest=backup.1
,它的含義是:先到backup.1這個目錄找找有沒有一樣的文件,有的話將其硬鏈接到目標目錄(backup.0
),沒有的話再拷貝。屬性的變化會認為是不同的文件,會生成新拷貝。
如果文件屬性的變化對於你的場景沒有場景,那么兩種方法都可以用,第一種方法還能少一些拷貝文件。
參考資料
- Incremental, Snapshot-based Backup with Rsync and SSH
- Easy Automated Snapshot-Style Backups with Rsync
打包(archive)差異備份文件
場景:比較老的備份打包后轉到其它機器(或者磁帶機)上,每周一次全量備份,然后每天的增量單獨打包
rsync -a --compare-dest=backup.week backup.1 backup.incremental-20150604
cd backup.incremental-20150604
tar zcvf ../backup.incremental-20150604.tar.gz *
--compare-dest
的含義跟上面--link-dest
類似:先到這個參數指定的目錄找找有沒有想要的文件,如果沒有再從源目錄拷貝