【CentOS 6.2】DRBD 建立 MySQL server HA 架構

參考資料 ----
http://www.mysql.com/why-mysql/white-papers/mysql-high-availability-drbd-configuration-deployment-guide/
http://www.mysql.com/why-mysql/white-papers/#en-22-16
http://www.mysql.com/why-mysql/white-papers/#zh-22-16
http://clusterlabs.org/quickstart-redhat.html
http://download.opensuse.org/repositories/network:/ha-clustering/CentOS_CentOS-6/
http://savannah.nongnu.org/projects/crmsh/

ORACLE 提出了幾個 MySQL HA 建置方案供做參考,如下表:


DRBD 的簡要介紹可參考 維基百科

規劃:
作業系統 CentOS 6.2(基於公司版本統一起見,不過這讓老灰鴨吃足苦頭,CentOS6.4 之後的版本可能會比較好架......)
兩台主機的名稱分別為
host1(10.71.0.207)
host2(10.71.0.208)
對外 IP10.71.0.209
gateway:10.71.0.254
子網路遮罩:255.255.255.0
預定 MySQL 資料存放位置 -- /var/lib/mysql_drbd/

STEP 1.
安裝 2CentOS 6.2 的主機,
1.1 確認兩台主機的網卡名稱一致,在本例中為 eth0
1.2 要存放 MySQL 資料的磁區要先預留,空下來,不做磁區分割。


為了之後的設定檔統一,所以將 LVM 儲區群組改名為一樣,並且留下 1G 的未分割空間,將來放 MySQL 的資料用,這個未分割空間要留在 sda 也行,不過個人認為 LVM 對磁區的調整較彈性。

安裝選項的自訂項目勾選 "高可用性",並全選右方的自訂項目




為了確保兩台主機的設定都是一樣的,建議在 host1 編寫設定檔,寫好之後,再以 scp 指令透過網路複製到 host2,這樣查問題會比較好查。



STEP 2.
[兩台主機]暫時關閉防火牆,因為本文是以架設兩台全新主機,讓環境最單純。


STEP 3.
停止並取消 NetworkManager 服務(注意大小寫)

[兩台主機]service  NetworkManager  stop
[兩台主機]chkconfig  NetworkManager  off



STEP 4.
變更 SELINUX 的設定為 disabled,理由是 ---- 我不熟 SELINUX...  :-P

[root@host1 ~]vi  /etc/selinux/config
將 SELINUX=enforcing 改為

SELINUX=disabled

存檔後,複製到 host2

[root@host1 ~]scp  /etc/selinux/config  host2:/etc/selinux/



STEP 5.
修改 host1/etc/hosts

[root@host1 ~]vi  /etc/hosts

內容如下:
127.0.0.1      localhost  localhost.localdomain
::1            localhost  localhost.localdomain
10.71.0.207    host1      host1.localdomain
10.71.0.208    host2      host2.localdomain

存檔後,複製到 host2

[root@host1 ~]scp  /etc/hosts  host2:/etc/

兩台主機皆重新啟動


STEP 6.
因為 CentOS6.x 沒有內建 DRBD 套件,現在的第三方套件也學習 RedHat 官方模式,提供 repository 給使用者,一併解決了相依性問題,而 pkgs.org 是一個提供第三方套件資訊的網站,到 pkgs.org 查詢得知 atrpms.net 有打包好的 DRBD 套件;目前 DRBD 最新版本為 DRBD-8.4.3

[兩台主機]cd  /tmp
[兩台主機]wget  http://dl.atrpms.net/el6-i386/atrpms/stable/atrpms-repo-6-6.el6.i686.rpm
安裝
[兩台主機]rpm  -Uvh  atrpms-repo*rpm
[兩台主機]yum  install  drbd



STEP 7.
建立 drbd 的磁區:

[兩台主機]lvcreate  -l  100%free  -n  /dev/vg_host/lv_drbd

下指令後,顯示結果

Logical  volume  "lv_drbd"  created

重開機,使磁區分割生效。

要檢視磁區,輸入

lvscan




STEP 8.
先在 host1 編寫 drbd 資源設定檔
更改 /etc/drbd.conf 檔名為 /etc/drbd.conf.bak

[root@host1 ~]mv  /etc/drbd.conf  /etc/drbd.conf.bak

複製 /etc/drbd.d/global_common.conf/etc/ 且檔名改為 /etc/drbd.conf

[root@host1 ~]cp  /etc/drbd.d/global_common.conf  /etc/drbd.conf

修改 /etc/drbd.conf 成下述內容:

global
{
    usage-count yes;
}

resource clusterdb_res 
{
    protocol C;
    handlers 
    {
        pri-on-incon-degr "/usr/lib/drbd/notify-pri-on-incon-degr.sh; /usr/lib/drbd/notify-emergency-
reboot.sh; echo b > /proc/sysrq-trigger; reboot -f";
        pri-lost-after-sb "/usr/lib/drbd/notify-pri-lost-after-sb.sh; /usr/lib/drbd/notify-emergency-
reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f";
        local-io-error "/usr/lib/drbd/notify-io-error.sh; /usr/lib/drbd/notify-emergency-shutdown.
sh; echo o > /proc/sysrq-trigger ; halt -f";
        fence-peer "/usr/lib/drbd/crm-fence-peer.sh";
    }

    startup
    {
        degr-wfc-timeout 120; # 2 minutes.
        outdated-wfc-timeout 2; # 2 seconds.
    }

    disk 
    {
        on-io-error detach;
    }

    net
    {
        cram-hmac-alg "sha1";
        shared-secret "clusterdb";
        after-sb-0pri disconnect;
        after-sb-1pri disconnect;
        after-sb-2pri disconnect;
        rr-conflict disconnect;
    }

    syncer
    {
        rate 10M;
        al-extents 257;
        on-no-data-accessible io-error;
    }

    on host1        # 注意這個名字要與下 uname –n 指令所得到的結果一致
    {
        device                  /dev/drbd0;
        disk                    /dev/vg_host/lv_drbd;
        address                 10.71.0.207:7788;
        flexible-meta-disk      internal;
    }

    on host2        # 注意這個名字要與下 uname –n 指令所得到的結果一致
    {
        device       /dev/drbd0;
        disk         /dev/vg_host/lv_drbd;
        address      10.71.0.208:7788;
        meta-disk    internal;
    }
}

再以 scp 透過網路 drbd.conf 複製到 host2

[root@host1  ~]scp /etc/drbd.conf    host2:/etc/

[兩台主機]drbdadm create-md clusterdb_res

啟動 DRBD 服務
[兩台主機]service drbd start

[任一台主機] service  drbd  status
會看到畫面如下:


指定 host1 為正式機
[root@host1  ~]drbdadm  --  --overwrite-data-of-peer  primary  all


若這時立馬下指令
[root@host1  ~]service  drbd  status
就會看到如下畫面:



表示 host1(正式機)、host2(備機) 正在同步中

格式化正式機
[root@host1  ~]mkfs -t ext4 /dev/drbd0




STEP 9.
安裝 MySQL
[兩台主機]yum  install  mysql-server  mysql


STEP 10.
變更目錄&目錄權限:
[兩台主機 ~]mkdir  /var/lib/mysql_drbd
[兩台主機 ~]chown  mysql  /var/lib/mysql_drbd
[兩台主機 ~]chgrp  mysql  /var/lib/mysql_drbd
[兩台主機 ~]chown  mysql  /var/lib/mysql
[兩台主機 ~]chgrp  mysql  /var/lib/mysql

STEP 11.
host1 mount /dev/drbd0,並建立 MySQL 設定檔
[root@host1 ~]mount /dev/drbd0 /var/lib/mysql_drbd
[root@host1 ~]mkdir /var/lib/mysql_drbd/data
[root@host1 ~]cp /usr/share/mysql/my-small.cnf /var/lib/mysql_drbd/my.cnf


修改 /var/lib/mysql_drbd/my.cnf
[mysqld] 這個區塊加入 datadir 位置,如下:
[mysqld]
datadir = /var/lib/mysql_drbd/data
socket  = /var/lib/mysql/mysql.sock
pid     = /var/lib/mysql/mysql.pid


STEP 12.
初始化 MySQL database
[root@host1 ~]mysql_install_db --no-defaults --datadir=/var/lib/mysql_drbd/data --user=mysql



初始化 MySQL database 後,千萬不要自行啟動 mysqld!!

[root@host1 ~]cd  /var/lib/mysql_drbd
[root@host1 ~]chmod  -R  uog+rw  *
[root@host1 ~]chown  mysql  my.cnf
[root@host1 ~]chmod  og-w  my.cnf
[root@host1 ~]chmod  644  my.cnf
[root@host1 ~]chown  -R  mysql  data

umount 磁區
[root@host1 ~]umount /var/lib/mysql_drbd

將正式機角色轉換回備機狀態
[root@host1 ~]drbdadm secondary clusterdb_res

在這個範例中,因為我們只有設定一個 DRBD 資源,也就是 clusterdb_res,所以上述的指令可以偷懶,如下:
[root@host1 ~]drbdadm secondary all


至此,MySQL 的部份設定完畢



STEP 13.
兩台主機 安裝/更新 pacemaker
檢查兩台主機是否已安裝 pacemaker,如果您跟我一樣在全新安裝 Linux 時就已勾選 "高可用性",那麼這幾個套件應都已經裝了。
如果您也是採用 CentOS6.2 且已經安裝了上述套件,就只需要將 pacemaker 更新即可。

[兩台主機]yum update pacemaker 




STEP 14.
CentOS 6.2 時,crm 這個套件是內含在 pacemaker 內的,之後就成為獨立套件 -- crmsh
STEP 13 我們更新了 pacemaker(一定要更新),因此我們需要再另外下載安裝 crmsh。(如果您是 CentOS6.4,您也需要安裝 crmsh)

[兩台主機]wget  -P  /etc/yum.repos.d/  http://download.opensuse.org/repositories/network:/ha-clustering/CentOS_CentOS-6/network:ha-clustering.repo

[兩台主機]yum install crmsh


STEP 15.
複製並修改 corosync 的設定檔

[root@host1 ~]cp  /etc/corosync/corosync.conf.example  /etc/corosync/corosync.conf
[root@host1 ~]vi  /etc/corosync/corosync.conf

修改為如下內容:

totem
{
    version: 2
    secauth: off
    threads: 0
    interface
    {
        ringnumber: 0
        bindnetaddr: 10.71.0.0    # 注意前 3 個數字與 ip 同網段,第 4 個數字為 0
        mcastaddr: 226.99.1.1
        mcastport: 5405
        ttl: 1
    }
}
......
......

建立 pcmk

vi  /etc/corosync/service.d/pcmk

內容如下:

service
{
    #Load the Pacemaker Cluster Resource Manager
    name: pacemaker
    ver: 1
}


以指令方式建立 /etc/cluster/cluster.conf

[root@host1 ~]ccs -f /etc/cluster/cluster.conf --createcluster pacemaker1

[root@host1 ~]ccs -f /etc/cluster/cluster.conf --addnode host1
[root@host1 ~]ccs -f /etc/cluster/cluster.conf --addnode host2

[root@host1 ~]ccs -f /etc/cluster/cluster.conf --addfencedev pcmk agent=fence_pcmk
[root@host1 ~]ccs -f /etc/cluster/cluster.conf --addmethod pcmk-redirect host1
[root@host1 ~]ccs -f /etc/cluster/cluster.conf --addmethod pcmk-redirect host2

[root@host1 ~]ccs -f /etc/cluster/cluster.conf --addfenceinst pcmk host1 pcmk-redirect port=host1
[root@host1 ~]ccs -f /etc/cluster/cluster.conf --addfenceinst pcmk host2 pcmk-redirect port=host2

生成的 cluster.conf 是一個 xml

複製前述 3 個檔案至 host2
[root@host1 ~]scp  /etc/corosync/corosync.conf  host2:/etc/corosync/
[root@host1 ~]scp  /etc/corosync/service.d/pcmk  host2:/etc/corosync/service.d/
[root@host1 ~]scp  /etc/cluster/cluster.conf  host2:/etc/cluster/

啟動 pacemaker
[兩台主機]service pacemaker start

觀察執行結果,  -1 是數字
[兩台主機]crm_mon  -1



HA 把每項要監控、接管的服務/程式稱為 resource,所以在上圖可以看到 2 Nodes configured(已設定 2 節點),0 Resources configured(因為我們還沒設定)。


STEP 16.
在本例中,我們要監控的有檔案系統,兩台主機對外共同的 IP、和 MySQL,接下來就開始設定

[root@host1 ~]crm  configure  property  no-quorum-policy=ignore
[root@host1 ~]crm  configure  rsc_defaults  resource-stickiness=100
[root@host1 ~]crm  configure  property stonith-enabled=false


停止 DRBD
[root@host1 ~]service drbd stop


建立 crm 設定

[root@host1 ~]crm  configure

這時會進入 crm 的編輯模式

crm(live)configure# primitive  p_drbd_mysql  ocf:linbit:drbd  params
drbd_resource="clusterdb_res"  op  monitor  interval="15s"

crm(live)configure# ms ms_drbd_mysql p_drbd_mysql meta master-max="1" master-node-max="1" clone-max="2" clone-node-max="1" notify="true"

crm(live)configure# primitive  p_fs_mysql  ocf:heartbeat:Filesystem  params  device="/dev/drbd0" directory="/var/lib/mysql_drbd"  fstype="ext4"

下面這道指令的 ip 是對外 ipnic 是網卡名稱
crm(live)configure# primitive p_ip_mysql ocf:heartbeat:IPaddr2 params ip="10.71.0.209" cidr_netmask="24" nic="eth0"

下面這道指令很關鍵,先另外開個終端機視窗,查出 mysqld 所在目錄,以我的主機為例,我的 mysqld/usr/libexec/mysqld,其餘如:config、datadir、pid、socket 等都在前面提過

crm(live)configure# primitive p_mysql ocf:heartbeat:mysql params binary="/usr/libexec/mysqld" config="/var/lib/mysql_drbd/my.cnf" datadir="/var/lib/mysql_drbd/data" pid="/var/lib/mysql/mysql.pid" socket="/var/lib/mysql/mysql.sock" user="mysql" group="mysql" additional_parameters="--bind-address=10.71.0.209 --user=mysql" op start timeout=120s op stop timeout=120s op monitor interval=20s timeout=30s

crm(live)configure# group  g_mysql  p_fs_mysql  p_ip_mysql  p_mysql

crm(live)configure# colocation  c_mysql_on_drbd  inf:  g_mysql  ms_drbd_mysql:Master

crm(live)configure# order  o_drbd_before_mysql  inf:  ms_drbd_mysql:promote  g_mysql:start

儲存設定
crm(live)configure# commit

離開
crm(live)configure# exit

所做的設定會立即生效,不需重新啟動 pacemaker 這個 service,結果如下:



如果您跑出來的結果和上圖不同,有可能是某些地方輸入錯誤,可透過下述指令檢視修正:

[root@host1 ~]crm  configure  edit


如果跑出來的結果如上圖,那再看一個:

[root@host1 ~]service drbd status

則會看到 pacemaker 啟動了剛剛在前面被我們停下來的 DRBD


因為在 crm configure 階段我們已改變了 mysqld 的啟動方式,所以不要以 service  mysqld  status 指令去檢查 mysqld 是否啟動成功,因為您會看到  mysqld 已停止 的回應。


題外話:
瞄一下 /usr/lib/ocf/resource.d/heartbeat/ 這個目錄,放著許多 server 套件的 script,我猜...這應該就是 pacemaker 目前支援的 service...


STEP 17.
建立驗證資料庫

[root@host1 ~]mysql  -u  root  -e  "GRANT ALL ON *.* to 'root'@'%' "
[root@host1 ~]mysql  -h  10.71.0.209  -P3306  -u  root

mysql> CREATE  DATABASE  clusterdb;  USE clusterdb;
顯示回應 Database changed
mysql> CREATE  TABLE  simples  (id  INT  NOT  NULL  PRIMARY  KEY);
mysql> INSERT  INTO  simples  VALUES  (1),(2),(3),(4);
mysql> exit


STEP 18.
建立網路斷線時的機制

[root@host1 ~]crm configure

crm(live)configure# primitive p_ping ocf:pacemaker:ping params name="ping" multiplier="1000" host_list="10.71.0.254" op monitor interval="15s" timeout="60s" start timeout="60s"

crm(live)configure# clone cl_ping p_ping meta interleave="true"

crm(live)configure# location l_drbd_master_on_ping ms_drbd_mysql rule $role="Master" -inf: not_defined ping or ping number:lte 0

crm(live)configure# commit

crm(live)configure# exit



STEP 19.
設定開機要啟動的 service

[兩台主機] chkconfig drbd off
[兩台主機] chkconfig mysqld off
[兩台主機] chkconfig pacemaker on


重新開機,從第 3 台主機來試撈資料(第 3 台主機需安裝 MySQL client)
[root@host3 ~]mysql  -h  10.71.0.209  -P3306  -u  root  -e  'SELECT * FROM clusterdb.simples;'

+----+
| id |
+----+
| 1  |
| 2  |
| 3  |
| 4  |
+----+



STEP 20.
指定 host1 當正式機
[root@host1 ~]crm  configure  edit
找到
location  cli-prefer-g_mysql  g_mysql  rule  $id="cli-prefer-rule-g_mysql"  inf:  #uname  eq  host1  and  #uname  eq  host2
確認先 host1 在前,host2 在後


STEP 21.
crm 設定複製到 host2
[root@host1 ~]crm  resource  migrate  g_mysql  host2
(這個動作只需在一開始建置,host2 還沒有設定時,做一次就好了,此後,只要 host1 一儲存設定後,host2 就會跟著更新了)

MySQL HA 環境建置完成!!



狀況模擬


試著拔除 host1 的網路線,大約 5 秒後 host2 就備援上來成為正式機了,不過您的公司若是 24hr 運作,則此 HA 方案可能不太適合,因為當 host1 修復後,有可能不能無痕銜接 -- 因為兩台主機內的資料差異度太大,造成所謂的 腦裂(split-brain)

host2 必需將資料備份出來
--> 下線暫停運作
--> 然後將自 host2 接手後的異動資料倒給 host1
--> 再回復 host1 為正式機,而 host2 為備機的關係。

接下來我想做的是:如果在出狀況時,備機接手成為正式機後,可以通知我,如此我才知道要去修復原本的正式機;可能還要繼續摸索如何結合 postfix 吧...


順道提一下可能會遇到的狀況與處置:


當主機狀態都是 StandAlone 時,嘗試連上線的指令

[root]# drbdadm  connect  clusterdb_res


當兩台主機都是 Secondary,要令某一台成為 Primary

[root]# drbdadm  primary  all

(其實 all 一字應鍵入 clusterdb_res,也就是設定的 resource 名稱,但因我們只有一個 resource,所以就偷懶...)


當兩台主機狀態都是 StandAlone 時,
或第 1 台是 StandAlone,第 2 台是 WFConnection 時,嘗試 connect 仍無法連上,
可能就發生了所謂的腦裂(split-brain),表示兩台主機的資料差異太大,要當 secondary 的主機就要捨棄自己的資料,重新向 Primary 索取


先讓 2 台主機都成 StandAlone 狀態

[root]# drbdadm  disconnect  clusterdb_res


然後令第 2 台連線,並捨棄自己的資料

[root]# drbdadm  secondary  clusterdb_res

[root]# drbdadm  connect  --discard-my-data  clusterdb_res

另一方面,也令第 1 台連線

[root]# drbdadm  connect  clusterdb_res


這時兩台主機就會開始重新將資料同步(就是將第 1 台的資料倒進第 2 台)

同步完,下

[root]# service drbd  status

就會看到第 1 台是 primary,而第 2 台是 Secondary