標簽:rsync
系統運維, 經驗雜筆CentOS搭建lsyncd實時同步——取代rsync+inotify
昨天先森發布了“CentOS下inotify+rsync實現文件實時同步”,inotify+rsync實時同步的方案是用shell在后臺常駐來實現實時同步,沒有守護進程,感覺不是很靠譜,如果腳本突然掛了,實時同步豈不是GG了?所以先森在實現了inotify+rsync后還是再找其他的解決方案。其實在找到lsyncd之前,先森先找到了sersync這個工具,但是好像這個工具很久沒有更新了,所以雖然也有較多好評,但是先森目前還是先研究lsyncd了。當然,無論是sersync還是lsyncd,其實都是對inotify這個內核中的文件事件監控系統進行了封裝,類似inotify-tools,給我們提供的是封裝好了的inotify+rsync工具。sersync是用C寫的,lsyncd是使用lua語言封裝的。搭建lsyncd實時同步lsyncdlsyncd項目也托管在GitHub上面,具體地址是https://github.com/axkibe/lsyncd,一會兒若是要編譯安裝也需要去這個地方。上文也說過,lsyncd是使用lua語言封裝的,所以初識lsyncd的配置文件時,還是有點不習慣,但是用久應該就還好了。lsyncd不僅僅是實現兩臺服務器的同步的,它還能夠在一臺服務器內對兩個文件夾進行同步,這里可以是cp,也可以是rsync。兩臺或多臺服務器間可以是rsync,也可以是rsyncssh。本文主要講的是兩臺服務器間的rsync。lsyncd可以配置inotify檢測到文件變動后多少秒才執行同步,也就是時間延遲。也可以配置文件變動個數達到多少個后立即執行同步,無論有沒有到達前面的時間延遲的要求,這就是累計觸發事件次數。這兩個配置可以減少rsync的同步,避免海量文件同步時rsync的頻繁發送文件對比列表。lsyncd安裝lsyncd的安裝方式有兩種,yum安裝和編譯安裝。yum安裝:yum安裝也有兩種方式,一個是阿里云的鏡像源,一個是fedoraproject的鏡像源。阿里云:#CentOS 7wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo#CentOS 6wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo#yum 安裝yum install lsyncd -yfedoraproject:#只找到CentOS 6的rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpmyum install lsyncd -y編譯安裝:1、首先還是去上文提到的GitHub上下載項目,通過下面的下載就是最新的了:wget https://github.com/axkibe/lsyncd/archive/master.zip2、下載了軟件包,先別急著安裝,上文提到了幾次,lsyncd是用lua語言封裝的,所以還需要安裝lua環境。另外lsyncd不是使用的make,而是cmake,所以也需要安裝cmake。yum install -y lua lua-devel asciidoc cmake3、下載了軟件包,裝好了環境依賴,下面就是編譯安裝:unzip lsyncd-master.zipcd lsyncd-mastercmake -DCMAKE_INSTALL_PREFIX=/usr/local/lsyncdmake && make install安裝好了的lsyncd在/usr/local/lsyncd下。配置文件、日志文件夾等需要我們自己定義與創建。4、配置文件。先森的配置文件是用于兩臺服務器間實時同步的,使用的是rsync模式。lsyncd的配置文件其實有點類似nginx,如nginx的server可以多定義互不沖突一樣,lsyncd也可以多個定義。settings { logfile ="/usr/local/lsyncd/logs/lsyncd.log", statusFile ="/usr/local/lsyncd/logs/lsyncd.status", inotifyMode = "CloseWrite or Modify", maxProcesses = 15, }sync { default.rsync, source = "/web/data/ftp", target = "user@172.17.8.16::datahome", delete="running", exclude = { ".*", ".tmp","*.swp","*.swx" }, delay = 0, rsync = { binary = "/usr/bin/rsync", archive = true, compress = true, verbose = true, password_file = "/etc/rsyncd/rsync.passwd", } }注釋版:settings { --定義日志文件 logfile ="/usr/local/lsyncd/logs/lsyncd.log", --定義狀態文件 statusFile ="/usr/local/lsyncd/logs/lsyncd.status", --指定inotify監控的事件,默認是CloseWrite,還可以是Modify或CloseWrite or Modify --這個就是使用的inotify能監控的事件 inotifyMode = "CloseWrite or Modify", --同步進程的最大個數。假如同時有20個文件需要同步,而maxProcesses = 8,則最大能看到有8個rysnc進程 maxProcesses = 15, --(這個配置先森沒有使用)累計到多少所監控的事件激活一次同步,即使后面的delay延遲時間還未到。 --maxDelays=10, }sync { --使用rsync通過daemon方式連接遠程rsyncd進程; default.rsync, --同步的源目錄,使用絕對路徑。 source = "/web/data/ftp", --定義目的地址,對應不同的模式有不同的寫法。這里是遠程rsync,使用“用戶名@ip::模塊名”寫法。 target = "user@172.17.8.16::datahome", --是否同步刪除,除了running選項,還有true、false和startup,這個配置先森不是很明白,大概是true是完全同步刪除,false是不允許刪除,startup和running要難理解一些\ --先森的理解是,startup是僅在啟動時將源目錄和目的目錄來一次完全同步,lsyncd運行時的源目錄的刪除文件在目的目錄中不做刪除操作\ --running是啟動時不對源、目的目錄進行完全同步,lsyncd運行時源目錄刪除的文件,目的目錄也會被刪除。 delete="running", --排除的文件,這里排除了一些隱藏文件,和文件打開是時的臨時文件 exclude = { ".*", ".tmp","*.swp","*.swx" }, -- 累計事件,等待rsync同步延時時間,默認15秒。先森配置的是0,也就是實時同步。 delay = 0, rsync = { --本地rsync命令路徑 binary = "/usr/bin/rsync", archive = true, compress = true, verbose = true, --遠程rsyncd的密碼 password_file = "/etc/rsyncd/rsync.passwd", } }5、啟動lsyncd/usr/local/lsyncd/bin/lsyncd -log Exec /usr/local/lsyncd/lsyncd.conf也可以自己創建一個啟動腳本,腳本內容如下,是先森從yum安裝的lsyncd拷貝的,一樣的可以使用。只是用之前,需要對lsyncd守護命令與配置文件先做個軟連接,免得需要修改啟動腳本:ln -s /usr/local/lsyncd/bin/lsyncd /usr/bin/lsyncdln -s /usr/local/lsyncd/lsyncd.conf /etc/lsyncd.conf啟動腳本:#!/bin/bash## chkconfig: - 85 15# description: Lightweight inotify based sync daemon## processname: lsyncd# config: /etc/lsyncd.conf# config: /etc/sysconfig/lsyncd# pidfile: /var/run/lsyncd.pid# Source function library. /etc/init.d/functions# Source networking configuration.. /etc/sysconfig/network# Check that networking is up.[ "$NETWORKING" = "no" ] && exit 0LSYNCD_OPTIONS="-pidfile /var/run/lsyncd.pid /etc/lsyncd.conf"if [ -e /etc/sysconfig/lsyncd ]; then . /etc/sysconfig/lsyncdfiRETVAL=0prog="lsyncd"thelock=/var/lock/subsys/lsyncdstart() { [ -f /etc/lsyncd.conf ] || exit 6 echo -n $"Starting $prog: " if [ $UID -ne 0 ]; then RETVAL=1 failure else daemon ${LSYNCD_USER:+--user ${LSYNCD_USER}} /usr/bin/lsyncd $LSYNCD_OPTIONS RETVAL=$? [ $RETVAL -eq 0 ] && touch $thelock fi; echo return $RETVAL}stop() { echo -n $"Stopping $prog: " if [ $UID -ne 0 ]; then RETVAL=1 failure else killproc lsyncd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $thelock fi; echo return $RETVAL}reload(){ echo -n $"Reloading $prog: " killproc lsyncd -HUP RETVAL=$? echo return $RETVAL}restart(){ stop start}condrestart(){ [ -e $thelock ] && restart return 0}case "$1" in start) start ;; stop) stop ;; restart) restart ;; reload) reload ;; condrestart) condrestart ;; status) status lsyncd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}" RETVAL=1esacexit $RETVAL優化因為lsyncd其實也是用到了inotify,所以和inotify+rsync方案一樣,我們還是需要對服務器的inotify內核配置進行優化。inotify檢查磁盤變動是有隊列等值的配置的,inotify默認內核參數值太小,會導致實際檢測的時候報錯。查看系統默認參數值sysctl -a | grep max_queued_eventssysctl -a | grep max_user_watchessysctl -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=99999999fs.inotify.max_user_watches=99999999fs.inotify.max_user_instances=65535其他官方配置文件wiki:https://axkibe.github.io/lsyncd/manual/config/file/
腳本編程, 系統運維, 經驗雜筆CentOS下inotify+rsync實現文件實時同步
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/inotifyinotify-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.rpmrpm -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.gztar zxvf inotify-tools-3.14.tar.gzcd inotify-tools-3.14./configure #或./configure --prefix=/usr/local/inotifymakemake 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/bashsource /etc/profilesrc=/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 fidoneinotify_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/bashsource /etc/profilesrc=/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.logslogs=/var/log/inotify_rsync.logserrlog=/var/log/inotify_rsync.err.logscd ${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 fidone這個腳本是將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_eventssysctl -a | grep max_user_watchessysctl -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=99999999fs.inotify.max_user_watches=99999999fs.inotify.max_user_instances=65535

川公網安備 51011202000104號