1. Rsync基本介紹
Rsync是一個文件同步工具,在同步的時候,只同步發生變化的文件或者是目錄(每次發生變化的數據對整個同步目錄數據來說是很小的,rsync在遍歷查找文件時,速度很快)
2. rsync的兩種工作模式
rsync有兩種工作模式,客戶端和服務器端,即rsync的客戶端和服務器端是同一個程序,名字都叫rsync,你用它啟動了服務作為守護進程,他就是服務器端,你沒啟動服務,而是直接調用它的命令,那么他就是客戶端。
3. rsync的同步方案
假設有A、B兩台服務器,我們要把A的文件同步到B,由於rsync的工作模式分為客戶端從服務器端下載文件(pull操作),或者客戶端把文件推送到服務器端(push操作),所以我們要討論一個問題,A、B誰做客戶端,誰做服務器端?
3.1 方案一
假設A做服務器端,B做客戶端,那么B要從A中同步文件,就要啟動定時任務,每隔一段時間執行一次同步命令,該命令會把A中的變化數據同步過來(實際上是做rsync客戶端做pull操作)。
3.2 方案二
假設A做客戶端,B做服務器端,A定時運行同步命令,把變化文件推送到B(rsync客戶端做push操作)
這兩個方案感覺都可以,那到底哪個好呢?
假設我們還有C、D兩台服務器也要從A同步文件,也就是B、C和D都從A同步文件,假設用方案一,那么B、C和D都要設置一個定時任務,定時從A中拉取文件進行同步,但這有一個問題,無法實時同步,因為B、C和D都不知道A什么時候更新了文件,只能定時去同步。
如果使用方案二,則B、C和D都是rsync的服務器端(都要啟動一個rsync守護進程),而客戶端只有一個,就是A。假如我們在A中添加定時任務,定時執行同步命令,把A中的文件推送到B、C和D,那感覺和方案一沒什么區別,也是無法實時同步文件。
但是,在方案二中,我們可以利用serync來檢測哪些文件更新了,然后用serync調用rsync同步命令,把更新變化的文件推送到B、C、D服務器。
4. 環境信息
使用方案二 push操作
192.168.28.100 客戶端
192.168.29.101 服務端
4.1 配置服務端
192.168.29.101
4.1.1 安裝rsync和修改配置文件
[root@node2 ~]# yum -y install rsync
[root@node2 ~]# cat /etc/rsyncd.conf
#指定運行的用戶名或ID號(rsync客戶端推送過來的文件所有者會被創建為uid指定的所有者)
uid = root
#指定運行的組名或組ID號(rsync客戶端推送過來的文件所屬組會被創建為gid指定的所屬組)
gid = root
#切換目錄
use chroot = no
#最大連接數
max connections = 10
#pid文件路徑
pid file = /var/run/rsyncd.pid
#鎖文件路徑
lock file = /var/run/rsyncd.lock
#日志文件路徑(可通過log format參數設置日志格式)
log file = /var/run/rsyncd.log
#傳輸日志
transfer logging = yes
#超時時間
timeout = 900
#忽略無法讀取的文件
ignore nonreadable = yes
#忽略部分io錯誤
ignore errors
#是否只讀(false就接受上傳,即puhs,否則只接受下載,即pull)
read only = false
#下載(pull)操作時,如果沒寫下載哪個模塊,則會列出模塊
list = false
#允許的客戶端ip或ip段(24也可寫成255.255.255.0,這是網段,或子網掩碼)
#host allow = 10.37.129.5/24
host allow = *
#除了允許的ip或ip段外禁止其他ip或ip段
#host deny = 0.0.0.0/32 #也可以直接寫*號
#認證用戶(客戶端執行同步操作時,需要用user@ip來指定用戶名,就跟ssh登錄一個道理,這里寫users是因為可配置多個用戶,用逗號隔開即可)
auth users = xiebruce
#認證密碼文件(后面會創建該文件,其實內容就是“用戶名:密碼”,一行一個用戶)
secrets file = /etc/rsyncd.secrets
#如果用-az指定了打包壓縮同步的文件,則指定這些后綴可以不壓縮這些文件。
# dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2
############# 自定義的傳輸模塊2 ##################
[ftpdata]
#同步路徑
path = /data
#注釋
comment = website
#不接受的目錄(該目錄位於path指定的目錄下)
exclude = cache
可以用man查看相應的配置
-
個別參數的詳解
use chroot = no
如果為yes, rsync會首先進行chroot設置,將根映射在path參數路徑下,對客戶端而言,系統的根就是path參數指定的路徑。但這樣做需要root權限,並且在同步符號連接資料時只會同步名稱,不會同步內容,所以我們一般設置為no。
4.2 在客戶端服務器創建登錄服務端的密碼文件
sudo echo "123456" > /etc/rsyncd.password
4..3 在服務器端創建用戶密碼對
sudo echo "xiebruce:123456" > /etc/rsyncd.secrets
注意:服務器端的用戶密碼文件是“用戶名:密碼”,而客戶端只需要密碼
4.4 修改客戶端和服務端的密碼文件權限
服務端
sudo chmod 600 /etc/rsyncd.secrets
sudo chown root:root /etc/rsyncd.secrets
客戶端
sudo chmod 600 /etc/rsyncd.password
sudo chown root:root /etc/rsyncd.password
注意:一定要服務端和客戶端都要設置
4.5 啟動服務進行在客戶端推數據進行測試
systemctl start rsyncd
systemctl enable rsyncd
rsync -avz --partial /data xiebruce@192.168.29.101::/data/ --password-file=/etc/rsyncd.password
5. 在客戶端安裝和配置sersync
5.1 配置文件如下
[root@node1 sersync]# cat confxml.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<head version="2.5">
<!-- hostip與port是針對插件的保留字段,對於同步功能沒有任何作用,保留默認即可。 -->
<host hostip="localhost" port="8008"></host>
<!-- 是否開啟debug模式 -->
<debug start="false"/>
<!-- 如果是xfs文件系統,則需要設置為true才能同步,rehat/REEL/CentOS/Fedora新版本默認都是xfs文件系統,可使用df -Th命令查看 -->
<fileSystem xfs="true"/>
<!-- 過濾器,設置為true則會對里面的exclude對應的正則匹配到的文件進行過濾,即不同步 -->
<filter start="true">
<!-- <exclude expression="(.*)\.svn"></exclude> -->
<!-- <exclude expression="(.*)\.gz"></exclude> -->
<!-- <exclude expression="^info/*"></exclude> -->
<!-- <exclude expression="^static/*"></exclude> -->
<exclude expression="^cache/*"></exclude>
</filter>
<!-- inotify是linux的內核功能,這里用於設置創建/刪除/修改/移動文件時,是否視為文件改變(進而進行同步) -->
<inotify>
<!-- 刪除一個文件是否視為文件改變(很明顯我們要設置為true) -->
<delete start="false"/>
<!-- 創建一個文件夾是否視為文件改變(很明顯我們要設置為true) -->
<createFolder start="true"/>
<!-- 創建一個文件是否觸發文件改變事件(這里要設置false,因為創建一個文件除了有createFile事件還會有closeWrite事件,我們只要把closeWrite事件設置為true即可監控到創建 一個文件) -->
<createFile start="false"/>
<!-- 創建文件或修改文件后再關閉會觸發該事件,比如vim打開一個文件,修改后用(:wq)保存,則會觸發該事件,當然創建新文件一樣會觸發 -->
<closeWrite start="true"/>
<!-- 從別的地方移到被監控目錄是否視為文件改變,毫無疑問要設置為true -->
<moveFrom start="true"/>
<!-- 被監控目錄中的某個文件被移動到其他地方算不算文件改變?毫無疑問要設置為true -->
<moveTo start="true"/>
<!-- 文件屬性改變了,是否視為文件改變?這個我們可以認為文件沒有改,所以設置false -->
<attrib start="false"/>
<!-- 文件內容被修改了是否視為文件改變?感覺文件改變肯定要設置為true,但其實不用,因為這個改變有可能是vim(:w)保存,還沒有關閉文件,所以保存的時候沒必要同步,而關閉 的時候會觸發closeWrite,所以修改的文件也是通過closeWrite來同步的 -->
<modify start="false"/>
</inotify>
<!-- servsync的模塊 -->
<sersync>
<!-- 指定要監控(即同步)的本地目錄 -->
<localpath watch="/data">
<!-- ip指定同步到遠程的哪個服務器,name填寫遠程服務器中rsync配置文件中的自定義模塊名稱(即中括號括起來的那個名稱) -->
<remote ip="192.168.29.101" name="ftpdata"/>
<!-- 如果你要同步到多台服務器,繼續填寫即可,每個服務器一個remote標簽 -->
<!--<remote ip="192.168.8.40" name="tongbu"/>-->
</localpath>
<!-- rsync模塊配置 -->
<rsync>
<!-- 公共參數,即我們手動執行rsync的時候要帶的選項就填在這里,servsync會自動組裝 -->
<commonParams params="-azP"/>
<!-- 密碼文件及指定用戶名(用戶名就是rsync服務器端配置文件中的"auth user =" 指定的用戶名) -->
<auth start="true" users="xiebruce" passwordfile="/etc/rsyncd.password"/>
<!-- 如果你rsync服務器不是默認端口873,那么就要在這里指定具體的端口,當然是默認的你也可以指定一下 -->
<userDefinedPort start="false" port="873"/>
<!-- rsync超時時間 -->
<timeout start="false" time="100"/><!-- timeout=100 -->
<!-- 是否使用ssh方式傳輸 -->
<ssh start="false"/>
</rsync>
<!-- 對於失敗的傳輸,會進行重新傳送,再次失敗就會寫入rsync_fail_log,然后每隔一段時間(timeToExecute進行設置,單位sec)執行該腳本再次重新傳送,然后清空該腳本。可以 通過path來設置日志路徑。 -->
<failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->
<!-- 定期整體同步功能,schedule表示crontab執行間隔,單位是min -->
<crontab start="false" schedule="600"><!--600mins-->
<!-- 同步過濾器,要開啟請把start設置為true,用於 整體同步時,排除一些文件或目錄,比如緩存目錄可以不需要同步 -->
<crontabfilter start="false">
<exclude expression="*.php"></exclude>
<exclude expression="info/*"></exclude>
</crontabfilter>
</crontab>
<!-- 同步完成后,執行一個插件,name表示執行哪些插件,而這個插件必須在后邊用plugin標簽定義 -->
<plugin start="false" name="command"/>
</sersync>
<!-- 定義一個command插件(command插件類型的一種,另外的類型有socket,refreshCDN,http(目前由於兼容性問題,http插件暫時不能用)) -->
<plugin name="command">
<!-- command插件其實就是“.sh”結尾的shell腳本文件,prefix和subffix用於拼成一條執行shell命令的命令 -->
<param prefix="/bin/sh" suffix="" ignoreError="true"/> <!--prefix /data/wwwroot/mmm.sh suffix-->
<!-- 該腳本做操作時要過濾的文件正則 -->
<filter start="false">
<include expression="(.*)\.php"/>
<include expression="(.*)\.sh"/>
</filter>
</plugin>
<!-- 定義一個socket插件,注意插件定義了但沒有調用的話,是不會被執行的 -->
<plugin name="socket">
<localpath watch="/data">
<deshost ip="192.168.138.20" port="8009"/>
</localpath>
</plugin>
<!-- 定義一個refreshCDN插件,主要用於同步數據到cdn -->
<plugin name="refreshCDN">
<localpath watch="/data0/htdocs/cms.xoyo.com/site/">
<cdninfo domainname="ccms.chinacache.com" port="80" username="xxxx" passwd="xxxx"/>
<sendurl base="http://pic.xoyo.com/cms"/>
<regexurl regex="false" match="cms.xoyo.com/site([/a-zA-Z0-9]*).xoyo.com/images"/>
</localpath>
</plugin>
</head>
5.2 客戶端啟動
sersync2 -o /usr/local/sersync/confxml.xml -d
現在,你可以測試一下在100服務器的同步目錄上添加文件,修改文件內容,看101服務器是否會修改.
解釋一下這個參數配置
前面配置文件里的注釋也說了,由於各種原因(如網絡很差或延遲非常大)可能會有傳輸失敗的情況,那為什么記錄傳輸失敗的文件不叫.log,而叫.sh呢?
下圖就是我傳輸失敗后自動成的/tmp/rsync_fail_log.sh文件的內容:
6. rsync+Lsyncd 實時同步配置
6.1 介紹
Lsyncd是一個輔助文件同步工具。它通過監聽系統的文件變化事件,調用rsync進行同步。注意“輔助”二字,輔助的意思是:同步文件本身並不是由lsyncd來實現,它只負責監測哪些文件改變了,進而調用rsync來完成同步,真正同步文件的是rsync,如果你不知道什么是rsync,請查看使用sersync +rsync進行實時文件同步中的rsync部分。
6.2 Lsyncd的三種同步模式
- default.rsync
- default.rsyncssh
- default.direct
為了方便,我們直接把它們稱為rsync、rsyncssh、direct
6.2.1 rsync同步模式
- rsync無法知道“什么時候同步”,因為rsync只有執行同步命令的時候,才會去掃描文件判斷哪些文件被修改了,只能建立一個定時任務,每隔一定的時間(比如5分鍾,10分鍾等等)去執行一次同步,這樣雖然能同步,但卻“不實時”。
- lsyncd就可以監聽文件的修改,換句話說,某個文件修改了,lsyncd會得到通知(原理是使用linux系統的inotify/fsevents功能),得到通知之后,再去調用rsync把修改的文件進行同步(即組裝一句rsync同步語句並執行),達到“實時同步”的效果。
- lsyncd調用rsync同步命令的時候,會用rsync的--include-from=FILE之類的選項來指定要同步哪些文件,這樣可以達到“減少rsync掃描文件帶來的延時和性能損耗”。
- 為什么這么說呢?因為如果讓rsync自己去查詢哪些文件改變了,需要消耗較多的時間和服務器資源,試想一下,在100萬個文件中,有一個文件添加了一個英文的句號.,如果沒有lsyncd告訴rsync改變的是這個文件,那rsync就要去掃描100萬個文件來找出這個僅僅多了一個.的文件,雖然rsync的查找效率很高,但這個查找是非常沒有必要的,這就是為什么lsyncd能“減少rsync掃描文件帶來的延時和性能損耗”。
rsync配置如上
環境如上
6.1 安裝Lsyncd
rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm # 安裝 epel 源
yum -y install lsyncd rsync # 安裝
vim /etc/lsyncd.conf # 配置
6.2 配置文件
-- 由於該配置文件實際上是lua語言的語法,所以寫注釋要用--,--是lua語言的注釋符號
-- Lsyncd本身的配置
settings {
-- 指定日志文件位置
logfile = "/var/log/lsyncd/lsyncd.log",
-- 指定狀態文件位置
statusFile = "/var/log/lsyncd/lsyncd.status",
-- inotify事件模式,什么事件才同步,CloseWrite表示文件關閉的時候同步(創建文件,修改文件后保存都會觸發CloseWrite事件)
inotifyMode = "CloseWrite",
-- 最大同步進程數(default.rsyncssh模式,則必須設置為1,這就是rsyncssh模式的缺點了,如果是default.rsync模式則可以設置大於1,這樣會有多個同步進程,速度更快)
maxProcesses = 8,
-- maxProcesses = 1,
-- 配合下面的delay選項使用,delay單位是秒,當delay時間到了,不管maxDelays設置多少,都會同步,同樣,當maxDelays達到了設定值,不管是否到delay時間,都會同步,即兩個選項有一個滿足即會觸發同步,為了實時同>步,我們一般設置為1,表示即使只有一個文件改變也同步
maxDelays = 1,
-- 是否以后台的方式運行,注意它是nodaemon,所以是雙重否定,如果填false,意思就是“不要不后台運行”(即后台運行),非后台運行一般用於調試,把rsync的verbose也設置為true,這樣會把同步的細節輸出到控制台,方便調試
nodaemon = false,
}
---- 同步配置default.rsync模式(比如配置從哪同步到哪,要忽略哪些文件,多久同步一次等),可以有多個sync模塊,每個模塊用於設置一台目標機器
sync {
-- 有default.rsync/default.direct/default.rsyncssh三種模式,我們默認都用default.rsync即可。
default.rsync,
-- 同步源目錄(本機某個目錄)
source = "/data/",
-- 同步目標地址,不同同步模式有不同寫法,由於絕大多數情況都采用rsync同步,所以這里寫的是rsync的同步地址
target = "xiebruce@10.1.1.135::ftpdata",
-- 默認true,允許刪除目錄服務器中的某些文件(即刪除“那些在源服務器中不存在的文件”),可選值有: true/false/startup/running,startup就是只在啟動lsyncd服務的時候判斷目標服務器中有哪些文件在源服務器中沒有,然后把這些文件刪除,但啟動之后如果目標服務器又新增了文件,這些文件即使在源服務器不存在,也不會被刪除;而running與startup正好相反,是在啟動的時候不會刪除,啟動之后會刪除,true=running+startup,false相當於running和startup都不做。
delete = false,
-- 哪些文件不同步(可用正則))
-- exclude = {
-- '.**',
-- '.git/**',
-- '*.bak',
-- '*.tmp',
-- 'runtime/**',
-- 'cache/**'
-- },
-- 與上邊的maxDelays配合,maxDelays是累計事件數(單位:個),delay是時間(單位:秒),這兩個只要有一個符合條件就會同步一次,但為了確保實時同步,maxDelays我們一般設置為1,也就是只要有一個文件變化事件,就會同步一次,而delay是比較大的,默認是15。當然,假如我們把maxDelays設置為100,那可能15秒到了也沒有達到100個文件變化,但由於到達時間了,它也會同步。
delay = 15,
-- 當init = false時只同步進程啟動以后發生改動事件的文件,原有的目錄即使有差異也不會同步,如果為true,則啟動后如果源目錄與目標目錄的文件有差異,就會同步,我們當然要設置為true,默認為true,所以這個設置可以不寫,寫在這里是為了解釋它。
-- init = false,
-- rsync的配置(這是default.rsync模式,如果是default.rsyncssh模式,該模塊的配置會有所不同)
rsync = {
-- rsync可執行文件的絕對路徑
binary = "/usr/bin/rsync",
-- 密碼文件路徑(default.rsyncssh模式不需要該項)
password_file = "/etc/rsyncd.password",
-- 打包后再同步(注意,打包不等於壓縮,打包即可以壓縮也可以不壓縮)
archive = true,
-- 壓縮后再同步
compress = false,
-- 輸出同步信息(由於是后台執行,所以沒必要輸出,如果非后台執行可以設置為true,非后台執行主要用於調試)
verbose = false,
-- 由於rsync有非常多的選項(請自己rsync --help查看),部分非主要選項可以用_extra的方式指定,雙引號引住,逗號分隔(bwlimit中的bw是bandwith,即帶寬,整個意思是帶寬限制,omit-link-times忽略符號鏈接的修改時間)
_extra = {"--bwlimit=200", "--omit-link-times"}
}
}
7. 同時同步到多台機
格式如下,每台目標服務器一個sync模塊即可,每個sync模塊都像上邊說的那樣寫就行,其實就只是ip不同,其他都一樣:
settings {
logfile = "/var/log/lsyncd/lsyncd.log",
inotifyMode = "CloseWrite or Modify",
-- statusFile = "/var/log/lsyncd/lsyncd.status",
}
-- B服務器配置
sync {
default.rsync,
source = "/etc/nginx/",
target = "rsync://rsync@192.168.1.6:1873/nginx/",
exclude = { ".*", "*.tmp", "*.swp", "*.bak", "*.log", "*.swx", "*~", "sets/config.json", "listen_local_*" },
delay = 2,
init = false,
rsync = {
password_file = "/etc/rsyncd.passwd",
archive = true,
compress = true,
verbose = true,
checksum = true,
ignore_times = true
}
}
-- C服務器配置
sync {
default.rsync,
source = "/data/web/",
target = "rsync://rsync@192.168.1.11:1873/web/",
exclude = { ".*", "*.tmp", "*.swp", "*.bak", "*.log", "*.out", "*/logs/*", "*.swx", "*~" },
delay = 120,
init = false,
rsync = {
password_file = "/etc/rsyncd.passwd",
archive = true,
compress = true,
verbose = true,
checksum = true,
ignore_times = true
}
}
-- D服務器配置
sync {
default.rsync,
source = "/data/script/",
target = "rsync://rsync@192.168.1.100:1873/script/",
exclude = { ".*", "*.tmp", "*.swp", "*.bak", "*.log", "*.out", "*/logs/*", "*.swx", "*~" },
delay = 2,
init = false,
rsync = {
password_file = "/etc/rsyncd.passwd",
archive = true,
compress = true,
verbose = true,
checksum = true,
ignore_times = true
}
}