Site icon Mr. 沙先生

架設 HA 高可用性:MySQL DRBD + Heartbeat – 兩台式架構 HA (Master/Slave)

在 MySQL HA 架構,企業中使用最頻繁的就是 DRBD + Heartbeat,其原因沒有別的,就是最省錢;只需要兩台 Database Server,並且使用 Master / Slave Fail-over 進行備援,若是 Master 掛掉,只需要在短短的幾秒內即可讓 Slave 升上 Master 上線服務。

MySQL HA 有幾種選擇 MHA、MMM、Keepalived、Heartbeat、Pacemaker ..

使用兩台式的 Master / Slave 的缺點上就是沒有第三台 Monitor Server 協助判定主機 Active / Dead以及切換,所以在技術上如果沒有處理好的話就會造成 split-brain 的狀況,這樣就必須要人為介入處理

DRBD + Heartbeat 官方也提供了 split-brain 的自動復原功能 Configure-split-brain-behavior

在這篇是採用 DRBD + Heartbeat 做 LAB 使用,架構如下:

採用兩台 Database Server,平時僅有 Master 運作,而 Slave 處於 stand by 的狀態,只有發生狀況才會替補上。

Client 端都是使用 VIP 在進行連線,Master / Slave 之間使用 heartbeat 心跳偵測彼此是否 Active / Dead,當 Master dead 狀態成立,heartbeat 會將 Slave 升級為 Master、掛載 Disk 資源池、啟動 MySQLd,整個流程的 down time 時間可以自己依照網路環境調整,若對你的內網很有信心,整個 MySQL 的 downtime 可以不超過 5 秒。

建立高可用性(HA)的 MySQL – DRBD + Heartbeat

**** 以下設定請在 mysql-node1、mysql-node2 同步作業 ****

建立 DRBD

Step.1 安裝 EL repo、drbd84

$ rpm -ivh http://www.elrepo.org/elrepo-release-6-6.el6.elrepo.noarch.rpm
$ yum install drbd84-utils kmod-drbd84 --enablerepo=elrepo

Step.2 檢查 kernel 版本是否支援對應的 DRBD 版本,並且載入 kernel drbd module,若沒有載入你的 drbd 是無法使用的

此篇是採用 drbd84 所支援的 kernel 最少要是 2.6.32-573.xx,在這之前的 kernel 請使用 drbd83

$ uname -r
2.6.32-642.1.1.el6.x86_64

$ modprobe drbd
#如果出現"FATAL: Module drbd not found."代表你的 kernel 並不支援 drbd84,請升級你的 kernel

Step.3 設定 hosts、hostname,DRBD 的設定會需要 hostname 和 hosts

$ vim /etc/hosts
192.168.50.20 mysql-node1
192.168.50.21 mysql-node2

$ vim /etc/sysconfig/network
HOSTNAME=mysql-node1

# HOSTNAME請設定 mysql-node1、mysql-node2 的主機名稱

Step.4 設定 drbd 的 global_common.conf 全局設定

$ vim /etc/drbd.d/global_common.conf

global {
    usage-count no;      # 是否提供 DRBD 進行分析
}
common {
    net {
        protocol C; # A 異地複製。Master寫入本機硬碟完畢並發送網路同步後即判定同步完成,Slave可能會有未寫入完全的風險。
    }               # B Memory複製。Master寫入本機硬碟完畢並發送給Slave記憶體空間即判定同步完成,若是出現異常則可能遺失最近幾次的資料。
}                   # C 同步複製。Master寫入本機硬碟完畢並且Slave也寫入硬碟完畢判定同步完成。

Step.5 設定 drbd 的 meta data 資源池

$ vim /etc/drbd.d/meta.res

# 建立資源池
resource meta {
    disk {
        resync-rate 1000M;  # 同步速度, 依照你網卡的速度而定
    }
    device /dev/drbd0;      # drbd 使用的 device 名稱
    disk /dev/sdb1;         # 實際切割出來的磁區,必須是 block device
    meta-disk internal;     # 此外還有 external
    on mysql-node1 {        # 和 hostname 相同
        address 192.168.50.20:7789;
    }
    on mysql-node2 {
        address 192.168.50.21:7789;
    }
}

如上的設定方式是 mysql-node1、mysqlnode2 具有相同的 /dev/sdb1、所以我寫在 resource meta 變數內而不是寫在 node 內。

Step.6 初始化 metadata

$ drbdadm create-md meta

initializing activity log
NOT initializing bitmap
Writing meta data...
New drbd meta data block successfully created.

Step.7 兩邊都啟動 drbd

$ drbdadm up meta

Step.8 查看 drbd 狀態

$ cat /proc/drbd

version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef9db1ba2792c642c251790795db49 build by mockbuild@Build64R6, 2016-01-12 13:27:11
 0: cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r-----
    ns:0 nr:0 dw:0 dr:0 al:8 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:104854364

因為還沒有決定要以哪邊的資料為主,所以 ds:Inconsistent,兩邊都是 Secondary

Step.9 在要決定是 Master 的 mysql-node1 執行 primary 使他升上 Master

# in mysql-node1
$ drbdadm primary --force meta
# 也可以用 drbdadm -- --overwrite-data-of-peer primary r0

$ cat /proc/drbd

# mysql-node1被升上Primary,並且ds為UpToDate,正同步到mysql-node2(Slave)
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef9db1ba2792c642c251790795db49 build by mockbuild@Build64R6, 2016-01-12 13:27:11
 0: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r-----
    ns:0 nr:0 dw:0 dr:0 al:8 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:104854364
    [================>...] sync'ed: 89.0% (8821390/1024000)M
    finish: 0:00:27 speed: 33,052 (32,148) K/sec

Step.10 同步完成 ds 狀態為 UpToDate/UpToDate。

$ cat /proc/drbd

version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by mockbuild@Build64R6, 2016-01-12 13
:27:11
 0: cs:Connected ro:Secondary/Primary ds:UpToDate/UpToDate C r-----
    ns:0 nr:100068956 dw:100068956 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0

Step.11 先格式化 drbd 磁區,然後準備資料

$ mkfs.ext4 /dev/drbd0

Step.12 將 MySQL data 指定到要 mount 的 metadata

$ mkdir -p /drbd/mysql
$ vim /etc/my.cnf
datadir=/drbd/mysql

Step.13 在 mysql-node1 嘗試 mount metadata,因為在 drbd 啟動時僅有 Master 有權限可以 mount metadata

$ mount /dev/drbd0 /drbd/mysql
$ service mysqld start

測試 create data 檢查是否可以寫入,如果你檢測 cat /proc/drbd 可以看到 dw 一直在寫入。

DRBD 測試

你可以在 mysql-node1、mysql-node2 之間切換 Primary/Secondary 並且寫入一些資料,確認同步OK

$ drbdadm primary meta      # 升級為 primary
$ drbdadm secondary meta    # 降級為 secondary

若是你只用 DRBD 的話就只能手動切換,這樣就沒有意義了,所以要搭配像是 Heartbeat 或是 Keepalive 這類型的東西來 Failover。

建立 Heartbeat

Step.1 直接下載 heartbeat

$ yum install heartbeat

Step.2 ha.cf 主要設定檔

$ vim /etc/ha.d/ha.cf

autojoin none
debugfile /var/log/ha-debug  # debug log
logfile /var/log/ha-log      # log
logfacility local0
keepalive 2                  # 每隔2秒確認一次對方存活狀態
deadtime 10                  # 當出現dead癥兆,10秒後確認已死機
warntime 4                   # 當出現dead癥兆,4秒後警告
initdead 60                  # 伺服器重開後等待init的啟動時間為60秒後才開始heartbeat
udpport 694                  # heartbeat互相監控的port
ucast eth0 192.168.50.20     # 填寫對方的IP,使用eth0/UDP單播連接,發送heartbeat訊息給對方,此外還有廣播的方式,但不建議使用。
auto_failback off            # 若是master恢復後是否將primary歸還,建議off。
node mysql-node1             # node 節點,與hostname相同
node mysql-node2
ping 192.168.50.254          # 第二個IP,作為網路正不正常的另一個依據。
respawn hacluster /usr/lib64/heartbeat/ipfail  # heartbeat ip fail的工具套件,背景常駐
respawn hacluster /usr/lib64/heartbeat/dopd    # heartbeat 升降Master/Slave的工具,背景常駐
apiauth dopd gid=haclient uid=hacluster        # heartbeat 所使用的權限

Step.3 heartbeat 連線所使用的認證密碼檔,使用目前安全性尚OK的 sha1,權限必須為 600,並且加入 heartbeat 的都必須擁有此 authkeys

$ (echo -ne "auth 1\n1 sha1 "; echo $RANDOM | openssl sha1 | awk '{print $2}') > /etc/ha.d/authkeys
$ chmod 600 /etc/ha.d/authkeys

Step.4 設定 haresources,當發生故障異常時,heartbeat 要幫你做的事情就在 haresources 進行設定

mysql-node1 IPaddr::192.168.50.22/32/eth0:1 drbddisk::meta Filesystem::/dev/drbd0::/drbd/mysql::ext4 mysqld

當 mysql-node1、mysql-node2 都 ready 好之後就可以啟動服務

$ chkconfig drbd on 
$ chkconfig heartbeat on
$ chkconfig mysqld off  # 預設開機不啟動,讓heartbeat來進行啟動。

測試

case.1 將 master 中斷時,slave 偵測到並升上 primary

# 警告mysql-node1已死
heartbeat: [19973]: WARN: node mysql-node1: is dead

# 由於mysql-node1已死,所以mysql-node1已經放棄resources
heartbeat: [19973]: info: Dead node mysql-node1 gave up resources.

# 最後確認mysql-node1死亡
ipfail: [20000]: info: Status update: Node mysql-node1 now has status dead

# mysql-node1 eth0 死亡
heartbeat: [19973]: info: Link mysql-node1:eth0 dead.

# ipfail 偵測到 slave 還活著!!!
ipfail: [20000]: info: NS: We are still alive!

# ipfail 進行狀態更新
ipfail: [20000]: info: Link Status update: Link mysql-node1:eth0 now has status dead
ipfail: [20000]: info: Asking other side for ping node count.
ipfail: [20000]: info: Checking remote count of ping nodes.

case.2 slave 復原,master 偵測到復原通知,僅更改 slave 狀態由 dead 轉 avtive

# mysql-node1 偵測到上線
heartbeat: [19973]: info: Link mysql-node1:eth0 up.

# mysql-node1 更新狀態初始化
heartbeat: [19973]: info: Status update for node mysql-node1 : status init

# ipfail 又出場更新狀態了
ipfail: [20000]: info: Link Status update: Link mysql-node1:eth0 now has status up
heartbeat: [19973]: info: all clients are now paused
ipfail: [20000]: info: Status update: Node mysql-node1 now has status active
heartbeat: [19973]: info: remote resource transition completed.
heartbeat: [19973]: info: all clients are now resumed
ipfail: [20000]: info: Asking other side for ping node count.
ipfail: [20000]: info: No giveup timer to abort.

當然在這中間還處理了 haresources 裡的動作,在這裡只擷取部分狀態的判定 log

架設技巧

如果你的 DRBD 同步線路為獨立網卡,若是不想浪費資源可以直接設定為網卡最大傳輸速率,在 Linux 可以這樣看網卡速率

$ dmesg |grep eth0

dmesg | grep eth0 | grep interface
bond0: Enslaving eth0 as a backup interface with a down link
bond0: link status definitely up for interface eth0, 1000 Mbps full duplex

Debug

Q:在啟動 heartbeat 服務時出現『Unable to find nic or netmask.』

Ans:這個訊息是 heartbeat 掛載 VIP 失敗,無法找到 netmask,如果沒設定 netmask 會預設抓你第一張網卡的 netmask,若是有誤就無法掛載上去,可以使用 ifconfig up 的方式測試是否可以成功掛上VIP。

參考資料:



Exit mobile version