sersync基於rsync+inotify實現數據實時同步

前言

提到數據同步就必然會談到rsync,通常簡單的服務器數據傳輸會使用ftp/sftp等方式,可是這樣的方式效率不高,不支持差別化增量同步也不支持實時傳輸。針對數據實時同步需求大多數人會選擇rsync+inotify-tools的解決方案,可是這樣的方案也存在一些缺陷(文章中會具體指出),sersync是國人基於前二者開發的工具,不只保留了優勢同時還強化了實時監控,文件過濾,簡化配置等功能,幫助用戶提升運行效率,節省時間和網絡資源。php

可靠高效的數據實時同步方式html


更新歷史

2015年08月13日 - 初稿linux

閱讀原文 - http://wsgzao.github.io/post/sersync/c++

擴展閱讀git

基於rsync+sersync的服務器文件同步實戰 - http://www.markdream.com/technologies/server/syncfile-by-rsync.shtml
經過 rsync sersync 實現高效的數據實時同步架構 - https://www.cnhzz.com/rsync_sersync/
rsync - https://rsync.samba.org/
inotify-tools - https://github.com/rvoicilas/inotify-tools
sersync - http://code.google.com/p/sersync/github


原理

Synchronize files and folders between servers -using inotiy and rsync with c++ 服務器實時同步文件,服務器鏡像解決方案web

sersync主要用於服務器同步,web鏡像等功能。基於boost1.43.0,inotify api,rsync command.開發。目前使用的比較多的同步解決方案是inotify-tools+rsync ,另一個是google開源項目Openduckbill(依賴於inotify- tools),這兩個都是基於腳本語言編寫的。相比較上面兩個項目,本項目優勢是:
1. sersync是使用c++編寫,並且對linux系統文件系統產生的臨時文件和重複的文件操做進行過濾(詳細見附錄,這個過濾腳本程序沒有實現),因此在結合rsync同步的時候,節省了運行時耗和網絡資源。所以更快。
2. 相比較上面兩個項目,sersync配置起來很簡單,其中bin目錄下已經有基本上靜態編譯的2進制文件,配合bin目錄下的xml配置文件直接使用便可。
3. 另外本項目相比較其餘腳本開源項目,使用多線程進行同步,尤爲在同步較大文件時,可以保證多個服務器實時保持同步狀態。
4. 本項目有出錯處理機制,經過失敗隊列對出錯的文件從新同步,若是仍舊失敗,則按設定時長對同步失敗的文件從新同步。
5. 本項目自帶crontab功能,只需在xml配置文件中開啓,便可按您的要求,隔一段時間總體同步一次。無需再額外配置crontab功能。
6. 本項目socket與http插件擴展,知足您二次開發的須要。express

針對上圖的設計架構,這裏作幾點說明,來幫助你們閱讀和理解該圖api

1 ) 線程組線程是等待線程隊列的守護線程,當事件隊列中有事件產生的時候,線程組守護線程就會逐個喚醒同步線程。當隊列中 Inotify 事件較多的時候,同步線程就會被所有喚醒一塊兒工做。這樣設計的目的是爲了可以同時處理多個 Inotify 事件,從而提高服務器的併發同步能力。同步線程的最佳數量=核數 x 2 + 2。
2 ) 那麼之因此稱之爲線程組線程,是由於每一個線程在工做的時候,會根據服務器上新寫入文件的數量去創建子線程,子線程能夠保證全部的文件與各個服務器同時同步。當要同步的文件較大的時候,這樣的設計能夠保證每一個遠程服務器均可以同時得到須要同步的文件。
3 ) 服務線程的做用有三個:
- 處理同步失敗的文件,將這些文件再次同步,對於再次同步失敗的文件會生成 rsync_fail_log.sh 腳本,記錄失敗的事件。
- 每隔10個小時執行 rsync_fail_log.sh 腳本一次,同時清空腳本。
- crontab功能,能夠每隔必定時間,將全部路徑總體同步一次。bash

4 ) 過濾隊列的創建是爲了過濾短期內產生的重複的inotify信息,例如在刪除文件夾的時候,inotify就會同時產生刪除文件夾裏的文件與刪除文件夾的事件,經過過濾隊列,當刪除文件夾事件產生的時候,會將以前加入隊列的刪除文件的事件所有過濾掉,這樣只產生一條刪除文件夾的事件,從而減輕了同步的負擔。同時對於修改文件的操做的時候,會產生臨時文件的重複操做。

角色

注意主從配置的區別,記得調整SELinux和防火牆

iptables配置實踐 - http://wsgzao.github.io/post/iptables/
LTMP手動編譯安裝以及全自動化部署實踐 - http://wsgzao.github.io/post/ltmp/

  1. 服務器A(主服務器)
  2. 服務器B(從服務器/備份服務器)
  3. rsync默認TCP端口爲873

服務器B

bash#在服務器B上安裝rsync
cd /app/local
wget  http://rsync.samba.org/ftp/rsync/src/rsync-3.1.1.tar.gz
tar zxf rsync-3.1.1.tar.gz
cd rsync-3.1.1
./configure
make && make install


#設置rsync的配置文件
vi /etc/rsyncd.conf

#服務器B上的rsyncd.conf文件內容
uid=root
gid=root
#最大鏈接數
max connections=36000
#默認爲true,修改成no,增長對目錄文件軟鏈接的備份 
use chroot=no
#定義日誌存放位置
log file=/var/log/rsyncd.log
#忽略無關錯誤
ignore errors = yes
#設置rsync服務端文件爲讀寫權限
read only = no 
#認證的用戶名與系統賬戶無關在認證文件作配置,若是沒有這行則代表是匿名
auth users = rsync
#密碼認證文件,格式(虛擬用戶名:密碼)
secrets file = /etc/rsync.pass
#這裏是認證的模塊名,在client端須要指定,能夠設置多個模塊和路徑
[rsync]
#自定義註釋
comment  = rsync
#同步到B服務器的文件存放的路徑
path=/app/data/site/
[img]
comment  = img
path=/app/data/site/img

#建立rsync認證文件  能夠設置多個,每行一個用戶名:密碼,注意中間以「:」分割
echo "rsync:rsync" > /etc/rsync.pass

#設置文件全部者讀取、寫入權限
chmod 600 /etc/rsyncd.conf  
chmod 600 /etc/rsync.pass  

#啓動服務器B上的rsync服務
#rsync --daemon -v
rsync --daemon

#監聽端口873
netstat -an | grep 873
lsof -i tcp:873

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   31445 root    4u  IPv4 443872      0t0  TCP *:rsync (LISTEN)
rsync   31445 root    5u  IPv6 443873      0t0  TCP *:rsync (LISTEN)


#設置rsync爲服務啓動項(可選)
echo "/usr/local/bin/rsync --daemon" >> /etc/rc.local

#要 Kill rsync 進程,不要用 kill -HUP {PID} 的方式重啓進程,如下3種方式任選
#ps -ef|grep rsync|grep -v grep|awk '{print $2}'|xargs kill -9
#cat /var/run/rsyncd.pid | xargs kill -9
pkill rsync
#再次啓動
/usr/local/bin/rsync --daemon

服務器A

bash#安裝rsync
cd /app/local
wget  http://rsync.samba.org/ftp/rsync/src/rsync-3.1.1.tar.gz
tar zxf rsync-3.1.1.tar.gz
cd rsync-3.1.1
./configure
make && make install

#安裝inotify-tools
cd /app/local
wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
tar zxf inotify-tools-3.14.tar.gz
cd inotify-tools-3.14
./configure --prefix=/app/local/inotify 
make && make install

#安裝sersync
cd /app/local
wget https://sersync.googlecode.com/files/sersync2.5.4_64bit_binary_stable_final.tar.gz
tar zxf sersync2.5.4_64bit_binary_stable_final.tar.gz
mv /app/local/GNU-Linux-x86/ /app/local/sersync
cd /app/local/sersync
#配置下密碼文件,由於這個密碼是要訪問服務器B須要的密碼和上面服務器B的密碼必須一致
echo "rsync" > /app/local/sersync/user.pass
#修改權限
chmod 600 /app/local/sersync/user.pass
#修改confxml.conf
vi /app/local/sersync/confxml.xml
xml
<?xml version="1.0" encoding="ISO-8859-1"?> <head version="2.5"> <host hostip="localhost" port="8008"></host> <debug start="true"/> <fileSystem xfs="false"/> <filter start="false"> <exclude expression="(.*)\.php"></exclude> <exclude expression="^data/*"></exclude> </filter> <inotify> <delete start="true"/> <createFolder start="true"/> <createFile start="false"/> <closeWrite start="true"/> <moveFrom start="true"/> <moveTo start="true"/> <attrib start="false"/> <modify start="false"/> </inotify> <sersync> <localpath watch="/home/"> <!-- 這裏填寫服務器A要同步的文件夾路徑--> <remote ip="8.8.8.8" name="rsync"/> <!-- 這裏填寫服務器B的IP地址和模塊名--> <!--<remote ip="192.168.28.39" name="tongbu"/>--> <!--<remote ip="192.168.28.40" name="tongbu"/>--> </localpath> <rsync> <commonParams params="-artuz"/> <auth start="true" users="rsync" passwordfile="/app/local/sersync/user.pass"/> <!-- rsync+密碼文件 這裏填寫服務器B的認證信息--> <userDefinedPort start="false" port="874"/><!-- port=874 --> <timeout start="false" time="100"/><!-- timeout=100 --> <ssh start="false"/> </rsync> <failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once--><!-- 修改失敗日誌記錄(可選)--> <crontab start="false" schedule="600"><!--600mins--> <crontabfilter start="false"> <exclude expression="*.php"></exclude> <exclude expression="info/*"></exclude> </crontabfilter> </crontab> <plugin start="false" name="command"/> </sersync> <!-- 下面這些有關於插件你能夠忽略了 --> <plugin name="command"> <param prefix="/bin/sh" suffix="" ignoreError="true"/> <!--prefix /opt/tongbu/mmm.sh suffix--> <filter start="false"> <include expression="(.*)\.php"/> <include expression="(.*)\.sh"/> </filter> </plugin> <plugin name="socket"> <localpath watch="/home/demo"> <deshost ip="210.36.158.xxx" port="8009"/> </localpath> </plugin> <plugin name="refreshCDN"> <localpath watch="/data0/htdocs/cdn.markdream.com/site/"> <cdninfo domainname="cdn.chinacache.com" port="80" username="xxxx" passwd="xxxx"/> <sendurl base="http://cdn.markdream.com/cms"/> <regexurl regex="false" match="cdn.markdream.com/site([/a-zA-Z0-9]*).cdn.markdream.com/images"/> </localpath> </plugin> </head>
bash#運行sersync
nohup /app/local/sersync/sersync2 -r -d -o /app/local/sersync/confxml.xml >/app/local/sersync/rsync.log 2>&1 &
nohup /app/local/sersync/sersync2 -r -d -o /app/local/sersync/img.xml >/app/local/sersync/img.log 2>&1 &

-d:啓用守護進程模式
-r:在監控前,將監控目錄與遠程主機用rsync命令推送一遍
-n: 指定開啓守護線程的數量,默認爲10個
-o:指定配置文件,默認使用confxml.xml文件
相關文章
相關標籤/搜索