1. 程式人生 > 資料庫 >MySQL高可用方案——雙主

MySQL高可用方案——雙主

MySQL的高可用方案有很多種,雙主、MHA、MMM等等,這裡只是寫下最簡單的雙主這種高可用方案。

一、配置MySQL互為主從

1.1 環境準備

OS IP hostname service
Centos 7.5 192.168.1.1 db01 MySQL+Keepalived
Centos 7.5 192.168.1.2 db02 MySQL+Keepalived

本篇博文就不再部署MySQL服務了,如果沒有MySQL的環境可以參考博文

1.2 開啟二進位制日誌及中繼日誌

[root@db01 ~]# vim /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port=3306
server_id=1
socket=/usr/local/mysql/mysql.sock
log-error=/usr/local/mysql/data/mysqld.err
pid-file=/usr/local/mysql/data/mysqld.pid
binlog_format = mixed     #指定二進位制格式
log-bin=/usr/local/mysql/data/log_bin            #指定二進位制日誌檔案
relay-log=/usr/local/mysql/data/relay-bin        #指定中繼日誌
relay-log-index=relay-bin.index
auto_increment_increment=2
auto_increment_offset=1
[root@db01 ~]# systemctl restart mysqld


[root@db02 ~]# vim /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
port=3306
server_id=2
socket=/usr/local/mysql/mysql.sock
log-error=/usr/local/mysql/data/mysqld.err
pid-file=/usr/local/mysql/data/mysqld.pid
binlog_format = mixed
log-bin=/usr/local/mysql/data/log_bin
relay-log=/usr/local/mysql/data/relay-bin
relay-log-index=relay-bin.index
auto_increment_increment=2
auto_increment_offset=2
[root@db02 ~]# systemctl restart mysqld

注意:mysql01和mysql02只有server-id和auto_increment_offset不同!

mysql中有自增長欄位,在做資料庫的主主同步時需要設定自增長的兩個相關配置:auto_increment_offset和auto_increment_increment。

  • auto-increment-increment表示自增長欄位每次遞增的量,其預設值是1。它的值應設為整個結構中伺服器的總數,我這裡用到兩臺伺服器,所以值設為2;
  • auto-increment-offset是用來設定資料庫中自動增長的起點(即初始值),因為這兩臺伺服器都設定了一次自動增長值2,所以它們的起點必須得不同,這樣才能避免兩臺伺服器資料同步時出現主鍵衝突;

關於“binlog_format = mixed”配置項,是用來定義二進位制日誌的格式的,有以下三個值可選,如下:

  • STATEMENT:基於sql語句來記錄二進位制日誌,比如有些sql語句可能會影響上百條資料的改動,那麼也只是記錄一條sql語句。優點:可以減少二進位制日誌的大小,減少日誌寫入的I/O量。缺點:需要進行資料恢復時,某些自定義的儲存過程或函式可能會失效,資料可能無法恢復;
  • ROW:基於行來記錄二進位制日誌,如果某一條SQL語句影響了多行資料,那麼將會記錄多條二進位制日誌,優點:可以通過二進位制日誌來精準的恢復資料。缺點:當發生變化的資料量較大時,會給磁碟I/O帶來一定的壓力;
  • mixed:基於混合模式來記錄二進位制日誌。MySQL自行判斷是基於行還是基於sql語句來記錄日誌,建議採用這種格式,如果基於sql語句來記錄就可以精準記錄資料的變化,那麼就會基於sql語句,如果sql語句中包含儲存過程或環境變數等,那麼就會基於行來記錄;

關於二進位制日誌的更多介紹,建議參考

注意:可以在my.cnf檔案中新增“binlog_do_db=資料庫名”配置項(可以新增多個)來指定要同步的資料庫!

1.3 將db01設定為db02的主伺服器

① 防火牆放行3306埠的流量(兩臺主機都需要放行3306埠,如果防火牆沒有開啟,則可忽略)
[root@db01 ~]# firewall-cmd --add-port=3306/tcp --permanent
[root@db01 ~]# firewall-cmd --reload
② db01上建立授權使用者
[root@db01 ~]# mysql -uroot -p123
mysql> grant replication slave on *.* to test@'192.168.1.%' identified by '123';
③ 檢視db01的當前binlog狀態資訊
mysql> show master status \G        #檢視該伺服器的binlog資訊
*************************** 1. row ***************************
             File: log_bin.000001        #該值一會會用到
         Position: 452             #該值一會會用到
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
④ 在db02上指定db01為master,並開啟slave功能
[root@db02 ~]# mysql -uroot -p123
mysql> change master to master_host='192.168.1.1',
    -> master_user='test',
    -> master_password='123',
    -> master_log_file='log_bin.000001',    #該值需與master上的值一致
    -> master_log_pos=452;        #同上
mysql> start slave;           #開啟slave功能
mysql> show slave status \G       #檢視slave狀態
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.1
                  Master_User: test
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: log_bin.000001
          Read_Master_Log_Pos: 452
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 318
        Relay_Master_Log_File: log_bin.000001
             Slave_IO_Running: Yes       #保證該執行緒是YES狀態
            Slave_SQL_Running: Yes       #同上

只要上面兩個值為yes,則表示主從沒有問題:

  • IO執行緒是去master上面讀取二進位制日誌到本地的中繼日誌中;
  • SQL執行緒是將本地的中繼日誌中的內容轉換為sql語句並執行;

1.4 將db02設定為db01的主伺服器

① db02建立授權使用者
[root@db02 ~]# mysql -uroot -p123
mysql> grant replication slave on *.* to test01@'192.168.1.%' identified by '123';
#授權的使用者可以和db01伺服器上的一致,也可以不一致
mysql> flush privileges;     #重新整理許可權
② 檢視db02的當前binlog狀態資訊
[root@db02 ~]# mysql -uroot -p123
mysql> show master status \G  #檢視該伺服器的binlog資訊,獲取File和 Position對應的值
*************************** 1. row ***************************
             File: log_bin.000001
         Position: 611
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
③ 在db01上指定db02為master,並開啟slave功能
[root@db01 ~]# mysql -uroot -p123
mysql> change master to master_host='192.168.1.2',
    -> master_user='test01',
    -> master_password='123',
    -> master_log_file='log_bin.000001',
    -> master_log_pos=611;
mysql> start slave;          #啟動slave
mysql> show slave status \G     #檢視slave狀態
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.2
                  Master_User: test01
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: log_bin.000001
          Read_Master_Log_Pos: 611
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 318
        Relay_Master_Log_File: log_bin.000001
             Slave_IO_Running: Yes       #保證該執行緒是YES狀態
            Slave_SQL_Running: Yes       #同上

1.5 測試同步

① db01建立測試資料
[root@db01 ~]# mysql -uroot -p123
mysql> create database test;
mysql> use test
mysql> create table t1(id int,name varchar(4));
mysql> insert into t1 values(1,'a'),(2,'b');
mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
+------+------+
② 確認db02已經同步資料並插入新的資料
[root@db02 ~]# mysql -uroot -p123
mysql> use test
mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
+------+------+
mysql> insert into t1 values(3,'c'),(4,'d');
mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    4 | d    |
+------+------+
③ 確認db01已經同步資料
[root@db01 ~]# mysql -uroot -p123
mysql> use test
mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    4 | d    |
+------+------+

至此,現在任何一臺MySQL上更新資料都會同步到另一臺MySQL,MySQL同步完成!

注意:若主MySQL伺服器已經存在,只是後期業務拓展才搭建從伺服器,在配置資料庫同步前應先將MySQL伺服器的要同步的資料庫拷貝到從伺服器上(如先在主MySQL上備份資料庫,再用備份再從MySQL伺服器上恢復)。

二、配置keepalived高可用

2.1 安裝Keepalived

[root@db01 ~]# yum -y install keepalived
[root@db02 ~]# yum -y install keepalived

2.2 配置防火牆放行相關流量

注意:兩臺主機都需要執行以下命令,以便放行相關流量。192.168.1.100是keepalived的組播地址,使用的是vrrp協議。

[root@db01 ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0 --in-interface ens33 --destination 192.168.1.100 --protocol vrrp -j ACCEPT
[root@db01 ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface ens33 --destination 192.168.1.100 --protocol vrrp -j ACCEPT
[root@db01 ~]# firewall-cmd --reload

2.3 修改主機db01的Keepalived配置檔案

[root@db01 ~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id db01       #route_id必須唯一
}

vrrp_instance VI_1 {
    state BACKUP   #指定角色為backup,兩臺MySQL伺服器的角色均為backup,設定backup將根據優先順序決定主從
    interface ens33    #指定承載虛擬IP的網絡卡
    virtual_router_id 51    #指定組,同一個叢集內的值必須一致。並且不可和區域網中的其他組衝突
    priority 100        #優先順序範圍為:0~100
    advert_int 1        #發vrrp包的時間間隔,即多久進行一次master選舉(可認為是健康檢查時間間隔)
    nopreempt      #不搶佔,即允許一個priority比較低的節點作為master
    authentication {             #認證區域
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {            #VIP區域,指定vip地址
        192.168.1.100
    }
}

virtual_server 192.168.1.100 3306 {     #設定虛擬伺服器,需要指定虛擬IP地址和服務埠,IP與埠之間用空格隔開
    delay_loop 2        #設定執行情況檢查時間,單位是秒
    lb_algo rr          #設定後端排程演算法
    lb_kind DR          #設定lvs實現負載均衡的機制,有NAT、TUN、DR三個模式,DR模式效率最高
    persistence_timeout 60       #會話保持時間,單位是秒
    protocol TCP        #指定轉發協議型別,有TCP和UDP兩種


    real_server 192.168.1.1 3306 {      #配置服務節點,這裡指定的也就是本機的真實IP
        weight 1         #設定權重
    notify_down /etc/keepalived/bin/mysql.sh      #檢測到real_server的MySQL服務宕機後執行的指令碼
    TCP_CHECK {
        connect_port 3306    #健康檢查埠
        connect_timeout 3     #連線超時時間
        retry 3         #重試次數
        delay_before_retry 3      #重連間隔時間
     }
   }
}
[root@db01 ~]# mkdir /etc/keepalived/bin
[root@db01 ~]# vim /etc/keepalived/bin/mysql.sh
#!/bin/bash
pkill keepalived    #停止keepalived服務
[root@db01 ~]# chmod +x /etc/keepalived/bin/mysql.sh
#建立需要的指令碼並賦予許可權
[root@db01 ~]# systemctl start keepalived
[root@db01 ~]# ip a show ens33    
#必須使用ip a命令才可以檢視到,ifconfig命令檢視不到
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:66:72:13 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.1/24 brd 192.168.1.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 192.168.1.100/32 scope global ens33    #可以看到指定的VIP已經繫結到ens33上
       valid_lft forever preferred_lft forever
    inet6 fe80::9f3:b94e:5f5d:8070/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

2.4 修改主機db02的Keepalived配置檔案

[root@db02 ~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   router_id db02       #更改router_id,此處在熱備組中必須要唯一
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 51
    priority 90       #更改優先順序
    advert_int 1
    nopreempt
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100
    }
}

virtual_server 192.168.1.100 3306 {
    delay_loop 2
    lb_algo rr
    lb_kind DR
    persistence_timeout 60
    protocol TCP

    real_server 192.168.1.2 3306 {    #更改為本機的IP地址及監聽埠
        weight 1
    notify_down /etc/keepalived/bin/mysql.sh
    TCP_CHECK {
        connect_port 3306
        connect_timeout 3
        retry 3
        delay_before_retry 3
     }
   }
}
[root@db02 ~]# mkdir /etc/keepalived/bin
[root@db02 ~]# vim /etc/keepalived/bin/mysql.sh
#!/bin/bash
pkill keepalived
[root@db02 ~]# chmod +x /etc/keepalived/bin/mysql.sh
#建立需要的指令碼並賦予許可權
[root@db02 ~]# systemctl start keepalived

至此,即可實現MySQL的雙主效果(只要VIP所在的節點,MySQL服務埠無法連線,那麼VIP將切換至另一臺節點,即使宕機的mysql伺服器恢復,也不會對VIP進行搶佔)。雖然有兩臺MySQL資料庫,但是其使用keepalived提供的虛擬IP地址來對外提供服務,不管這個虛擬Ip地址落在哪臺伺服器上,都可以保證資料的一致性,因為它們互為主從,並且keepalived的狀態都為backup,也設定了不搶佔(減少VIP的切換次數),這樣可以大大的避免keepalived的腦裂問題!