MySQL高可用之MGC--MariaDB Galera Cluster

lhrbest發表於2020-02-20

MySQL高可用之MGC--MariaDB Galera Cluster


MariaDB Galera Cluster 介紹

https://cloud.tencent.com/developer/article/1120419


MariaDB 叢集是 MariaDB 同步多主機叢集。它僅支援 XtraDB/ InnoDB 儲存引擎(雖然有對 MyISAM 實驗支援 - 看 wsrep_replicate_myisam 系統變數)。

主要功能:

  • 同步複製
  • 真正的 multi-master,即所有節點可以同時讀寫資料庫
  • 自動的節點成員控制,失效節點自動被清除
  • 新節點加入資料自動複製
  • 真正的並行複製,行級
  • 使用者可以直接連線叢集,使用感受上與MySQL完全一致

優勢:

  • 因為是多主,所以不存在Slavelag(延遲)
  • 不存在丟失事務的情況
  • 同時具有讀和寫的擴充套件能力
  • 更小的客戶端延遲
  • 節點間資料是同步的,而 Master/Slave 模式是非同步的,不同 slave 上的 binlog 可能是不同的

技術:

Galera 叢集的複製功能基於 Galeralibrary 實現,為了讓 MySQL 與 Galera library 通訊,特別針對 MySQL 開發了 wsrep API。

Galera 外掛保證叢集同步資料,保持資料的一致性,靠的就是可認證的複製,工作原理如下圖:

mariadb_galera_cluster

當客戶端發出一個 commit 的指令,在事務被提交之前,所有對資料庫的更改都會被 write-set收集起來,並且將  write-set 紀錄的內容傳送給其他節點。

write-set 將在每個節點進行認證測試,測試結果決定著節點是否應用 write-set更改資料。

如果認證測試失敗,節點將丟棄 write-set ;如果認證測試成功,則事務提交。



MariaDB Galera Cluster搭建

我這裡實驗時使用的作業系統是CentOS7,使用了3臺虛擬機器,IP分別為 10.211.55.610.211.55.710.211.55.8

關閉防火牆及selinux

為了先把MariaDB Galera Cluster部署起來,不受防火牆、selinux的干擾,先把3臺虛擬機器上這倆關閉了。如果防火牆一定要開啟,可參考 這裡設定防火牆規則。

systemctl disable firewalld.service
systemctl stop firewalld.service
setenforce 0sed -i 's/^SELINUX=.*$/SELINUX=disabled/'  /etc/selinux/config

新增mariadb的yum源

在3臺虛擬機器上執行以下命令

# 已使用國內yum映象,原映象地址是http://yum.mariadb.org
echo '[mariadb]name = MariaDB
baseurl = http://mirrors.ustc.edu.cn/mariadb/yum/10.1/centos7-amd64
gpgkey=http://mirrors.ustc.edu.cn/mariadb/yum/RPM-GPG-KEY-MariaDB
gpgcheck=1' > /etc/yum.repos.d/MariaDB.repo

安裝軟體包

在3臺虛擬機器上執行以下命令

1

yum install -y mariadb mariadb-server mariadb-common galera rsync

資料庫初始化

10.211.55.6上執行以下命令

systemctl start mariadb
mysql_secure_installation # 注意這一步是有互動的,需要回答一些問題,做一些設定
systemctl stop mariadb

修改galera相關配置

在3臺虛擬機器上均開啟 /etc/my.cnf.d/server.cnf進行編輯,修改片斷如下:

...[galera]wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_name=galera_cluster
wsrep_cluster_address="gcomm://10.211.55.6,10.211.55.7,10.211.55.8"wsrep_node_name=10.211.55.6   # 注意這裡改成本機IP
wsrep_node_address=10.211.55.6   # 注意這裡改成本機IP
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2...

啟動MariaDB Galera Cluster服務

先在第1臺虛擬機器執行以下命令:

sudo -u mysql /usr/sbin/mysqld --wsrep-new-cluster &> /tmp/wsrep_new_cluster.log &disown $!tail -f /tmp/wsrep_new_cluster.log

出現 ready for connections ,證明啟動成功,繼續在另外兩個虛擬機器裡執行命令:

1

systemctl start mariadb

等後面兩個虛擬機器裡mariadb服務啟動後,再到第1臺虛擬機器裡執行以下命令:

(ps -ef|grep mysqld|grep -v grep|awk '{print $2}'|xargs kill -9) &>/dev/nullsystemctl start mariadb

驗證MariaDB Galera Cluster服務

在任意虛擬機器裡執行以下命令:

mysql -e "show status like 'wsrep_cluster_size'"  # 這裡應該顯示叢集裡有3個節點
mysql -e "show status like 'wsrep_connected'"     # 這裡應該顯示ON
mysql -e "show status like 'wsrep_incoming_addresses'" # 這裡應該顯示10.211.55.7:3306,10.211.55.8:3306,10.211.55.6:3306mysql -e "show status like 'wsrep_local_state_comment'" # 這裡節點的同步狀態

檢視叢集全部相關狀態引數可執行以下命令:

1

mysql -e "show status like 'wsrep_%'"

至此,MariaDB Galera Cluster已經成功部署。

MariaDB Galera Cluster的自啟動

在實際使用中發現一個問題,Galera叢集啟動時必須按照一個特定的規則啟動,研究了下,發現規則如下:

  • 如果叢集從來沒有啟動過(3個節點上都沒有 /var/lib/mysql/grastate.dat檔案),則必要由其中一個節點以 --wsrep-new-cluster引數啟動,另外兩個節點正常啟動即可
  • 如果叢集以前啟動過,則參考 /var/lib/mysql/grastate.dat,找到 safe_to_bootstrap1的節點,在該節點上以 --wsrep-new-cluster引數啟動,另外兩個節點正常啟動即可
  • 如果叢集以前啟動過,但參考 /var/lib/mysql/grastate.dat,找不到 safe_to_bootstrap1的節點(一般是因為mariadb服務非正常停止造成),則在3個節點中隨便找1個節點,將 /var/lib/mysql/grastate.dat中的 safe_to_bootstrap修改為1,再在該節點上以 --wsrep-new-cluster引數啟動,另外兩個節點正常啟動即可

從以上3種場景可知,正常情況下很難保證mariadb galera cluster可以無人值守地完成開機自啟動。國外論壇上也有人反映了 這個問題,但好像官方的人員好像說設計上就是這樣,怎麼可以這樣。。。

最後寫了個指令碼,放在3個虛擬機器上面,解決了這個問題。指令碼如下:

cat /usr/local/bin/mariadb_cluster_helper.sh
#!/bin/bash
GRASTATE_FILE=/var/lib/mysql/grastate.dat
WSREP_NEW_CLUSTER_LOG_FILE=/tmp/wsrep_new_cluster.log
# 如果啟動mariadb超過10秒還沒返回0,則認為失敗了
START_MARIADB_TIMEOUT=10# 以--wsrep-new-cluster引數啟動,超過5次檢查,發現仍沒有其它節點加入叢集,則認為此路不通
SPECIAL_START_WAIT_MAX_COUNT=5# 得到本機IP
MY_IP=$(grep 'wsrep_node_address' /etc/my.cnf.d/server.cnf | awk -F '=' '{print $2}')# 殺掉mysqld程式function kill_mysqld_process() {
    (ps -ef|grep mysqld|grep -v grep|awk '{print $2}'|xargs kill -9) &>/dev/null}# 正常啟動mariadbfunction start_mariadb_normal(){
    # 首先確保safe_to_bootstrap標記為0
    sed -i 's/^safe_to_bootstrap.*$/safe_to_bootstrap: 0/' $GRASTATE_FILE
    timeout $START_MARIADB_TIMEOUT systemctl start mariadb &> /dev/null
    return $?}# 以--wsrep-new-cluster引數啟動mariadbfunction start_mariadb_special(){
    # 首先確保safe_to_bootstrap標記為1
    sed -i 's/^safe_to_bootstrap.*$/safe_to_bootstrap: 1/' $GRASTATE_FILE
    # 以--wsrep-new-cluster引數啟動mariadb    /usr/sbin/mysqld --user=mysql --wsrep-new-cluster &> $WSREP_NEW_CLUSTER_LOG_FILE &
    disown $!
    try_count=0
    # 迴圈檢查    while [ 1 ]; do
        # 如果超過SPECIAL_START_WAIT_MAX_COUNT次檢查,仍沒有其它節點加入叢集,則認為此路不通,嘗試正常啟動,跳出迴圈        if [ $try_count -gt $SPECIAL_START_WAIT_MAX_COUNT ] ; then
            kill_mysqld_process
            start_mariadb_normal            return $?
        fi
        new_joined_count=$(grep 'synced with group' /tmp/wsrep_new_cluster.log | grep -v $MY_IP|wc -l)
        exception_count=$(grep 'exception from gcomm, backend must be restarted' $WSREP_NEW_CLUSTER_LOG_FILE | wc -l)
        # 如果新加入的節點數大於0,則認為叢集就緒了,可正常啟動了,跳出迴圈
        # 如果執行日誌中發現了異常(兩個節點都以--wsrep-new-cluster引數啟動,其中一個會報錯),則認為此路不通,嘗試正常啟動,跳出迴圈        if [ $new_joined_count -gt 0 ] || [ $exception_count -gt 0 ] ; then
            kill_mysqld_process
            start_mariadb_normal            return $?
        else
            try_count=$(( $try_count + 1 ))
        fi
        sleep 5
    done}# 首先殺掉mysqld程式
kill_mysqld_process
ret=-1# 如果safe_to_bootstrap標記為1,則立即以--wsrep-new-cluster引數啟動if [ -f $GRASTATE_FILE ]; then
    safe_bootstrap_flag=$(grep 'safe_to_bootstrap' $GRASTATE_FILE | awk -F ': ' '{print $2}')
    if [ $safe_bootstrap_flag -eq 1 ] ; then
        start_mariadb_special
        ret=$?
    else
        start_mariadb_normal
        ret=$?
    fielse
    start_mariadb_normal
    ret=$?fi
# 隨機地按某種方式啟動,直到以某種方式正常啟動以止;否則殺掉mysqld程式,隨機休息一會兒,重試while [ $ret -ne 0 ]; do
    kill_mysqld_process
    sleep_time=$(( $RANDOM % 10 ))
    sleep $sleep_time
    choice=$(( $RANDOM % 2 ))
    ret=-1
    if [ $choice -eq 0 ] ; then
        start_mariadb_special
        ret=$?
    else
        start_mariadb_normal
        ret=$?
    fi
done
# 使上述指令碼開機自啟動
chmod +x /usr/local/bin/mariadb_cluster_helper.sh
chmod +x /etc/rc.d/rc.local
echo '/usr/local/bin/mariadb_cluster_helper.sh &> /var/log/mariadb_cluster_helper.log &' >> /etc/rc.d/rc.local

然後3個節點終於可以開機自啟動自動組成叢集了。

搭配keepalived+haproxy+clustercheck

為了保證mariadb galera叢集的高可用,可以使用haproxy進行請求 負載均衡,同時為了實現haproxy的高可用,可使用keepalived實現haproxy的熱備方案。keepalived實現haproxy的熱備方案可參見之前的 博文。這裡重點說一下haproxy對mariadb galera叢集的請求負載均衡。

這裡使用了 https://github.com/olafz/percona-clustercheck 所述方案,使用外部指令碼在應用層檢查galera節點的狀態。

首先在mariadb裡進行授權:

1

GRANT PROCESS ON *.* TO 'clustercheckuser'@'%' IDENTIFIED BY 'clustercheckpassword!'

下載檢測指令碼:

wget -O /usr/bin/clustercheck https://raw.githubusercontent.com/olafz/percona-clustercheck/master/clustercheck
chmod +x /usr/bin/clustercheck

準備檢測指令碼用到的配置檔案:

MYSQL_USERNAME="clustercheckuser"MYSQL_PASSWORD="clustercheckpassword!"MYSQL_HOST="$db_ip"MYSQL_PORT="3306"AVAILABLE_WHEN_DONOR=0

測試一下監控指令碼:

# /usr/bin/clustercheck > /dev/null# echo $?0 # synced1 # un-synced

使用xinetd暴露http介面,用於檢測galera節點同步狀態:

cat > /etc/xinetd.d/mysqlchk << EOF
# default: on
# description: mysqlchk
service mysqlchk{
        disable = no
        flags = REUSE
        socket_type = stream
        port = 9200
        wait = no
        user = nobody
        server = /usr/bin/clustercheck
        log_on_failure += USERID
        only_from = 0.0.0.0/0
        per_source = UNLIMITED}EOF
service xinetd restart

測試一下暴露出的http介面:

curl http://127.0.0.1:9200Galera cluster node is synced. # synced
Galera cluster node is not synced # un-synced

最後在 /etc/haproxy/haproxy.cfg裡配置負載均衡:

...frontend vip-mysql
    bind $vip:3306
    timeout client 900m
    log global
    option tcplog
    mode tcp
    default_backend vms-mysql
backend vms-mysql
    option httpchk
    stick-table type ip size 1000
    stick on dst
    balance leastconn
    timeout server 900m
    server mysql1 $db1_ip:3306 check inter 1s port 9200 backup on-marked-down shutdown-sessions maxconn 60000
    server mysql2 $db2_ip:3306 check inter 1s port 9200 backup on-marked-down shutdown-sessions maxconn 60000
    server mysql2 $db3_ip:3306 check inter 1s port 9200 backup on-marked-down shutdown-sessions maxconn 60000...

搭配galera仲裁服務

官方也提到gelera叢集最少要三節點部署,但每增加一個節點,要付出相應的資源,因此也可以最少兩節點部署,再加上一個galera仲裁服務。

The recommended deployment of Galera Cluster is that you use a minimum of three instances. Three nodes, three datacenters and so on. In the event that the expense of adding resources, such as a third datacenter, is too costly, you can use Galera Arbitrator. Galera Arbitrator is a member of the cluster that participates in voting, but not in the actual replication

這種部署模式有兩個好處:

  1. 使叢集剛好是奇數節點,不易產生腦裂。
  2. 可能通過它得到一個一致的資料庫狀態快照,可以用來備份。

這種部署模式的架構圖如下:

MySQL高可用之MGC--MariaDB Galera Cluster

mage-20180401214224

部署方法也比較簡單:

# 假設已經構建了一個兩節點的galera叢集,在第3個節點部署garbd服務
echo '
GALERA_NODES="10.211.55.6:4567 10.211.55.7:4567" # 這裡是兩節點的地址
GALERA_GROUP="galera_cluster"  # 這裡的group名稱保持與兩節點的wsrep_cluster_name屬性一致
LOG_FILE="/var/log/garb.log"' > /etc/sysconfig/garb
systemctl start garb # 啟動garbd服務

測試一下效果。

首先看一下兩節點部署產生腦裂的場景。

# 首先在第3個節點停止garb服務
systemctl stop garb
# 然後在第2個節點drop掉去住第1個節點和仲裁節點的資料包
iptables -A OUTPUT -d 10.211.55.6 -j DROP
iptables -A OUTPUT -d 10.211.55.9 -j DROP
# 這時檢查前兩個節點的同步狀態,發生腦裂了,都不是同步狀態了
mysql -e "show status like 'wsrep_local_state_comment'"+---------------------------+-------------+| Variable_name             | Value       |+---------------------------+-------------+| wsrep_local_state_comment | Initialized |+---------------------------+-------------+

再試驗下有仲裁節點參與的場景。

# 首先在第3個節點啟動garb服務
systemctl start garb
# 在前兩個節點檢視叢集節點數,發現是3個,說明包括了仲裁節點
mysql -e "show status like 'wsrep_cluster_size'"+---------------------------+-------------+| Variable_name             | Value       |+---------------------------+-------------+| wsrep_cluster_size        | 3           |+---------------------------+-------------+# 然後在第2個節點drop掉去住第1個節點和仲裁節點的資料包
iptables -A OUTPUT -d 10.211.55.6 -j DROP
iptables -A OUTPUT -d 10.211.55.9 -j DROP
# 這時檢查第1個節點的同步狀態,仍然是同步狀態
mysql -e "show status like 'wsrep_local_state_comment'"+---------------------------+-------------+| Variable_name             | Value       |+---------------------------+-------------+| wsrep_local_state_comment | Synced      |+---------------------------+-------------+# 再在第1個節點檢視叢集節點數,發現是2個
mysql -e "show status like 'wsrep_cluster_size'"+---------------------------+-------------+| Variable_name             | Value       |+---------------------------+-------------+| wsrep_cluster_size        | 2           |+---------------------------+-------------+# 這時檢查第2個節點的同步狀態,發現是未同步的
mysql -e "show status like 'wsrep_local_state_comment'"+---------------------------+-------------+| Variable_name             | Value       |+---------------------------+-------------+| wsrep_local_state_comment | Initialized |+---------------------------+-------------+

以前試驗說明採用了仲裁節點後,因為叢集節點數變為了奇數,有效地避免了腦裂,同時將真正有故障的節點隔離出去了。

參考

  1. https://segmentfault.com/a/1190000002955693
  2. https://github.com/olafz/percona-clustercheck
  3. http://galeracluster.com/documentation-webpages/arbitrator.html




About Me

........................................................................................................................

● 本文作者:小麥苗,部分內容整理自網路,若有侵權請聯絡小麥苗刪除

● 本文在itpub、部落格園、CSDN和個人微 信公眾號( xiaomaimiaolhr)上有同步更新

● 本文itpub地址: http://blog.itpub.net/26736162

● 本文部落格園地址: http://www.cnblogs.com/lhrbest

● 本文CSDN地址: https://blog.csdn.net/lihuarongaini

● 本文pdf版、個人簡介及小麥苗雲盤地址: http://blog.itpub.net/26736162/viewspace-1624453/

● 資料庫筆試面試題庫及解答: http://blog.itpub.net/26736162/viewspace-2134706/

● DBA寶典今日頭條號地址: http://www.toutiao.com/c/user/6401772890/#mid=1564638659405826

........................................................................................................................

● QQ群號: 230161599 、618766405

● 微 信群:可加我微 信,我拉大家進群,非誠勿擾

● 聯絡我請加QQ好友 646634621 ,註明新增緣由

● 於 2020-02-01 06:00 ~ 2020-02-31 24:00 在西安完成

● 最新修改時間:2020-02-01 06:00 ~ 2020-02-31 24:00

● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

........................................................................................................................

小麥苗的微店https://weidian.com/s/793741433?wfr=c&ifr=shopdetail

小麥苗出版的資料庫類叢書http://blog.itpub.net/26736162/viewspace-2142121/

小麥苗OCP、OCM、高可用網路班http://blog.itpub.net/26736162/viewspace-2148098/

小麥苗騰訊課堂主頁https://lhr.ke.qq.com/

........................................................................................................................

使用 微 信客戶端掃描下面的二維碼來關注小麥苗的微 信公眾號( xiaomaimiaolhr)及QQ群(DBA寶典)、新增小麥苗微 信, 學習最實用的資料庫技術。

........................................................................................................................

歡迎與我聯絡

 

 



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2676352/,如需轉載,請註明出處,否則將追究法律責任。

相關文章