DRBD = distributed replicated block device
DRBD 是把兩台以上的主機的硬碟空間 mirror 成一顆硬碟,就像是 RAID 1 一樣,只是 DRDB 是透過網路的
單 primary 模式,只允許一個 node 讀寫,檔案系統只適合 ext3, ext4, xfs
雙 primary 模式,因為會有同時存取的可能,所以需要有 distributed lock manager,像 GFS2 與 OCFS2
同步方式有
- Protocal A (非同步方式),常用於長距離複製,primary node 確認已寫入完畢,且要被複寫到 secondary node 的有暫存起來,此方式較有可能會有資料遺失。
- Protocal B (半同步方式),primary node 確認資料已寫入,且要被同步的資料也已送給 secondary node。
- Protocal C (同步複製方式),primary 與 secondary node 都確認已寫入完畢,這個方式較常被使用。
因為 DRBD 是透過網路傳送資料,所以最好先確保網路 ok 的,比如用 Gigabit Ethernet (網卡),網路有妥善備援。
也要確保沒有服務是會佔用到 tcp port 7788 ~ 7799
環境
CentOS 6.6 # 我本來是用 CentOS 6.4,但 drbd 需要有 2.6.32-504 kernel,所以我就用了 6.6 了
kernel 2.6.32-504.el6.x86_64
node1: 10.10.10.134 (primary)
node2: 10.10.10.135 (secondary)
指定主機名稱與 ip,因為設定會需要有 ip 與 名稱的解析
node1 與 node2
cat <<EOF>>/etc/hosts 10.10.10.134 node1 10.10.10.135 node2 EOF
再確定主機名稱是對的,因為 drbd 的名稱一定要對應到這個
node1
sed -i 's/^HOSTNAME=.*/HOSTNAME=node1/g' /etc/sysconfig/network
node2
sed -i 's/^HOSTNAME=.*/HOSTNAME=node2/g' /etc/sysconfig/network
安裝 drbd
使用有 drbd 套件 的 yum 庫,在 node1 與 node2 都要安裝
rpm -ivh http://www.elrepo.org/elrepo-release-6-6.el6.elrepo.noarch.rpm
node1 與 node2
yum -y install drbd84-utils kmod-drbd84
node1 與 node2
vi /etc/drbd.d/global_common.conf
global { usage-count no; # 是否要參與 DRBD 的統計,列在這裡 http://usage.drbd.org/ } common { net { protocol C; } }
設定資源,node1 與 node2 (兩台相同的內容),只要在 drbd.d/ 裡給個 XX.res 即可,因為 /etc/drbd.conf 就會 include 了,資源名稱叫 r1
cat </etc/drbd.d/r1.res # r1 為資源名稱,必需是 ASCII,不可有空白 resource r1 { disk { resync-rate 40M; # 同步速度,預設不給 M 時為 KB } on node1 { # 這個名稱一定要等於 hostname device /dev/drbd1; # drbd 使用的 device 名稱 disk /dev/sdb1; # 實際硬碟的 device address 10.10.10.134:7789; meta-disk internal; } on node2 { device /dev/drbd1; # drbd 使用的 device 名稱 disk /dev/sdb1; # 實際硬碟的 device address 10.10.10.135:7789; meta-disk internal; } } EOF
也可簡化內容
cat </etc/drbd.d/r1.res # r1 為資源名稱,必需是 ASCII,不可有空白 resource r1 { disk { resync-rate 40M; # 同步速度,預設不給 M 時為 KB } device /dev/drbd1; # drbd 使用的 device 名稱 disk /dev/sdb1; # 實際硬碟的 device meta-disk internal; on node1 { # 這個名稱一定要等於 hostname address 10.10.10.134:7789; } on node2 { address 10.10.10.135:7789; } } EOF
node1 與 node2
一定要載入 drbd kernel module 才可以使用
modprobe drbd
node1 與 node2
初始化 metadata
drbdadm create-md r1
成功 initial 訊息
initializing activity log NOT initializing bitmap Writing meta data... New drbd meta data block successfully created. success
node1 與 node2
啟動 drbd 資源,這時後 node 間會互相開始溝通了
drbdadm up r1
這裡其實可直接 /etc/init.d/drbd start 即可 (它也會 modprobe drbd)
查看狀態
cat /proc/drbd # 或 service drbd status
未同步時狀態為 Unknown
[root@node1 drbd.d]# service drbd status drbd driver loaded OK; device status: version: 8.4.6 (api:1/proto:86-101) GIT-hash: 833d830e0152d1e457fa7856e71e11248ccf3f70 build by phil@Build64R6, 2015-04-09 14:35:00 m:res cs ro ds p mounted fstype 1:r1 WFConnection Secondary/Unknown Inconsistent/DUnknown C
當 drbd start時,drbd device 也會被建立起來,它就是被用來掛載放資料的 device
/dev/drbd1
將 node1 設為 primary/secondary,預設 up 時會是 secondary/secondary
drbdadm primary --force r1
當 node1 (為 primary) 與 node2 (secondary) 的 drbd 都啟動時,就會開始同步
以下為同步狀態
node1
version: 8.4.6 (api:1/proto:86-101) GIT-hash: 833d830e0152d1e457fa7856e71e11248ccf3f70 build by phil@Build64R6, 2015-04-09 14:35:00 1: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r----- ns:7460188 nr:0 dw:0 dr:7460852 al:0 bm:0 lo:0 pe:1 ua:0 ap:0 ep:1 wo:f oos:926440 [================>...] sync'ed: 89.0% (904/8188)M finish: 0:00:27 speed: 33,052 (32,148) K/sec
node2
version: 8.4.6 (api:1/proto:86-101) GIT-hash: 833d830e0152d1e457fa7856e71e11248ccf3f70 build by phil@Build64R6, 2015-04-09 14:35:00 1: cs:SyncTarget ro:Secondary/Primary ds:Inconsistent/UpToDate C r----- ns:0 nr:7554304 dw:7554304 dr:0 al:0 bm:0 lo:1 pe:5 ua:0 ap:0 ep:1 wo:f oos:831300 [=================>..] sync'ed: 90.2% (808/8188)M finish: 0:00:25 speed: 32,552 (32,144) want: 31,120 K/sec
同步完後的狀態
[root@node1 drbd.d]# service drbd status drbd driver loaded OK; device status: version: 8.4.6 (api:1/proto:86-101) GIT-hash: 833d830e0152d1e457fa7856e71e11248ccf3f70 build by phil@Build64R6, 2015-04-09 14:35:00 m:res cs ro ds p mounted fstype 1:r1 Connected Primary/Secondary UpToDate/UpToDate C /var/lib/mysql ext4
參數值
- cs = connection state
- ro = roles of nodes
- ds = disk states
- p = replication protocol
- 其它參考 http://drbd.linbit.com/users-guide-8.4/ch-admin.html
查看 /proc/drbd 裡的 r—- 這段是什麼
它是 IO state flags
第一個欄位代表: r = running、s = suspended
其它參考 http://drbd.linbit.com/users-guide-8.4/ch-admin.html
其它
- ns = network send (KB)
- nr = network receive (KB)
- dw = disk writ (KB)e,本機硬碟寫入
- dr = disk read (KB)
- al = activity log,meta data 的 log 的更新數量
- bm = bit map,meta data 的 bitmap 的更新數量
- lo = local count,open request numbers
- pe = pending,送 request 給對方,但尚未回應的數量
- ua = unacknowledged
- ap = application pending,block I/O request 未回應數量
- ep = epochs
- wo = write order,寫入方式,b = barrier, f = flush , d = drain , n = none
- oos = out of sync (KB)
- 其它參考 http://drbd.linbit.com/users-guide-8.4/ch-admin.html
查看連線狀態
drbdadm cstate r1
查看資源角色
drbdadm role r1
查看硬碟狀態
drbdadm dstate r1
其實以上查看狀態的方式,我最後都只用 cat /proc/drbd 或 service drbd status
使用掛載 device 前先格式化,且 node1 的狀態一定要為 primary
mkfs.ext4 /dev/drbd1
安裝 mysql,順便裝一下 httpd、php,因為我使用 phpmyadmin 來測試
yum -y install mysql-server httpd php php-mbstring
裝好 mysql-server 時,/var/lib/mysql 目錄就有了
這時掛載 drbd 給 mysql 用
mount /dev/drbd1 /var/lib/mysql
再 service mysqld start後,/var/lib/mysql 就會產生資料庫了,且是在 drbd device 裡的
還有當 node1 掛載時, node2 是不能掛載的,需要 node1 umount 後, node2 切換為 primary 才行 (而 node1 為 secondary),如下動作
node1
service mysqld stop umount /dev/drbd1 drbdadm secondary r1
node2
drbdadm primary r1 mount /dev/drbd1 /var/lib/mysql service mysqld start
以上不可以同時間設置兩個為 primary,不然會有同步問題 (split brain)
DRBD 當然不是不能兩邊都是 primary
DRBD 還是有可以讓兩個 node 皆為 primary,一定要設定 protocol C;
但風險就是網路中斷的話就會有 split-brain 發生
node1 與 node2,設定兩個為 primary 方式,在 r1.res 加入
resource r1 { net { protocol C; allow-two-primaries yes; } startup { become-primary-on both; # 啟用 drbd 服務時也讓 node 為 primary,但不適合在有 pacemaker 環境下使用 } }
node1 與 node2
drbdadm adjust r1
再來可以在 node2
drbdadm primary r1
這樣子就可以兩邊都是 primary 了
Q: ‘r1’ not defined in your config (for this host)
A: XXX 需要相同於 hostname
Q: 在 drbdadm create-md r1 時
md_offset 8587153408 al_offset 8587120640 bm_offset 8586858496 Found ext3 filesystem 8385896 kB data area apparently used 8385604 kB left usable by current configuration Device size would be truncated, which would corrupt data and result in 'access beyond end of device' errors. You need to either * use external meta data (recommended) * shrink that filesystem first * zero out the device (destroy the filesystem) Operation refused. Command 'drbdmeta 1 v08 /dev/sdb1 internal create-md' terminated with exit code 40
A: 是因為它發現 /dev/sdb1 裡有東西,所以要清空一下才行
以上是 DRBD 的設定過程,再來要麼自動切換,當 node1 掛了,讓 node2 可以為 primary,並 mount drbd device,及 start mysql 服務
所以就要安裝設定 heartbeat (3.0.4 版),node1 與 node2 都要
這邊會用到 VIP (10.10.10.180),供自動切換為主要的溝通 ip,可用 ip a 看得到 (不會在 ifconfig eth0 上看到)
yum install -y heartbeat
node1 與 node2 設定 ha.cf,node2 的 ucast eth0 為 10.10.10.134
cat <<EOF>/etc/ha.d/ha.cf autojoin none debugfile /var/log/ha-debug # debug log logfile /var/log/ha-log # log logfacility local0 keepalive 2 # 多久間隔確認對方是否還活著 (秒) deadtime 10 # 多久時間確認對方已完全 down (秒) warntime 4 # 持續多久時間連不上就警告 (秒) initdead 60 # 主機若重開機,等待網路或服務啟動的時間 (秒) udpport 694 # 使用 694 Port 來作 Heartbeat 監控 #bcast eth1 # 用 eth1 作 UDP 廣播來發送 heartbeat 訊息 ucast eth0 10.10.10.135 # 用 eth0 作 UDP 單播,來發送 heartbeat 訊息,此為對方 IP,建議採用單播,避免多組 cluster 主機都會看到對方節點 # node1 這裡填的是 node2 的 IP # node2 就是填 node1 的 IP auto_failback off # 若 node1 異常修復完畢,是否需要從 secondary 自動切換回 primary,建議 off node node1 # node1 與 node2,必須要與 uname -n 指令得到的名稱一致 node node2 ping 10.10.10.252 # 其它 IP,作為網路正不正常的另一個依據 respawn hacluster /usr/lib64/heartbeat/ipfail respawn hacluster /usr/lib64/heartbeat/dopd apiauth dopd gid=haclient uid=hacluster EOF
node1 與 node2,要相同內容的 authkeys
(echo -ne "auth 1\n1 sha1 "; echo $RANDOM | openssl sha1 | awk '{print $2}') > /etc/ha.d/authkeys chmod 600 /etc/ha.d/authkeys
node1 與 node2,同內容,用來判斷 drbd 的資源,及掛載到那個目錄,及 mysql 服務名稱 (/etc/init.d/mysqld)
cat <<EOF> /etc/ha.d/haresources node1 10.10.10.180 drbddisk::r1 Filesystem::/dev/drbd1::/var/lib/mysql::ext4 mysqld EOF
node1 與 node2,啟動 heartbeat
/etc/init.d/heartbeat start
讓服務開機時啟動
chkconfig drbd on chkconfig heartbeat on # mysqld 不用 on
情境測試
當 node1 的 drbd restart 時,它會說
Stopping all DRBD resources: umount: /var/lib/mysql: device is busy.
r1: State change failed: (-12) Device is held open by someone
而 node2 的 drbd restart 時,服務不會有什麼影響
情境測試
當 node1 的 heartbeat restart 後,就會讓它們之間的角色互換了,node1 就變成 secondary/primary、umount VIP 與 drbd1、mysqld stop,而 node2 就 mount VIP 與 drbd1、mysqld start,與狀態為 primary/secondary
情境測試
當 node1 掛了, heartbeat 就會觸使 node2 接手 VIP 並變身為 primary (同上)
當 node1 回復時,正常情況下,它就會一直是 secondary 了,那怎麼切換成 primary,我想就只有將 node2 的 heartbeat restart 囉
情境測試
啟動服務只要 node1 與 node2 的 drbd start,與 heartbeat start 就好,mysqld 會被 heartbeat 帶起來的
情境測試
當 node2 的 heartbeat stop 了,再來 node1 的 heartbeat 也 stop 了,node1 的 mysqld 也會 stop 與 umount drbd1,然後 drbd 的狀態都會是 secondary/secondary,再讓 node1 的 heartbeat start 後,等個 60 秒 (就是 initdead 60 設定)後 node1 的狀態就會是 primary/secondary 與 mount drbd1 與 start mysqld,最後再將 node2 的 heartbeat start
情境測試
當 node1 與 node2
service mysqld stop ; service drbd stop ; service heartbeat stop
再同時啟動
service drbd start
再同時啟動
service heartbeat start
狀態會是
node1 為 primary/secondary,mount VIP 與 drbd1
node2 為 secondary/primary
情境測試
如果是 node1 掛了,而 node2 為 primary 時,兩台重開機,將會是 node1 為 primary 的,所以在這之前要先確保資料那一個才是主要的
情境測試
split-brain (未實際測過)
split-brain 解法
node2
drbdadm secondary r1
放棄資料,狀態從 standalone 變為 WFConnection
drbdadm — –discard-my-data connect r1
node1
drbdadm connect r1
測試時除錯
watch "cat /proc/drbd;echo;echo;ip a | grep 'inet 10'; echo ;echo ;df -h ; echo;echo ; service heartbeat status ; echo ;echo ; service mysqld status"
tail -f /var/log/ha-* /var/log/messages
留言