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

 

最後修改日期: 2015 年 06 月 04 日

作者

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。