1. 程式人生 > 其它 >MySQL雙主和keepalived高可用的搭建

MySQL雙主和keepalived高可用的搭建

環境描述

MySQL主機名稱 MySQL主機IP MySQL版本 VIP 作業系統
master1 192.168.199.101 5.7.33 192.168.199.100 centos7
master2 192.168.199.102 5.7.33 192.168.199.100 centos7

MySQL安裝和初始化教程自行百度,以下操作都是在MySQL安裝後和初始化後才能操作。

開啟bin-log日誌

MySQL做主從或主主前需要開啟bin-log功能
# 停止MySQL
systemctl stop mysqld

# 編輯/etc/my.conf
[mysqld]
server_id=1             # 兩臺MySQL的server_id必須唯一,不能相同。
log-bin=mysql-bin       # 開啟bin-log日誌功能,就會在$datadir目錄下生成日誌檔案。

# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql  # 定義資料庫的儲存路徑,備份也可以將此目錄做備份。
socket=/var/lib/mysql/mysql.sock

# skip_grant_tables=1
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
max_allowed_packet  = 64M
max_connections = 500

資料庫備份和恢復

一般在搭建前就得規劃好使用的架構,所以大部分情況下做主從或雙主時,這兩臺資料庫都是空的就不需要做備份。
但是如果是做主從或雙主前,master1就已經單獨使用一段時間並且資料庫存在資料,這時又給了一臺新的master2配合master1做主從或雙主,此時就需要備份master1中的資料後再操作 !!!

備份詳細說明可以參考:https://www.cnblogs.com/chenbin93/p/14697451.html

備份master1
假如當前master1資料庫中存在資料,則備份master1(兩臺都沒有資料可跳過備份和恢復)

# 備份master1上所有資料庫並壓縮備份檔案
mysqldump -uroot -pYOUR_PASSWORD --all-databases | gzip > mysql_backup.sql.gz

# 備份執行完成後會在當前目錄生成mysql_backup.sql.gz檔案,將此檔案拷貝到master2上做還原操作。
cp mysql_backup.sql.gz root@master2:/data/
恢復到master2
將在master1上的備份資料恢復到master2上
# 在master2上解壓mysql_backup.sql.gz
gzip -d /data/mysql_backup.sql.gz

# 恢復
mysql -uroot -pYOUR_PASSWORD > /data/mysql_backup.sql

# 此時master2資料庫上有master1上的所有資料(備份時的資料)接下來就可以做主從或雙主。

建立專門用於同步的使用者

# master1
# 登入MySQL建立test1使用者
mysql> create user test1 identified by '123456';
# 授予replication和slave許可權
mysql> grant replication slave on *.* to 'test1'@'192.168.199.102' identified by '123456';
mysql> select user,host from mysql.user;
+---------------+-----------------+
| user          | host            |
+---------------+-----------------+
| test1         | 192.168.199.102 |
| mysql.session | localhost       |
| mysql.sys     | localhost       |
| root          | localhost       |
+---------------+-----------------+
4 rows in set (0.00 sec)

# master2
# 登入MySQL建立test2使用者
mysql> create user test2 identified by '123456';
# 授予replication和slave許可權
mysql> grant replication slave on *.* to 'test2'@'192.168.199.101' identified by '123456';
mysql> select user,host from mysql.user;
+---------------+-----------------+
| user          | host            |
+---------------+-----------------+
| test2         | 192.168.199.101 |
| mysql.session | localhost       |
| mysql.sys     | localhost       |
| root          | localhost       |
+---------------+-----------------+
4 rows in set (0.00 sec)

# 建立的使用者指定登入的主機是相互的,test1這個使用者只能在master2主機上登入,test2只能在master1主機上登入。
# 當然也可以是%允許在任何主機遠端登入。

檢視當前資料庫狀態

# 登入MySQL
# master1
# 檢視master狀態:
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000002 |  1713832 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
# slave狀態:
mysql> show slave status;
Empty set (0.00 sec)

# master2
# 檢視master狀態:
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000002 |   859788 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
# slave狀態:
mysql> show slave status;
Empty set (0.00 sec)

# 如果master的狀態為 Empty set (0.00 sec),則是當前的主機上面MySQL的bin-log功能沒有開啟,開啟後即可看到結果。

配置雙主

配置master2為master1的slave
# master2
# 先配置master2為master1的slave,執行前先檢視master1的master狀態,記下file和Position對應的值。
mysql> stop slave;
mysql> change master to
     master_host='192.168.199.101',
     master_user='test1',
     master_password='123456',
     master_log_file='mysql-bin.000002',    	# master1中的master狀態的file名稱
     master_log_pos=1713832;				   # master1中的master狀態的Position
Query OK, 0 rows affected, 2 warnings (0.12 sec)

# 啟動slave
mysql> start slave;

Slave_IO_Running和Slave_SQL_Running都為yes時說明配置成功,如果有NO的,可以檢視Last_IO_Error中描述的報錯進行解決。

# 檢視slave狀態
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.199.101
                  Master_User: test1
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 1713832
               Relay_Log_File: Mysql-slave-relay-bin.000002
                Relay_Log_Pos: 320
        Relay_Master_Log_File: mysql-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
........#省略.......
                   Last_Errno: 0
                   Last_Error: 
........#省略.......
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
........#省略.......
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
........#省略.......
1 row in set (0.00 sec)
配置master1為master2的slave
# master1
# 配置master1為master2的slave,執行前先檢視master1的master狀態,記下file和Position對應的值。
mysql> stop slave;
mysql> change master to
     master_host='192.168.199.102',
     master_user='test2',
     master_password='123456',
     master_log_file='mysql-bin.000002',    	# master2中的master狀態的file名稱
     master_log_pos=859788;				   	   # master2中的master狀態的Position
Query OK, 0 rows affected, 2 warnings (0.12 sec)

# 啟動slave
mysql> start slave;

Slave_IO_Running和Slave_SQL_Running都為yes時說明配置成功,如果有NO的,可以檢視Last_IO_Error中描述的報錯進行解決。

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.199.102
                  Master_User: test2
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 859788
               Relay_Log_File: Mysql-master-relay-bin.000002
                Relay_Log_Pos: 320
        Relay_Master_Log_File: mysql-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
........#省略.......
                   Last_Errno: 0
                   Last_Error: 
........#省略.......
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
........#省略.......
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
........#省略.......
1 row in set (0.00 sec)
此時,雙主配置完成,接下來驗證一下:

驗證雙主

可以在master1上面建立資料庫或者表,然後在master2上檢視是否同步過去;
再從master2上面建立資料庫或者表,然後在master1上檢視是否存在剛剛在master2上面建立的庫和表。
如果配置沒問題,那就會看到,只要在其中一個數據庫上建立庫或表,另一個數據庫就會同步。
至此相互同步相互備份。

# master1 
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| classinfo          |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

# 在master1上面建立一個名為master1的資料庫。
mysql> create database master1;  
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| classinfo          |
| master1            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
6 rows in set (0.00 sec)

# 在master2上檢視
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| classinfo          |
| master1            | # 存在剛剛在master1上建立的master1庫。
| mysql              |
| performance_schema |
| sys                |
+--------------------+
6 rows in set (0.00 sec)

# 在master2上面建立一個名為master2的資料庫。
mysql> create database master2;  
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| classinfo          |
| master1            |
| master2            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
7 rows in set (0.00 sec)
# 再到master1上檢視
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| classinfo          |
| master1            |
| master2            | # 存在剛剛在master2上建立的master2庫。
| mysql              |
| performance_schema |
| sys                |
+--------------------+
7 rows in set (0.00 sec)
驗證沒問題,這樣一來,如果其中一臺宕機,就可以拿另一臺上面的資料使用。雙主模式下兩臺主機都可以當作主,但是通常我們的服務都是連線一個地址,那另一臺就當作備機閒下來了。
由此一來我們需要使用keepalived做主備切換,實現當正在使用的節點宕機或故障導致資料庫不可用時能迅速自動切換到備機。

keepalived高可用搭建和配置

# 兩臺主機都需要安裝
yum -y install keepalived

# 備份配置檔案
cd /etc/keepalived/
cp keepalived.conf keepalived.conf.bak

# 編輯配置檔案,兩臺配置檔案基本一樣,只有優先順序不同。
cat keepalived.conf

! Configuration File for keepalived

global_defs {
   notification_email {
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
   vrrp_skip_check_adv_addr
   #vrrp_strict 		  # 如果ping不通虛擬IP(VIP)可以嘗試註釋此項。
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}
vrrp_script mysql_check {  # 健康檢查指令碼,通過命令判斷MySQL的狀態值,如果狀態值不為零,則MySQL異常,停止keepalived服務,VIP將飄逸到另一臺backup上面。
	script "/etc/keepalived/mysql_check.sh"
	# 指令碼別忘了加上可執行許可權。
	interval 2
	weight 2
}

vrrp_instance VI_1 {
    state BACKUP	       # 如果使用非搶佔模式nopreempt,則兩臺主機都設定為BACKUP。
    interface ens33
    virtual_router_id 51   # 虛擬路由的ID號,每個節點設定必須一樣,可選擇IP最後一段使用,相同的 VRID 為一個組,他將決定多播的 MAC 地址。 
    priority 100           # 優先順序,優先順序高的優先分配VIP
    advert_int 1
    nopreempt			  # 非搶佔模式:當master出現異常後,backup自動切換為master。master恢復正常後不再搶佔VIP。
    
# 說明:當master出現異常後,backup自動切換為master。然而當master恢復正常後會再次搶佔成為master,最終導致不必要的主備切換。因此可以將兩臺keepalived初始狀態均配置為backup,設定不同的優先順序,優先順序高的設定為nopreempt來解決異常恢復後再次搶佔的問題。通過以上設定我們可實現當優先順序高的排程節點故障恢復後,不再搶佔為主排程伺服器,從而也就避免了因排程節點的故障及故障恢復後來回切換的問題。

    authentication {
        auth_type PASS
        auth_pass 1111
    }
track_script {	
        mysql_check        # 使用vrrp_script定義的名稱
    }
    virtual_ipaddress {    # 虛擬IP(VIP) 網絡卡名稱:可通過ifconfig檢視	
        192.168.199.100/24 ens33
    }
}

健康檢查指令碼mysql_check.sh

cat /etc/keepalived/mysql_check.sh
#!/bin/bash

ss -tnl |grep 3306
i=$?

ps -ef | grep mysqld |grep -v color |grep -v "grep mysqld"
j=$?

mysql -uroot -pYOUR_ROOT_PASSWORD -e "select version();"
k=$?

if [ $i -ne 0 -a $j -ne 0 -a $k -ne 0 ];then
# 通過命令判斷MySQL的狀態值,如果狀態值不為零,則MySQL異常,停止keepalived服務,VIP將飄逸到另一臺backup上面。
  systemctl stop keepalived
  exit 1
else 
  exit 0
fi
systemctl start keepalived

驗證高可用

# master1
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:ad:6f:15 brd ff:ff:ff:ff:ff:ff
    inet 192.168.199.101/24 brd 192.168.199.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 192.168.199.100/24 scope global secondary ens33  # 現在VIP在master1
       valid_lft forever preferred_lft forever
    inet6 fe80::401c:480d:c598:1ecd/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

# 關閉master1上的MySQL服務
systemctl stop mysqld

# 在master2上面檢視IP
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:c8:25:50 brd ff:ff:ff:ff:ff:ff
    inet 192.168.199.102/24 brd 192.168.199.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 192.168.199.100/24 scope global secondary ens33  # 現在VIP在master2
       valid_lft forever preferred_lft forever
    inet6 fe80::3870:308:6da:d486/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
       
 # 注意,測試VIP漂移時,時關閉的MySQL服務,指令碼中發現MySQL服務不正常,就會把MySQL所在主機上的keepalived服務關閉,這樣VIP就漂移到另一臺keepalived上,當這臺修復好以後,需要先開啟mysql服務,在啟動keepalived。因為如果先啟動keepalived,keepalived就會直接執行指令碼檢查mysql狀態,導致keepalived被關閉。
 # 同時,修復後的主機不會主動搶佔VIP,即使優先順序大於另一臺keepalived。