【实战】部署 MySQL 8 主从复制和读写分离

40519
2022/11/01 21:08:45

利用主从复制,可以实现 MySQL 的读写分离、热备份等。本章将带你实战 MySQL 的一主二从。

主从复制架构

实战环境

本次实战使用HAX的免费VPS的同一机房的三台VPS进行,操作系统为 Debian 11 x64。

节点IP
主节点(Master)2a01:4f8:13a:2690:face:10d4:*:0001
从节点1(Slave1)2a01:4f8:13a:2690:face:0915:*:0001
从节点2(Slave2)2a01:4f8:13a:2690:face:0e54:*:0001

安装MySQL

三个节点均需要安装 MySQL:

wget -O /tmp/mysql-apt-config.deb https://dev.mysql.com/get/mysql-apt-config_0.8.24-1_all.deb && \
dpkg -i /tmp/mysql-apt-config.deb && \
apt update -y && apt install mysql-server -y

安装过程中,需要一些交互:

选择要安装的组件

选择要安装的组件

这里保持默认,即安装 MySQL 8 Server。

设置 root 密码

设置root密码

这里输入 axum.rs 作为 root 用户的密码。注意,输入密码的时候可能没有回显,直接输入即可。输入完成按回车。

设置主节点(Master)

为了实现主从复制,我们需要对 MySQL 服务器进行设置。通过 apt 方式安装的 MySQL,它的 mysqld 配置文件位于 /etc/mysql/mysql.conf.d/mysqld.cnf

server-id = 1
read-only = 0
log-bin = axum-rs-bin
binlog-format = mixed
bind-address = ::
  • server-id:服务器ID。必须设置,且同一个主从配置中,该值必须唯一
  • read-only:是否只读。对于主节点来说可选。
  • log-bin:是否开启binlog,及其文件名。对于 MySQL 8 来说可选,因为 MySQL 8 默认就开启 binlog
  • binlog-formatbinlog 格式,可选。
  • bind-address:MySQL 服务器监听地址。使用 apt 方式安装的 MySQL,默认监听的是本地回环地址,要想远程访问,需要将其设置为公网IP。对于 ipv4,通常设置为 0.0.0.0,由于本次实战使用的是 Hax 的 ipv6 机器,所以这里设置成了 ipv6的地址。
cat > /etc/mysql/mysql.conf.d/mysqld.cnf << EOF
[mysqld]
pid-file	= /var/run/mysqld/mysqld.pid
socket		= /var/run/mysqld/mysqld.sock
datadir		= /var/lib/mysql
log-error	= /var/log/mysql/error.log
server-id = 1
read-only = 0
log-bin = axum-rs-bin
binlog-format = mixed
bind-address = ::
EOF

设置完成后,重启 MySQL 服务,并尝试登录:

systemctl restart mysql && \
mysql -u root -paxum.rs

设置从节点(Slave)

从节点和主节点配置大同异,以 slave1 为例:

server-id = 2
read-only = 1
log-bin = axum-rs-bin
binlog-format = mixed
bind-address = ::
relay-log = axum-rs-relay
  • server-id:服务器ID,请确保在同一个主从复制中,其值的唯一性
  • read-only:对于从服务器来说,将其设置为只读是必要的。因为它的数据始终是由主节点同步而来。
  • relay-log:MySQL 8 新增的配置,用于开启和设置中继日志。

从节点1(slave1)

cat > /etc/mysql/mysql.conf.d/mysqld.cnf << EOF
[mysqld]
pid-file	= /var/run/mysqld/mysqld.pid
socket		= /var/run/mysqld/mysqld.sock
datadir		= /var/lib/mysql
log-error	= /var/log/mysql/error.log
server-id = 2
read-only = 1
log-bin = axum-rs-bin
binlog-format = mixed
bind-address = ::
relay-log = axum-rs-relay
EOF

systemctl restart mysql && \
mysql -u root -paxum.rs

从节点2(slave2)

cat > /etc/mysql/mysql.conf.d/mysqld.cnf << EOF
[mysqld]
pid-file	= /var/run/mysqld/mysqld.pid
socket		= /var/run/mysqld/mysqld.sock
datadir		= /var/lib/mysql
log-error	= /var/log/mysql/error.log
server-id = 3
read-only = 1
log-bin = axum-rs-bin
binlog-format = mixed
bind-address = ::
relay-log = axum-rs-relay
EOF

systemctl restart mysql && \
mysql -u root -paxum.rs

开启主从复制

主节点

创建主从复制的用户

CREATE USER 'slaver'@'%' IDENTIFIED BY 'axum.rs';
GRANT REPLICATION SLAVE ON *.* TO 'slaver'@'%';
ALTER USER 'slaver'@'%' IDENTIFIED WITH mysql_native_password BY 'axum.rs';
FLUSH PRIVILEGES;

查看主节点状态

SHOW MASTER STATUS;

/*
+--------------------+----------+--------------+------------------+-------------------+
| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+--------------------+----------+--------------+------------------+-------------------+
| axum-rs-bin.000001 |     1147 |              |                  |                   |
+--------------------+----------+--------------+------------------+-------------------+
*/

请牢记两个值:

  • File:当前binlog 文件名
  • Position:当前位置

从节点

两个从节点都要执行以下操作。

设置同步数据的主节点信息

CHANGE MASTER TO 
MASTER_HOST='2a01:4f8:13a:2690:face:10d4:*:0001',
MASTER_USER='slaver',
MASTER_PASSWORD='axum.rs',
MASTER_SSL=0,
MASTER_LOG_FILE='axum-rs-bin.000001',
MASTER_LOG_POS=1147;
  • MASTER_HOST:主节点地址
  • MASTER_USER:执行同步的用户名
  • MASTER_PASSWORD:执行同步密码
  • MASTER_LOG_FILE:在“查看主节点状态”中,输出结果的 File 的值
  • MASTER_LOG_POS:在“查看主节点状态”中,输出结果的 Position

开启同步

START SLAVE;

查看同步状态

SHOW SLAVE STATUS\G

注意,只有当以下两个值均为 Yes时,才表示设置成功:

  • Slave_IO_Running
  • Slave_SQL_Running

从节点1的同步状态

从节点1的同步状态

从节点2的同步状态

测试主从同步

为了验证主从同步是否正常工作,下面进行测试。首先在主节点创建数据库、创建表、插入数据;然后在两个从节点分别查询数据。

主节点

CREATE DATABASE axum_rs;
USE axum_rs;
CREATE TABLE axum_rs_test (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL
);
INSERT INTO axum_rs_test (name) 
VALUES 
	('axum.rs'), ('test'), ('foobar');
SELECT * FROM axum_rs_test;

主节点创建并查询数据

从节点

从节点1的查询结果

从节点1的查询结果

从节点2的查询结果

从节点2的查询结果