前言
关于 MySQL 主从复制的原理,请参阅以前的 《Redis进阶篇04 — 复制技术(一)MySQL》。
Q:为什么主从复制一定要搭配 keepalived ?
复制(Replication):一种将一组数据从一个数据源拷贝到另外一个或多个数据源的备份技术。在 MySQL 主从复制中,复制能实现数据备份、读写分离(提高并发处理能力)、部分高可用(相比单机单实例)。在实际的业务环境中,主从复制的 master 出现故障时,需要人为手动的进行切换,但有些关键业务需要一些可靠性标准——2个9标准(99%);3个9标准(99.9%)等。因此我们需要出现故障时全程自动切换,这也是为什么需要 keepalived 的原因。
由前面文章可知主从复制的原则:
- 每个 Slave(replica) 只能有一个 Master(source)
- 每个 Slave(replica) 只能有唯一的 server-id
- 每个 Master(source) 可以有多个 Slave(replica)
基本信息列表:
OS | COMMAND/GUI | 真实 IP | 部署软件 | 扮演角色 | VIP | 初始主备 |
---|---|---|---|---|---|---|
RL 8.7 | COMMAND | 10.1.1.3/24 | Mysql Server V8.0.33 | source | 10.1.1.15/24 | Master |
RL 8.7 | COMMAND | 10.1.1.4/24 | Mysql Server V8.0.33 | replica | 10.1.1.15/24 | Backup |
MySQL 的安装与配置
您的安装方式不必与作者相同。
10.1.1.3/24 安装和配置 MySQL
以下为操作步骤:
# 创建伪用户(0<uid<1000)和伪组(0<gid<1000)
Shell > groupadd -r mysql && useradd -r -g mysql -s /sbin/nologin mysql
# 安装依赖,\ 表示命令未结束
Shell > dnf -y install libaio ncurses-compat-libs ncurses-devel make cmake gcc bison git libtirpc-devel \
openssl openssl-devel rpcgen gcc-toolset-12-gcc gcc-toolset-12-gcc-c++
# 开始源代码编译
Shell > wget -c https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-8.0.33.tar.gz
Shell > tar -zvxf mysql-boost-8.0.33.tar.gz -C /usr/local/src/
Shell > cd /usr/local/src/mysql-8.0.33/ && mkdir build && cd build && cmake .. \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_0900_ai_ci \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql/ \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DENABLED_LOCAL_INFILE=1 \
-DMYSQL_TCP_PORT=3306 \
-DWITH_BOOST=/usr/local/src/mysql-8.0.33/boost/ \
-DMYSQL_DATADIR=/usr/local/mysql/data \
&& make && make install
大约需要等待 1.5 小时,MySQL 才完成编译和安装。
基本配置如下:
Shell > chmod -R 755 /usr/local/mysql/
Shell > chown -R mysql:mysql /usr/local/mysql/
# 执行初始化,生成数据目录以及初始的 root 密码
Shell > /usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql \
--datadir=/usr/local/mysql/data
# 添加配置文件 /etc/my.cnf
Shell > vim /etc/my.cnf
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
server-id = 1
port = 3306
socket = /tmp/mysql.sock
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
user = mysql
log-error = /usr/local/mysql/data/mysqld_start.err
bind-address = *
default-storage-engine = INNODB
group-concat-max-len = 102400
skip-name-resolve
back-log = 151
max-connections = 700
wait-timeout = 90
max-allowed-packet = 100M
read-buffer-size = 512K
sync-binlog = 1
innodb-buffer-pool-size = 1G
log-bin = /usr/local/mysql/data/source-binlog
read-only = 0
binlog-expire-logs-seconds = 2592000
binlog-format = ROW
[mysqldump]
quick
一些关键配置项的说明:
server-id = 1
,标识当前数据库实例的唯一编号,主要是为了区别不同的 MySQL 服务器default-storage-engine = INNODB
– 默认使用的存储引擎group-concat-max-len = 102400
– GROUP_CONCAT( )函数允许的最大结果长度(字节),默认 1024。通常我们都建议您加大该参数项的值back-log = 151
– 在 Redis 中你也见过这个配置项,一个影响性能的关键配置项。它是指 MySQL 这个服务的全连接队列的大小。全连接队列的大小由两部分决定——listen 函数里的 backlog 以及 Linux 内核参数/proc/sys/net/core/somaxconn
,最终的队列大小由数字最小的那个来决定。我们在 Redis基础篇06 — 配置文件详解(一) 中说明过。max-connections = 700
– MySQL 的最大连接数,范围为 [1,100000],值越大,占用的内存资源越多。该配置项也在 Redis 中见过,参阅 Redis基础篇07 — 配置文件详解(二)。请注意文件描述符的值,默认情况下,用户级别的文件描述符上限为 1024sync-binlog = 1
– 控制数据库的 binlog 间隔多少秒刷新到磁盘上去innodb-buffer-pool-size = 1G
– innodb 缓冲池大小,通常为当前可用内存的 80%read-only = 0
– 是否只读,0 值表示当前数据库实例可读可写。binlog-format = ROW
– binlog 的格式
最后,我们需要修改初始的 root 密码:
Shell > /usr/local/mysql/bin/mysqld_safe --user=mysql &
Shell > /usr/local/mysql/bin/mysql -u root --password="wl%J,b)cM6-y";
Mysql > ALTER USER 'root'@'localhost' IDENTIFIED BY '338922549';
10.1.1.4/24 安装和配置 MySQL
步骤同上,但是 /etc/my.cnf 稍有不同:
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
server-id = 2 ← 不同项
port = 3306
socket = /tmp/mysql.sock
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
user = mysql
log-error = /usr/local/mysql/data/mysqld_start.err
bind-address = *
default-storage-engine = INNODB
group-concat-max-len = 102400
skip-name-resolve
back-log = 151
max-connections = 700
wait-timeout = 90
max-allowed-packet = 100M
read-buffer-size = 512K
sync-binlog = 1
innodb-buffer-pool-size = 1G
relay-log = /usr/local/mysql/data/replica-relaylog ← 开启中继日志,不同项
replicate-ignore-db = mysql ← 复制时要忽略的 source server 的库,可以填写多行。不同项
replicate-ignore-db = sys
replicate-ignore-db = performance_schema
replicate-ignore-db = information_schema
[mysqldump]
quick
修改 root 的初始密码:
Shell > /usr/local/mysql/bin/mysql -u root --password="lOt;USseu8qh";
Mysql > ALTER USER 'root'@'localhost' IDENTIFIED BY '95270110';
主从复制的操作步骤
步骤1:在 10.1.1.3/24 上创建用于复制的用户
Mysql > create user 'mysqlsync'@'%' identified by '1592778';
Mysql > grant replication slave on *.* to 'mysqlsync'@'%';
# 一定要执行这一步,如果不执行,在从服务器上 使用 show slave status\G; 报错,提示——Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connectio
Mysql > alter user 'mysqlsync'@'%' identified with mysql_native_password by '1592778';
Mysql > show grants for 'mysqlsync'@'%';
# 查看使用到的 binlog
Mysql> show master status;
+----------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+----------------------+----------+--------------+------------------+-------------------+
| source-binlog.000002 | 986 | | | |
+----------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
步骤2:在 10.1.1.4/24 上执行复制操作
Mysql > change replication source to
source_host='10.1.1.3',
source_user='mysqlsync',
source_password='1592778',
source_log_file='source-binlog.000002',
source_log_pos=986;
# 如果这一步报错,可使用 reset replica;
Mysql > start replica;
Mysql > show replica status\G;
# 或者
Mysql > show slave status\G;
...
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
...
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
请注意!我们这里的主从同步是单向的,只有主从同步成功的那一刻起,新创建的库与表才会被同步,过往历史的并不会。当然,你可以将主服务器上的过往历史数据使用逻辑备份备份出来,并将它们恢复到从服务器中。
keepalived 的安装与配置
10.1.1.3/24 执行的操作
# 依赖包
Shell > dnf -y install wget make gcc openssl openssl-devel libnl3-devel libnl3 tar bzip2 gzip zip xz
# 源代码编译
Shell > wget -c https://keepalived.org/software/keepalived-2.2.7.tar.gz && tar -zvxf keepalived-2.2.7.tar.gz -C /usr/local/src/
Shell > cd /usr/local/src/keepalived-2.2.7/ && ./configure --prefix=/usr/local/keepalived \
--with-init=systemd \
--with-systemdsystemunitdir=/usr/lib/systemd/system \
&& make && make install
配置 Keepalived:
Shell > cd /usr/local/keepalived/etc/keepalived && mv keepalived.conf.sample keepalived.conf
Shell > vim /usr/local/keepalived/etc/keepalived/keepalived.conf
global_defs {
router_id VRRP01
vrrp_skip_check_adv_addr
enable_script_security
script_user root
}
vrrp_script check_mysql {
script "/usr/local/keepalived/check_mysql.sh"
interval 2
weight -5
}
vrrp_instance VI_1 {
state MASTER
interface ens160
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.1.1.15/24 dev ens160 label ens160:1
}
track_script {
check_mysql
}
}
Shell > vim /usr/local/keepalived/check_mysql.sh
#!/bin/bash
port=$(ss -tulnp | grep mysqld | awk '{print $5}' | cut -f 2 -d ":" | grep -w 3306)
if [ -z "${port}" ]
then
systemctl stop keepalived.service
fi
Shell > chmod 755 /usr/local/keepalived/check_mysql.sh
Shell > vim /usr/lib/systemd/system/keepalived.service
...
[Service]
...
ExecStart=/usr/local/keepalived/sbin/keepalived -f /usr/local/keepalived/etc/keepalived/keepalived.conf
...
10.1.1.4/24 执行的操作
安装步骤同上。
配置 Keepalived:
Shell > cd /usr/local/keepalived/etc/keepalived && mv keepalived.conf.sample keepalived.conf
Shell > vim /usr/local/keepalived/etc/keepalived/keepalived.conf
global_defs {
router_id VRRP02
vrrp_skip_check_adv_addr
enable_script_security
script_user root
}
vrrp_script check_mysql {
script "/usr/local/keepalived/check_mysql.sh"
interval 2
weight -5
}
vrrp_instance VI_1 {
state BACKUP
interface ens160
virtual_router_id 51
priority 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.1.1.15/24 dev ens160 label ens160:1
}
track_script {
check_mysql
}
}
Shell > vim /usr/local/keepalived/check_mysql.sh
#!/bin/bash
port=$(ss -tulnp | grep mysqld | awk '{print $5}' | cut -f 2 -d ":" | grep -w 3306)
if [ -z "${port}" ]
then
systemctl stop keepalived.service
fi
Shell > chmod 755 /usr/local/keepalived/check_mysql.sh
Shell > vim /usr/lib/systemd/system/keepalived.service
...
[Service]
...
ExecStart=/usr/local/keepalived/sbin/keepalived -f /usr/local/keepalived/etc/keepalived/keepalived.conf
...
注意点:
- Master 和 Backup 的 router_id 必须不同且唯一
- VRRP 实例名称必须相同,这里都是
VI_1
- VRRP 实例里的 VRID 必须相同,这里都是
51
- Master 的优先级要比 Backup 的优先级高50
- 若在配置文件未写入任何有关抢占模式方面的内容,则默认就是 抢占模式
模拟主备切换
前文提到,MySQL 8 为了安全性考虑,默认不允许 root 登录,因此需要创建相关的登录用户。
前面的配置文件提到,我忽略了 mysql、sys、performance_schema、information_schema 这四个库的复制。在实际情况下,您在 source 和 replica 所创建的用户与密码应该相同,这里只是为了具体演示出效果与差异。
# 10.1.1.3/24
Mysql > create user 'mclient1'@'%' identified by 'google404';
Mysql > grant all privileges on *.* to 'mclient1'@'%';
# 10.1.1.4/24
Mysql > create user 'bclient1'@'%' identified by 'googlecloud';
Mysql > grant all privileges on *.* to 'bclient1'@'%';
在正常情况下,客户端可通过 VIP 进行访问:
若假设 Source MySQL 故障了(相当于 Master Keepalived 故障),手动停止 —— /usr/local/mysql/bin/mysqladmin -u root -p shutdown
此时 Backup keepalived的日志输出如下:
4月 23 13:21:48 Backup Keepalived_vrrp[18146]: (VI_1) Backup received priority 0 advertisement
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: (VI_1) Receive advertisement timeout
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: (VI_1) Entering MASTER STATE
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: (VI_1) setting VIPs.
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: (VI_1) Sending/queueing gratuitous ARPs on ens160 for 10.1.1.15
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:49 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:54 Backup Keepalived_vrrp[18146]: (VI_1) Sending/queueing gratuitous ARPs on ens160 for 10.1.1.15
4月 23 13:21:54 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:54 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:54 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:54 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
4月 23 13:21:54 Backup Keepalived_vrrp[18146]: Sending gratuitous ARP on ens160 for 10.1.1.15
此时依旧可以正常访问: