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 statusG
*************************** 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 statusG
*************************** 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 {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   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。
原文地址:https://www.cnblogs.com/Smbands/p/14963880.html