CentOS下inotify+rsync實現文件實時同步
編輯:狂族晨曦 來源:腳本編程,系統運維,經驗雜筆 日期:2018-02-07 閱讀: 4,048 次 搶個沙發 百度已收錄
rsync僅同步差異文件,所以傳輸效率較高,所以先森在項目中負載的資源服務器做了rsync同步,確保通過負載IP都能訪問到相同的文件,使用crontab計劃任務每1分鐘執行一次同步。
計劃任務最小時間刻度為1分鐘(雖然可以用數學方法再調小,但是運行密度大了對服務器會造成負荷),也就是上傳一張圖片,最長可能要等1分鐘后才能在其它服務器上訪問,如果同步目錄下的文件基數是百萬級的,那么時間可能更久。
這種方案先森曾發過:CentOS下rsync服務器安裝與配置-數據同步|文件增量備份

inotify+rsync實時同步
rsync的不足
rsync具有安全性高、備份迅速、支持增量備份等優點,通過rsync可以解決實時性不高的數據備份需求,例如定期數據庫備份。
但隨著業務規模的擴大,業務需求的增加,rsync的缺點也暴露出來了:
1、當文件數量大到百萬級別,rsync僅差異掃描就是一項非常耗時的工作;
2、rsync自身不能實時的檢測并同步數據,它總是被動的通過各種方式去觸發同步。
inotify與inotify-tools
注:inotify是一個 Linux 內核特性,inotify-tools是為linux下inotify文件監控工具提供的一套C的開發接口庫函數。
inotify:
inotify是一種強大的、細粒度的、異步的文件系統事件監控機制,Linux內核從2.6.13開始引入,允許監控程序打開一個獨立文件描述符,并針對事件集監控一個或者多個文件,例如打開、關閉、移動/重命名、刪除、創建或者改變屬性。
CentOS 6是已經支持的了,判斷服務器是否支持inotify,只需要執行下面命令,查看是否有結果即可。
ll /proc/sys/fs/inotify
inotify-tools:
inotify-tools是為linux下inotify文件監控工具提供的一套C的開發接口庫函數,同時還提供了一系列的命令行工具,這些工具可以用來監控文件系統的事件。
inotify-tools是用c編寫的,除了要求內核支持inotify外,不依賴于其他。
inotify-tools提供兩種工具,一是inotifywait,它是用來監控文件或目錄的變化,二是inotifywatch,它是用來統計文件系統訪問的次數。我們主要用到的是inotifywait工具。
inotify-tools安裝
inotify-tools先森找到了兩種安裝方式,rpm安裝和編譯安裝,先森用的是編譯安裝。
rpm安裝
wget http://dl.fedoraproject.org/pub/epel/6/x86_64/Packages/i/inotify-tools-3.14-1.el6.x86_64.rpm rpm -vhi inotify-tools-3.14-1.el6.x86_64.rpm
編譯安裝
編譯前請確保服務器已安裝編譯組件:
yum install -y make gcc gcc-c++
這個項目是發布在github上的,下載也是在github上下載。但是先森在項目首頁下載下來的無法編譯安裝,所以安裝的還是3.1.4版本的。
github項目地址:https://github.com/rvoicilas/inotify-tools/
編譯安裝:
wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz tar zxvf inotify-tools-3.14.tar.gz cd inotify-tools-3.14 ./configure #或./configure --prefix=/usr/local/inotify make make install
安裝后命令在/usr/local/bin/目錄下。
查看效果:
/usr/local/bin/inotifywait -mrq --format '%Xe %w%f' -e modify,create,delete,attrib /data/
不停止上面的命令,新建終端連接然后進入/data/文件夾進行各類操作,可以看下上面輸出的結果。
rsync組合inotify-tools完成實時同步
inotify的作用,是讓我們知道監控的文件夾中有變動,我們可以根據inotify輸出內容,去觸發rsync同步。
提示:以往使用crontab觸發rsync時,我們是將rsync服務端搭建在主服務器,其他服務器去主服務器同步文件。而inotify+rsync的方式,是將rsync服務端搭建在從服務器,主服務器推送文件到從服務器,所以從服務器上的rsync配置中“read only”要配置為no,也就是“read only = no”。
inotify-tools只是個工具,并不是軟件,所以要與rsync配合就需要我們自己寫shell腳本,并讓腳本一直運行在后臺。
先森通過實際測試,整理出了兩個腳本,也就是兩種方案。
方案1:
#!/bin/bash
source /etc/profile
src=/data/ # 需要同步的源路徑
des=datahome # 目標服務器上 rsync 模塊名
rsync_passwd_file=/etc/rsyncd/rsync.passwd # rsync驗證的密碼文件
ipaddr=(10.0.0.1) # 目標服務器,多個目標服務器以空格分開
user=user # rsync --daemon定義的驗證用戶名
logs=/var/log/inotify_rsync.logs # 日志
inotify_rsync(){
cd ${src} # 此方法中,由于rsync同步的特性,這里必須要先cd到源目錄,inotify再監聽 ./ 才能rsync同步后目錄結構一致,有興趣的同學可以進行各種嘗試觀看其效果
/usr/local/bin/inotifywait -mrq --format '%Xe %w%f' -e modify,create,delete,attrib,close_write,move --exclude=".*.swp" ./ | while read file # 把監控到有發生更改的"文件路徑列表"循環
do
INO_EVENT=$(echo $file | awk '{print $1}') # 把inotify輸出切割 把事件類型部分賦值給INO_EVENT
INO_FILE=$(echo $file | awk '{print $2}') # 把inotify輸出切割 把文件路徑部分賦值給INO_FILE
echo "-------------------------------$(date)------------------------------------"
echo $file
#增加、修改、寫入完成、移動進事件
#增、改放在同一個判斷,因為他們都肯定是針對文件的操作,即使是新建目錄,要同步的也只是一個空目錄,不會影響速度。
if [[ $INO_EVENT =~ 'CREATE' ]] || [[ $INO_EVENT =~ 'MODIFY' ]] || [[ $INO_EVENT =~ 'CLOSE_WRITE' ]] || [[ $INO_EVENT =~ 'MOVED_TO' ]] # 判斷事件類型
then
echo 'CREATE or MODIFY or CLOSE_WRITE or MOVED_TO'
for ip in ${ipaddr[@]}
do
rsync -avzcR --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx" $(dirname ${INO_FILE}) ${user}@${ip}::${des} >> $logs # INO_FILE變量代表路徑哦 -c校驗文件內容
done
#仔細看 上面的rsync同步命令 源是用了$(dirname ${INO_FILE})變量 即每次只針對性的同步發生改變的文件的目錄(只同步目標文件的方法在生產環境的某些極端環境下會漏文件 現在可以在不漏文件下也有不錯的速度 做到平衡) 然后用-R參數把源的目錄結構遞歸到目標后面 保證目錄結構一致性
fi
#刪除、移動出事件
if [[ $INO_EVENT =~ 'DELETE' ]] || [[ $INO_EVENT =~ 'MOVED_FROM' ]]
then
echo 'DELETE or MOVED_FROM'
echo 'CREATE or MODIFY or CLOSE_WRITE or MOVED_TO'
for ip in ${ipaddr[@]}
do
rsync -avzR --delete --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx" $(dirname ${INO_FILE}) ${user}@${ip}::${des} >> $logs
done
#看rsync命令 如果直接同步已刪除的路徑${INO_FILE}會報no such or directory錯誤 所以這里同步的源是被刪文件或目錄的上一級路徑,并加上--delete來刪除目標上有而源中沒有的文件,這里不能做到指定文件刪除,如果刪除的路徑越靠近根,則同步的目錄月多,同步刪除的操作就越花時間。這里有更好方法的同學,歡迎交流。
fi
#修改屬性事件 指 touch chgrp chmod chown等操作
if [[ $INO_EVENT =~ 'ATTRIB' ]]
then
echo 'ATTRIB'
if [ ! -d "$INO_FILE" ] # 如果修改屬性的是目錄 則不同步,因為同步目錄會發生遞歸掃描,等此目錄下的文件發生同步時,rsync會順帶更新此目錄。
then
for ip in ${ipaddr[@]}
do
rsync -avzcR --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx" $(dirname ${INO_FILE}) ${user}@${ip}::${des} >> $logs
done
fi
fi
done
inotify_rsync >> $logs 2>&1
}
inotify_rsync >> $logs 2>&1
將上面內容保存為inotify_rsync_A.sh,執行:
inotify_rsync_A.sh &
或使用screen后臺啟動。
另外,為避免意外遺漏文件,最好在定時任務中每隔兩個小時執行一次全目錄同步。
這個方案的優點:利用inotify讓rsync每次僅同步有更改的文件,減少遞歸操作。
缺點:經過先森實際運用發現,inotify的特性,每次創建文件會產生多條輸出,而這個腳本inotify的每條輸出都會觸發一次rsync,這樣會對服務器資源產生浪費。
方案2:
為了解決方案1的問題,先森找到了另一個腳本,對方案1的腳本進行了修改:
#!/bin/bash
source /etc/profile
src=/data/ # 需要同步的源路徑
des=datahome # 目標服務器上 rsync 模塊名
rsync_passwd_file=/etc/rsyncd/rsync.passwd # rsync驗證的密碼文件
ipaddr=(10.0.0.1) # 目標服務器,多個目標服務器以空格分開
user=user # rsync --daemon定義的驗證用戶名
inlogs=/var/log/inotifywait.logs
logs=/var/log/inotify_rsync.logs
errlog=/var/log/inotify_rsync.err.logs
cd ${src} # 此方法中,由于rsync同步的特性,這里必須要先cd到源目錄,inotify再監聽 ./ 才能rsync同步后目錄結構一致,有興趣的同學可以進行各種嘗試觀看其效果
/usr/local/bin/inotifywait -mrq --format '%Xe %w%f' -e modify,create,delete,attrib,close_write,move --exclude=".*.swp" ./ >> $inlogs &
while true;do
if [ -s ${inlogs} ];then
grep -i -E "delete|moved_from" ${inlogs} >> /var/log/inotify_away.log
for ip in ${ipaddr[@]}
do
rsync -avzcR --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx" ${src} ${user}@${ip}::${des} >> $logs
RETVAL=$?
done
#同步失敗后的輸出日志
if [ $RETVAL -ne 0 ];then
echo "${src} sync to ${ipaddr} failed at `date +"%F %T"`,please check it by manual" >> $errlog
fi
cat /dev/null > $inlogs
for ip in ${ipaddr[@]}
do
rsync -avzcR --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx" ${src} ${user}@${ip}::${des} >> $logs
done
else
sleep 1
fi
done
這個腳本是將inotify的檢測內容輸出到文件/var/log/inotifywait.logs,腳本判斷這個文件是否為空,非空則表明有變動,那么就來一次完整的同步。如果文件為空則睡眠1秒。
將上面內容保存為inotify_rsync_B.sh,執行:
inotify_rsync_B.sh &
這個方案的優點:不會根據inotify輸出重復觸發rsync同步。
缺點:每次都是rsync完整同步,如果文件數量較大則對比時間會比較長。
inotify優化
inotify檢查磁盤變動是有隊列等值的配置的,inotify默認內核參數值太小,會導致實際檢測的時候報錯。
查看系統默認參數值
sysctl -a | grep max_queued_events sysctl -a | grep max_user_watches sysctl -a | grep max_user_instances
臨時修改
sysctl -w fs.inotify.max_queued_events="99999999" sysctl -w fs.inotify.max_user_watches="99999999" sysctl -w fs.inotify.max_user_instances="65535"
固定修改:vim /etc/sysctl.conf #添加以下代碼
fs.inotify.max_queued_events=99999999 fs.inotify.max_user_watches=99999999 fs.inotify.max_user_instances=65535
轉載請注明出處來自http://www.cnidcc.cn/inotify_rsync.html

川公網安備 51011202000104號