NFS雙機熱備探究實驗linux
1、實驗背景:web
公司只有一臺NFS服務器,上面存有一些編譯工具,通用腳本等,如今該機器比較老舊,出現故障時恢復困難,存在單點故障不說,還會形成線上服務的不穩定,現急需對該服務器進行雙機熱備高可用,不管哪臺掛了,能夠自動切換過去。vim
2、初步設想:api
使用兩臺機器,使用文件同步工具對兩個機器的文件保持一致,其中一個掛掉後,將另外一個機器改成一樣的IP地址,使服務恢復,下面就來進行探究該方法是否能夠。服務器
3、實驗環境ide
master: 192.168.254.135 Linux版本:CentOS 6.9工具
slave: 192.168.254.136 Linux版本:CentOS 6.9測試
client: 192.168.254.129 Linux版本:CentOS 6.9ui
VIP:192.168.254.100spa
實驗目標:master和slave保存同一份存儲文件,不管哪臺機器down機,client1和2均不受影響。
4、實驗步驟
1、yum安裝nfs並配置keepalived,實現IP地址漂移。
master和slave上:
yum -y install nfs keepalived
yum -y install nfs-utils nfs-utils-lib nfs4-acl-tools
chmod 777 /global
vim /etc/exports
/global 192.168.254.0/24(rw,sync,no_root_squash)
/etc/init.d/rpcbind start
service nfs start
vi /etc/selinux/config
SELINUX=disabled
service iptables stop
chkconfig iptables off
vim /etc/keepalived/keepalived.conf
2、客戶端
mount -t nfs 192.168.254.100:/global /global
可是通過試驗,使用了keepalived並不能實現雙機熱備,IP地址能夠漂移,可是nfs服務沒法自動恢復,必需要umount卸載掉而後從新掛載VIP的/global目錄,因此咱們就來單機抓包來分析一下根本緣由。爲了避免搞混VIP到底在哪臺機器上,咱們在這裏不使用VIP掛載,使用更改IP地址的方式測試服務是否能夠自動恢復。
步驟1:在客戶端掛載192.168.254.135這臺服務器的/global目錄,掛載成功
步驟2:把136這臺服務器的IP地址和mac地址都改爲和135相同,發現ls /global目錄提示Stale file handle。
步驟3:把136關機,135開機,發現global能夠自動掛回來。
打開wireshark進行抓包,發如今135關機後把136的IP地址改爲135,TCP鏈接能夠連回來,可是NFS連不回來,進行報文分析以下。
客戶端和正常的135服務器之間的通訊以下:
1、客戶端先向服務器端發送NFS V4 NULL Call,此報文中不包含什麼有用信息,只包含一個版本號。而服務器端也向客戶端返回一個一樣的空報文。此爲握手階段。
2、緊接着,客戶端向服務器端發送NFS報文之PUTROOTFH|GETATTR|GETFH操做。
在這裏須要先解釋一下FH文件句柄的含義:
RFC協議原文以下:The filehandle in the NFS protocol is a per-server unique identifier for a file system object. The contents of the filehandle are opaque to the client. Therefore, the server is responsible for translating the filehandle to an internal representation of the file system object.[1]
翻譯過來就是:NFS協議中的文件句柄是文件系統對象的每服務器惟一標識符。文件句柄的內容對客戶端是不透明的。所以,服務器負責將文件句柄轉換爲文件系統對象的內部表示。
通俗點講就是文件句柄是文件系統的表示方式,而且對客戶端是不透明的。
PUTROOTFH一般用做NFS請求中的第一個操做,用於爲後續操做設置上下文。客戶端經過使用PUTROOTFH操做,以ROOT 文件句柄啓動。PUTROOTFH操做指示服務器將「當前」文件句柄設置爲服務器文件系統的ROOT。一旦使用了這個PUTROOTFH操做,客戶端就可使用LOOKUP過程遍歷整個服務器的文件樹。
而GETATTR操做將獲取當前文件句柄指定的文件系統對象的屬性。
GETFH是指獲取當前文件句柄,此操做返回當前文件句柄值。
簡單來說就是客戶端要服務器端的/的文件句柄的值,而後服務器告訴他個人/的句柄hash值爲0x62d40c52。
3、客戶端反覆進行GETATTR的操做,將服務器端根的屬性所有獲取到
4、獲取完服務器的根的屬性以後客戶端請求PUTFH,ACCESS,GETATTR三個操做
PUTFH的意思就是我要對這個文件進行操做
ACCESS就是要訪問PUTFH的文件,即服務器的/,客戶端挨個問:我能不能讀?我能不能查找?我能不能修改?我能不能增長?我能不能刪除?
客戶端請求報文詳細信息:
而後服務器端就會告訴他:以下圖:
你能夠來讀、查、刪、增、改,可是我只容許你讀和查,意思就是你能夠來刪,可是我不讓你刪,並非不能刪。
5、那麼好,既然你能讓我查我就查一查個人/etc/fstab中要掛載誰呢?我要掛載你的/global,因而客戶端就先發送了查詢請求到服務器端,查一查/下有沒有global,若是有的話你把他的文件標識符發給我。
客戶端請求報文詳細信息:
其中:PUTFH是服務器的/的文件標識符,LOOKUP是要掛載的服務器的目錄,請求它的GETFH,和我須要的/global的屬性。
服務器響應報文詳細信息:
服務器說:你給個人根的FH我這匹配,OK,查詢請求能夠幫你查,OK,你要的/global的文件標識符是xxx,對應的hash值爲0x03168bcf,屬性給你。
6、好的,既然你給我了/global的FH我就沒必要每次都找/了,就像有了中間人牽線以後兩我的再聯繫就沒必要每次都讓中間人聯繫了同樣。直接能夠找/global了
客戶端發送了6次請求獲取/global的相關屬性。
7、兩我的是聯繫上了,可是可否進入對方的心呢?客戶端又問:我能不能讀?我能不能查……服務器端固然仍是頗有禮貌的說:你能夠讀,你能夠查……
客戶端請求報文:
服務器端響應報文:
至此,客戶端和服務器端鏈接創建完畢,下面進入/global,並執行ls命令。
8、ls命令執行時先獲取一些屬性信息,而後發送READDIR請求,
客戶端請求READDIR報文:
服務器端響應READDIR請求報文:
9、新建一個文件,總共進行了這麼多操做,咱們一一來看。
首先仍是權限檢查,而後發送客戶端ID報文:
裏面包含了客戶端的一些關鍵信息,
服務器端也會返回一個客戶端id
而後客戶端確認該id,服務器端再次確認。
接下來客戶端使用OPEN操做建立文件,操做信息以下圖:
裏面包含了不少文件相關的信息,例如權限,文件名,FH,客戶端ID等等信息。
而後服務器端響應該請求,二者之間互相發送OPEN_CONFIRM確認信息,最後關閉,發送CLOSE報文,完成一次寫操做,其餘過程相似,再也不贅述,總之報文裏面信息很是詳細。
10、心跳
在以後的一段時間內沒有對/global進行任何操做,他們之間仍然週期性的發送心跳包,客戶端每隔60秒發送一次更新請求,服務器端來響應。
那麼若是用另外一臺機器改爲一樣的IP地址來做爲服務器會發生什麼現象呢?
在客戶端訪問nfs服務器時一樣會發出請求報文,請求FH爲0x03168bcf的文件,可是服務器端會告訴他,我這沒有這個FH的文件,報一個NFS4ERR_STALE的錯誤,在RFC官網上查詢該錯誤的意思是:無效的文件句柄。參數中給出的文件句柄無效。該文件句柄引用的文件再也不存在或訪問它已被撤銷。
到這裏,對NFS的報文抓包分析即將接近尾聲,證實試圖經過keepalived爲nfs作高可用的方案是不可行的,緣由就是在nfs通訊的時候不只使用TCP鏈接,更重要的是使用FH文件句柄來識別是不是同一個文件系統,若是不一致的話是沒法自動恢復鏈接的。因此對NFS的高可用應該是用其餘方法。或者使用腳本不斷檢測NFS掛載點是否可用,若是不可用則強行卸載並從新掛載便可。
下面按照官方推薦的NFS高可用方法來作一遍實驗,看是不是FH不變。即NFS+DRBD的方式來測試。
測試步驟簡略寫一下便可,網上不少,再也不贅述。
第一步:下載repo yum源,並yun安裝drbd。
rpm -Uvh http://www.elrepo.org/elrepo-release-6-8.el6.elrepo.noarch.rpm
yum -y install drbd83-utils kmod-drbd83
第二步:修改配置文件
modprobe drbd
lsmod |grep drbd
cat /etc/drbd.conf
# You can find an example in /usr/share/doc/drbd.../drbd.conf.example
include "drbd.d/global_common.conf";
include "drbd.d/*.res";
cp /etc/drbd.d/global_common.conf /etc/drbd.d/global_common.conf.bak
cp /etc/drbd.d/global_common.conf /etc/drbd.d/global_common.conf.bak
第三步:編輯主配置文件
vim /etc/drbd.d/global_common.conf
global {
usage-count yes;
}
common {
protocol C;
handlers {
}
startup {
wfc-timeout 240;
degr-wfc-timeout 240;
outdated-wfc-timeout 240;
}
disk {
on-io-error detach;
}
net {
cram-hmac-alg md5;
shared-secret "testdrbd";
}
syncer {
rate 30M;
}
}
給master和slave主機增長硬盤,而後fdisk分區獲得一個設備路徑,本例中爲:/dev/sdb1。
而後vim /etc/drbd.d/r0.res 編輯
其中 on後面填寫主機和備機的主機名,本例爲master和slave,device爲未來生成的磁盤設備號,寫/dev/drbd0便可,disk爲剛剛分區以後的磁盤設備路徑,address分別寫主機和備機的IP地址。
resource r0 {
on master {
device /dev/drbd0;
disk /dev/sdb1;
address 192.168.254.135:7898;
meta-disk internal;
}
on slave {
device /dev/drbd0;
disk /dev/sdb1;
address 192.168.254.136:7898;
meta-disk internal;
}
}
drbdadm up r0 //啓動drbd drbdadm create-md r0 //建立drbd塊設備
/etc/init.d/drbd start //啓動drbd服務
ps -ef|grep drbd //查看進程
root 5174 2 0 02:25 ? 00:00:00 [drbd0_worker]
root 5193 2 0 02:25 ? 00:00:00 [drbd0_receiver]
root 5207 2 0 02:25 ? 00:00:00 [drbd0_asender]
root 5211 18667 0 02:25 pts/0 00:00:00 grep --color drbd
cat /proc/drbd //查看狀態
/etc/init.d/drbd status //查看狀態
drbd driver loaded OK; device status:
version: 8.3.16 (api:88/proto:86-97)
GIT-hash: a798fa7e274428a357657fb52f0ecf40192c1985 build by phil@Build64R6, 2014-11-24 14:51:37
m:res cs ro ds p mounted fstype
0:r0 StandAlone Secondary/Unknown UpToDate/DUnknown r-----
第四步:分區格式化,只在master上作 drbdadm primary --force r0 //只須要主機執行,設置本身爲master
mkfs.ext4 /dev/drbd0
mkdir /global
mount /dev/drbd0 /global
再次查看主的狀態,發現已經變成connected,Primary/Secondary了,意思就是已經鏈接,而且本身是主,掛載點是/global,類型是ext4。
查看備的狀態,發現也是connected,可是本身是Secondary,對方是Primary,沒有掛載點。
把primary的eth1給ifdown了,而後直接在secondary上進行主的提高(drbdadm primary --force r0),而且給mount上(mount /dev/drbd0 /global),發如今primary上測試拷入的文件已經同步過來了,而且客戶端能夠直接ls查看,無需從新掛載。
查看備的狀態,狀態是WFC,意思就是等待鏈接,由於主已經被我關機了,可是本身變成了Primary,對方爲Unknown,如今在客戶端對其寫入文件,啓動主節點。
以後把primary的eth1恢復後,發現沒有自動恢復主從關係,通過查詢,發現出現了drbd檢測出現了Split-Brain 的情況,兩個節點各自都standalone了。
手動恢復Split-Brain情況:
在secondary上:
drbdadm secondary r0
drbdadm -- --discard-my-data connect r0
在primary上:
drbdadm connect r0
drbdadm primary --force r0
mount /dev/drbd0 /global
參考文獻:
[1] https://pike.lysator.liu.se/docs/ietf/rfc/56/rfc5661.xml