数据库主从复制

1. 主从复制概述

1.1 什么是主从复制

MySQL的主从架构模式,是很多企业广泛使用,并且大家所广为熟知的一种架构模式,这是DBA所应该熟练掌握的技能。

主从复制(Master-Slave Replication)是MySQL提供的一种数据复制机制,允许将一个MySQL服务器(主库)的数据自动复制到一个或多个MySQL服务器(从库)。

核心概念

  • 主库(Master):接受写操作的数据库服务器
  • 从库(Slave):复制主库数据的数据库服务器
  • 复制(Replication):数据从主库同步到从库的过程

1.2 MySQL主从复制主要用途

1. 用于备份,避免影响业务

优势

  • 从库可以独立进行备份,不影响主库性能
  • 备份过程对业务透明
  • 可以保留多个时间点的数据快照

应用场景

  • 定期数据备份
  • 数据归档
  • 历史数据查询

2. 实时灾备,用于故障切换

优势

  • 主库故障时可以快速切换到从库
  • 数据实时同步,RPO(恢复点目标)接近0
  • 提高系统可用性

应用场景

  • 主库故障切换
  • 数据中心灾备
  • 异地容灾

3. 读写分离,提供查询服务

优势

  • 读操作分散到多个从库
  • 减轻主库压力
  • 提高系统整体性能

应用场景

  • 高并发读场景
  • 报表查询
  • 数据分析

1.3 MySQL主从复制存在的问题

1. 主库宕机后,数据可能丢失

问题描述

  • 主库宕机时,未同步到从库的数据可能丢失
  • 异步复制存在数据丢失风险

解决方案

  • 半同步复制:至少一个从库确认接收后才返回
  • 全同步复制:所有从库确认接收后才返回
  • 要求:MySQL 5.7+版本支持

2. 主库写压力大,复制可能会延时

问题描述

  • 主库写入量大时,从库可能跟不上
  • 从库复制延迟导致数据不一致

解决方案

  • 并行复制:多线程并行执行复制
  • 建议:MySQL 5.7+版本,性能提升显著

1.4 MySQL主从复制原理

MySQL主从复制基于二进制日志(Binary Log)实现,采用异步复制机制。

复制流程

1
2
3
4
5
6
7
8
9
10
11
12
主库(Master)                   从库(Slave)
| |
| 1. 记录变更到Binary Log |
| (DDL、DML、DCL) |
| |
| 2. I/O线程读取Binary Log |
| ────────────────────────────> |
| | 3. 写入Relay Log
| | (中继日志)
| |
| | 4. SQL线程读取Relay Log
| | 5. 重放到从库数据库

详细步骤

步骤1:主库记录变更

在主库上把将更改(DDL、DML、DCL)记录到二进制日志(Binary Log)中。

1
2
3
4
5
6
-- 主库执行操作
INSERT INTO t1 VALUES (1, 'test');
UPDATE t1 SET name = 'new' WHERE id = 1;
DELETE FROM t1 WHERE id = 1;

-- 这些操作会被记录到Binary Log中

步骤2:从库I/O线程复制日志

备库I/O线程将主库上的二进制日志复制到自己的中继日志(Relay Log)中。

I/O线程职责

  • 连接主库
  • 请求binlog内容
  • 接收binlog事件
  • 写入Relay Log

步骤3:从库SQL线程重放

备库SQL线程读取中继日志中的事件,将其重放到备库数据库之上。

SQL线程职责

  • 读取Relay Log
  • 解析SQL语句
  • 在从库执行
  • 更新从库数据

1.5 主从复制架构类型

根据图片中的架构图,MySQL主从复制有以下几种常见架构:

1. MySQL主从复制(Master-Slave)

架构:一主一从

特点

  • 最简单的复制架构
  • 主库负责读写
  • 从库主要用于备份

2. MySQL读写分离复制

架构:一主一从,读写分离

特点

  • 主库负责写操作
  • 从库负责读操作
  • 减轻主库压力

3. MySQL一主多从复制

架构:一主多从

特点

  • 一个主库,多个从库
  • 读操作分散到多个从库
  • 提高读性能

4. MySQL一主多从负载均衡

架构:一主多从 + LVS+Keepalived

特点

  • 使用负载均衡器分发读请求
  • 高可用性
  • 自动故障切换

5. MySQL双向同步(Master-Master)

架构:双主复制

特点

  • 两个主库互相复制
  • 高可用性
  • 支持双写(需注意冲突)

6. MySQL读写分离双向同步

架构:双主 + 读写分离

特点

  • 双主架构
  • 读写分离
  • 高可用 + 高性能

7. MySQL双主双从

架构:双主 + 双从

特点

  • 双主互相复制
  • 每个主库有独立的从库
  • 最高可用性和性能

2. MySQL数据库传统复制

2.1 传统复制概述

传统复制是MySQL最基础的复制方式,通过指定binlog文件和位置点来实现复制。

特点

  • 需要手动指定binlog文件和位置
  • 配置相对复杂
  • 适用于MySQL 5.6及以下版本

2.2 环境准备

操作系统配置

/etc/hosts文件解析

1
2
3
# 在主库和从库上配置
192.168.70.160 master1
192.168.70.161 slave1

验证网络连通性

1
2
3
4
5
# 在主库上测试
[root@Master ~]# ping slave1

# 在从库上测试
[root@Slave ~]# ping master1

2.3 Master配置

1. 修改配置文件

1
2
3
4
5
6
7
8
# 编辑MySQL配置文件
[root@Master ~]# vim /etc/my.cnf

[mysqld]
# 开启二进制日志
log-bin
# 设置服务器ID(必须唯一)
server-id=160

配置说明

  • log-bin:开启二进制日志
  • server-id:服务器唯一标识,主从不能相同

2. 重启MySQL服务

1
2
3
4
5
6
7
8
9
10
# 重启MySQL服务使配置生效
[root@Master ~]# systemctl restart mysqld

# 验证binlog是否开启
mysql> SHOW VARIABLES LIKE 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+

3. 模拟线上数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- 创建测试数据库
mysql> CREATE DATABASE linuxdb;
Query OK, 1 row affected (0.00 sec)

mysql> USE linuxdb;
Database changed

-- 创建测试表
mysql> CREATE TABLE t1(id INT, name VARCHAR(20));
Query OK, 0 rows affected (0.00 sec)

-- 插入测试数据
mysql> INSERT INTO t1 VALUES (1,'tt');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO t1 VALUES (2,'ttt');
Query OK, 1 row affected (0.00 sec)

-- 查看数据
mysql> SELECT * FROM t1;
+------+------+
| id | name |
+------+------+
| 1 | tt |
| 2 | ttt |
+------+------+
2 rows in set (0.00 sec)

4. 授权复制用户

1
2
3
4
5
6
7
8
-- 授权,允许能够远程连接的主机(replication)
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
-> TO 'rep'@'192.168.70.%' IDENTIFIED BY 'Rep123.com';
Query OK, 0 rows affected (0.00 sec)

-- 刷新权限
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

权限说明

  • REPLICATION SLAVE:允许从库连接主库
  • REPLICATION CLIENT:允许查看复制状态
  • 192.168.70.%:允许该网段的主机连接

5. 导出当前数据

1
2
3
4
5
6
# 导出所有数据库,包含binlog位置信息
[root@Master ~]# mysqldump -uroot -pBgx123.com \
--all-databases \
--single-transaction \
--master-data=1 \
--flush-logs > /root/db-$(date +%F)-all.sql

参数说明

  • --all-databases:备份所有数据库
  • --single-transaction:保证一致性
  • --master-data=1:记录binlog位置
  • --flush-logs:刷新日志

6. 将备份文件传送至Slave

1
2
# 使用scp传输备份文件
[root@Master ~]# scp /root/db-2018-05-10-all.sql root@slave1:/root

2.4 Slave配置

1. 检查远程账户登录

1
2
# 测试复制用户是否可以连接主库
[root@slave ~]# mysql -hmaster1 -urep -pRep123.com

如果连接失败,检查

  • 防火墙规则
  • 网络连通性
  • 用户权限

2. 修改配置文件

1
2
3
4
5
6
7
8
# 编辑MySQL配置文件
[root@slave ~]# vim /etc/my.cnf

[mysqld]
# 设置服务器ID(必须与主库不同)
server-id=161
# 从库建议也开启binlog(用于级联复制)
log-bin

配置说明

  • server-id:必须与主库不同
  • log-bin:从库开启binlog可用于级联复制

3. 重启MySQL服务

1
2
# 重启MySQL服务
[root@slave ~]# systemctl restart mysqld

4. 导入数据

1
2
# 导入备份数据,追master的binlog
[root@Slave ~]# mysql -uroot -p'Bgx123.com' -e "SOURCE /root/db-2018-05-10-all.sql"

或者

1
[root@Slave ~]# mysql -uroot -p'Bgx123.com' < /root/db-2018-05-10-all.sql

5. 配置主从关系

1
2
3
4
5
6
-- 指向Master,传统复制无需指定binlogfile和pos(从备份文件中自动获取)
mysql> CHANGE MASTER TO
-> MASTER_HOST='master1',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='Rep123.com';
Query OK, 0 rows affected (0.01 sec)

说明

  • 如果备份文件包含--master-data=1,会自动读取binlog位置
  • 也可以手动指定:MASTER_LOG_FILEMASTER_LOG_POS

6. 启动Slave角色

1
2
3
-- 启动从库复制
mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

7. 查看Slave状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
-- 查看从库复制状态
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: master1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: Master1-bin.000003
Read_Master_Log_Pos: 589
Relay_Log_File: Slave1-relay-bin.000004
Relay_Log_Pos: 613
Relay_Master_Log_File: Master1-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 589
Relay_Log_Space: 820
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 160
Master_UUID:
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:

关键字段说明

字段 说明 正常值
Slave_IO_Running I/O线程状态 Yes
Slave_SQL_Running SQL线程状态 Yes
Seconds_Behind_Master 复制延迟(秒) 0(无延迟)
Master_Log_File 主库当前binlog文件 -
Read_Master_Log_Pos 已读取的主库binlog位置 -
Last_IO_Error 最后一次I/O错误 空(无错误)
Last_SQL_Error 最后一次SQL错误 空(无错误)

验证复制

1
2
3
4
5
6
7
8
9
10
11
12
-- 在主库插入数据
mysql> INSERT INTO linuxdb.t1 VALUES (3,'test');

-- 在从库查看
mysql> SELECT * FROM linuxdb.t1;
+------+------+
| id | name |
+------+------+
| 1 | tt |
| 2 | ttt |
| 3 | test |
+------+------+

复制成功:从库已自动同步主库数据。


3. MySQL数据库GTID复制

3.1 GTID复制概述

GTID(Global Transaction Identifier)是MySQL 5.6+引入的全局事务标识符,用于简化主从复制的配置和管理。

GTID优势

  • 自动定位:无需手动指定binlog文件和位置
  • 故障恢复:自动找到正确的复制位置
  • 多源复制:支持从多个主库复制
  • 简化管理:配置更简单

GTID格式

1
2
GTID = server_uuid:transaction_id
例如:3E11FA47-71CA-11E1-9E33-C80AA9429562:23

3.2 环境准备

/etc/hosts文件解析

1
2
192.168.70.160 master1
192.168.70.161 slave1

注意:如果实验过传统主从复制,请重置Slave数据库。

3.3 Master配置

1. 修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
# 编辑MySQL配置文件
[root@Master ~]# vim /etc/my.cnf

[mysqld]
# 开启二进制日志
log-bin
# 设置服务器ID
server-id=160
# 开启GTID
gtid_mode=ON
# 强制GTID一致性
enforce_gtid_consistency=1

配置说明

  • gtid_mode=ON:开启GTID模式
  • enforce_gtid_consistency=1:强制GTID一致性,防止不支持GTID的语句

2. 重启MySQL服务

1
2
3
4
5
6
7
8
9
10
# 重启MySQL服务使配置生效
[root@Master ~]# systemctl restart mysqld

# 验证GTID是否开启
mysql> SHOW VARIABLES LIKE 'gtid_mode';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| gtid_mode | ON |
+---------------+-------+

3. 模拟线上数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 创建测试数据库
mysql> CREATE DATABASE linuxdb;
mysql> USE linuxdb;
mysql> CREATE TABLE t1(id INT, name VARCHAR(20));
mysql> INSERT INTO t1 VALUES (1,'tt');
mysql> INSERT INTO t1 VALUES (2,'ttt');
mysql> SELECT * FROM t1;
+------+------+
| id | name |
+------+------+
| 1 | tt |
| 2 | ttt |
+------+------+

4. 授权复制用户

1
2
3
4
-- 授权复制用户
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
-> TO 'rep'@'192.168.70.%' IDENTIFIED BY 'Rep123.com';
mysql> FLUSH PRIVILEGES;

5. 导出当前数据

1
2
3
4
5
6
# 导出数据
[root@Master ~]# mysqldump -uroot -pBgx123.com \
--all-databases \
--master-data=1 \
--single-transaction \
--flush-logs > /root/db-$(date +%F)-all.sql

6. 将备份文件传送至Slave

1
2
# 传输备份文件
[root@Master ~]# scp /root/db-2018-05-10-all.sql root@slave1:/root

3.4 Slave配置

1. 重新初始化环境

1
2
3
4
5
6
7
8
9
10
11
# 停止MySQL服务
[root@Slave1 ~]# systemctl stop mysqld

# 删除数据目录(重置从库)
[root@Slave1 ~]# rm -rf /var/lib/mysql/*

# 修改权限
[root@Slave1 ~]# chown -R mysql.mysql /var/lib/mysql

# 启动MySQL服务(会自动初始化)
[root@Slave1 ~]# systemctl start mysqld

2. 检查远程账户登录

1
2
# 测试复制用户连接
[root@slave ~]# mysql -hmaster1 -urep -pRep123.com

3. 修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 编辑MySQL配置文件
[root@slave ~]# vim /etc/my.cnf

[mysqld]
# 设置服务器ID
server-id=161
# 开启GTID
gtid_mode=ON
# 强制GTID一致性
enforce_gtid_consistency=1

# [可选]保存连接信息至表中
# log-info-repository=TABLE
# relay-log-info-repository=TABLE

可选配置说明

  • log-info-repository=TABLE:将复制信息保存到表中,而不是文件
  • relay-log-info-repository=TABLE:将中继日志信息保存到表中

4. 重启MySQL服务

1
2
# 重启MySQL服务
[root@slave ~]# systemctl restart mysqld

5. 导入数据

1
2
# 导入备份数据
[root@Slave ~]# mysql -uroot -p'Bgx123.com' -e "SOURCE /root/db-2018-05-10-all.sql"

6. 配置主从关系(GTID自动协商)

1
2
3
4
5
6
7
-- 指向Master,GTID自动协商同步
mysql> CHANGE MASTER TO
-> MASTER_HOST='master1',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='Rep123.com',
-> MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected (0.01 sec)

关键参数

  • MASTER_AUTO_POSITION=1:启用GTID自动定位,无需指定binlog位置

7. 启动Slave角色

1
2
3
-- 启动从库复制
mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

8. 查看Slave状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- 查看从库复制状态
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: master1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: Master1-bin.000003
Read_Master_Log_Pos: 589
Relay_Log_File: Slave1-relay-bin.000004
Relay_Log_Pos: 613
Relay_Master_Log_File: Master1-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Retrieved_Gtid_Set: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
Executed_Gtid_Set: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
Auto_Position: 1

GTID相关字段

  • Retrieved_Gtid_Set:已接收的GTID集合
  • Executed_Gtid_Set:已执行的GTID集合
  • Auto_Position:是否启用自动定位(1表示启用)

4. MySQL数据库双主复制

4.1 双主复制概述

双主复制(Master-Master Replication)是两个MySQL服务器互相作为对方的主库和从库。

注意:数据库双主M-M架构,需要基于GTID的主从架构演变。

应用场景

  • 高可用性要求
  • 双数据中心部署
  • 负载均衡

注意事项

  • 避免同时写入相同数据
  • 使用应用层控制写操作
  • 或使用VIP切换

4.2 双主复制配置

Master1配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1.修改配置
vim /etc/my.cnf

[mysqld]
log-bin
server-id=160
gtid_mode=ON
enforce_gtid_consistency=1

# 2.重启MySQL数据库
systemctl restart mysqld

# 3.授权(之前已授权,可跳过)
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
-> TO 'rep'@'192.168.70.%' IDENTIFIED BY 'Rep123.com';

# 4.导出数据库
mysqldump -uroot -pBgx123.com \
--all-databases \
--master-data=1 \
--single-transaction \
--flush-logs > /root/master1-$(date +%F).sql

Master2配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1.修改配置
vim /etc/my.cnf

[mysqld]
log-bin
server-id=161
gtid_mode=ON
enforce_gtid_consistency=1

# 2.重启MySQL数据库
systemctl restart mysqld

# 3.授权(给master1授权,由于之前授权针对网段,可跳过)
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
-> TO 'rep'@'192.168.70.%' IDENTIFIED BY 'Rep123.com';

# 4.恢复Master1数据,保持主从同步
mysql -uroot -pBgx123.com < /root/master1-2018-05-10.sql

重要:master1和master2数据必须保持一致。

配置双向复制

在Master1上执行

1
2
3
4
5
6
7
8
9
-- 指向Master2
mysql> CHANGE MASTER TO
-> MASTER_HOST='master2',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='Rep123.com',
-> MASTER_AUTO_POSITION=1;

mysql> START SLAVE;
mysql> SHOW SLAVE STATUS\G

在Master2上执行

1
2
3
4
5
6
7
8
9
-- 指向Master1
mysql> CHANGE MASTER TO
-> MASTER_HOST='master1',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='Rep123.com',
-> MASTER_AUTO_POSITION=1;

mysql> START SLAVE;
mysql> SHOW SLAVE STATUS\G

验证双主复制

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 在Master1插入数据
mysql> INSERT INTO linuxdb.t1 VALUES (4,'master1');

-- 在Master2查看
mysql> SELECT * FROM linuxdb.t1;
-- 应该能看到master1插入的数据

-- 在Master2插入数据
mysql> INSERT INTO linuxdb.t1 VALUES (5,'master2');

-- 在Master1查看
mysql> SELECT * FROM linuxdb.t1;
-- 应该能看到master2插入的数据

5. MySQL数据库多源复制

5.1 多源复制概述

多源复制(Multi-Source Replication)允许一个从库从多个主库复制数据,MySQL 5.7+支持。

架构:M-M-S-S(双主双从)

应用场景

  • 数据汇总
  • 报表分析
  • 多数据中心数据合并

5.2 多源复制配置

环境准备

1
2
3
4
5
# /etc/hosts文件解析
192.168.70.160 master1
192.168.70.161 master2
192.168.70.162 slave2
192.168.70.163 slave3

Master1配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 1.修改配置
vim /etc/my.cnf

[mysqld]
log-bin
server_id=160
gtid_mode=ON
enforce_gtid_consistency=1

# 2.重启MySQL服务器
systemctl restart mysqld

# 3.授权(建议网段)
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
-> TO 'rep'@'192.168.70.%' IDENTIFIED BY 'Rep123.com';
mysql> FLUSH PRIVILEGES;

# 4.导出对应的数据
mysqldump -uroot -p'Bgx123.com' \
--all-databases \
--master-data=1 \
--single-transaction \
--flush-logs > /root/$(date +%F)-mysql-all.sql

# 5.分发对应的数据
scp /root/2018-05-10-mysql-all.sql root@master2:/root
scp /root/2018-05-10-mysql-all.sql root@slave2:/root
scp /root/2018-05-10-mysql-all.sql root@slave3:/root

Master2配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 1.修改配置
vim /etc/my.cnf

[mysqld]
server_id=161
log_bin
gtid_mode=ON
enforce_gtid_consistency=1

# 2.重启
systemctl restart mysqld

# 3.导入数据
mysql -uroot -pBgx123.com -e "RESET MASTER;"
mysql -uroot -pBgx123.com < /root/2018-05-10-mysql-all.sql

# 4.验证远程账户是否可用
mysql -hmaster1 -urep -pRep123.com

# 5.登录数据库,清理从库的二进制日志
mysql> RESET MASTER;

# 6.指定master
mysql> CHANGE MASTER TO
-> MASTER_HOST='master1',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='Rep123.com',
-> MASTER_AUTO_POSITION=1;

# 7.启动slave角色
mysql> START SLAVE;

# 8.查看角色状态
mysql> SHOW SLAVE STATUS\G

配置Master1和Master2双向复制

在Master1上执行

1
2
3
4
5
6
7
8
9
mysql> FLUSH PRIVILEGES;
mysql> CHANGE MASTER TO
-> MASTER_HOST='master2',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='Rep123.com',
-> MASTER_AUTO_POSITION=1;

mysql> START SLAVE;
mysql> SHOW SLAVE STATUS\G

双主配置完成

Slave2和Slave3配置(多源复制)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1.修改配置
vim /etc/my.cnf

[mysqld]
server_id=162
gtid_mode=ON
enforce_gtid_consistency=1
# 多源复制必须配置
master-info-repository=TABLE
relay-log-info-repository=TABLE

# 2.重启数据库
systemctl restart mysqld

# 3.初始化数据库,导入数据
mysql -uroot -p'Bgx123.com' -e "RESET MASTER;"
mysql -uroot -p'Bgx123.com' < /root/2018-05-10-mysql-all.sql

# 4.清理二进制日志文件
mysql> RESET MASTER;

配置多源复制(使用Channel)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 指向Master1(使用channel区分)
mysql> CHANGE MASTER TO
-> MASTER_HOST='master1',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='Rep123.com',
-> MASTER_AUTO_POSITION=1
-> FOR CHANNEL 'master1-channel';

-- 指向Master2(使用channel区分)
mysql> CHANGE MASTER TO
-> MASTER_HOST='master2',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='Rep123.com',
-> MASTER_AUTO_POSITION=1
-> FOR CHANNEL 'master2-channel';

-- 启动所有channel的slave
mysql> START SLAVE;

-- 查看所有channel的状态
mysql> SHOW SLAVE STATUS\G

多源复制状态查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- 查看所有channel的状态
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: master1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: Master1-bin.000001
Read_Master_Log_Pos: 154
Relay_Log_File: slave2-relay-bin-master1@002dchannel.000002
Relay_Log_Pos: 371
Relay_Master_Log_File: Master1-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Channel_Name: master1-channel
*************************** 2. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: master2
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: Master2-bin.000001
Read_Master_Log_Pos: 154
Relay_Log_File: slave2-relay-bin-master2@002dchannel.000002
Relay_Log_Pos: 371
Relay_Master_Log_File: Master2-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Channel_Name: master2-channel

关键字段

  • Channel_Name:区分不同的复制通道

6. MySQL数据库读写分离

6.1 读写分离概述

读写分离是将写操作发送到主库,读操作发送到从库,从而提高系统整体性能。

实现方式

  • 应用层实现:在代码中区分读写
  • 中间件实现:使用MyCat、ProxySQL等中间件
  • MySQL Router:MySQL官方路由工具

6.2 使用MyCat实现读写分离

6.2.1 部署MyCat

MyCat是一个开源的数据库中间件,支持读写分离、分库分表等功能。

1. 安装Java环境
1
2
3
4
5
6
# MyCat依赖于Java环境
[root@Mycat ~]# yum install -y java
[root@Mycat ~]# java -version
openjdk version "1.8.0_161"
OpenJDK Runtime Environment (build 1.8.0_161-b14)
OpenJDK 64-Bit Server VM (build 25.161-b14, mixed mode)
2. 下载MyCat
1
2
3
4
5
6
7
8
# 创建目录
[root@Mycat ~]# mkdir /soft/

# 下载MyCat
[root@Mycat ~]# wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

# 解压
[root@Mycat ~]# tar xf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz -C /soft/

6.2.2 配置应用程序连接MyCat

1
2
# 编辑MyCat配置文件
[root@Mycat ~]# vim /soft/mycat/conf/server.xml

配置内容

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 应用连接mycat账户 -->
<user name="blog">
<!-- 应用连接mycat密码 -->
<property name="password">123456</property>
<!-- 针对哪个库进行授权 -->
<property name="schemas">blog</property>
</user>

<user name="www">
<property name="password">123456</property>
<property name="schemas">www</property>
</user>

说明

  • name:应用连接MyCat的用户名
  • password:应用连接MyCat的密码
  • schemas:授权的数据库名称

6.2.3 配置MyCat连接后端数据库

1
2
# 编辑schema.xml配置文件
[root@Mycat ~]# vim /soft/mycat/conf/schema.xml

配置内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

<!-- 链接mycat后的显示名称 -->
<schema name="blog" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>
<schema name="www" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn2"></schema>

<!-- dateNode数据节点 dataHost相当于主机池 -->
<dataNode name="dn1" dataHost="dn1pool" database="blog" />
<dataNode name="dn2" dataHost="dn2pool" database="www" />

<!-- 定义blog资源池限制 -->
<dataHost name="dn1pool" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<!-- 健康检查 -->
<heartbeat>SELECT user()</heartbeat>

<writeHost host="Master" url="192.168.70.160:3306" user="blog" password="Bgx123.com">
<readHost host="Slave1" url="192.168.70.161:3306" user="blog" password="Bgx123.com" />
<readHost host="Slave2" url="192.168.70.162:3306" user="blog" password="Bgx123.com" />
</writeHost>
</dataHost>

<!-- 定义www资源池限制 -->
<dataHost name="dn2pool" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<!-- 健康检查 -->
<heartbeat>SELECT user()</heartbeat>

<!-- 定义www库读写主机 -->
<writeHost host="Master" url="192.168.70.160:3306" user="www" password="Bgx123.com">
<readHost host="Slave1" url="192.168.70.161:3306" user="www" password="Bgx123.com" />
<readHost host="Slave2" url="192.168.70.162:3306" user="www" password="Bgx123.com" />
</writeHost>
</dataHost>

</mycat:schema>

balance负载均衡类型

balance值 说明
0 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上
1 所有的主机都参与select语句的负载均衡,但写语句还是由writeHost
2 所有读操作都随机的在writeHost、readhost上分发

推荐:使用balance="1",实现读写分离。

6.2.4 配置MySQL相关信息

在MySQL Master上操作

1
2
3
4
5
6
7
8
9
10
11
12
-- 创建数据库
mysql> CREATE DATABASE blog;
mysql> CREATE DATABASE www;

-- 创建测试表
mysql> CREATE TABLE blog.b(id INT);
mysql> CREATE TABLE www.w(id INT);

-- 授权用户
mysql> GRANT ALL ON www.* TO 'www'@'192.168.70.%' IDENTIFIED BY 'Bgx123.com';
mysql> GRANT ALL ON blog.* TO 'blog'@'192.168.70.%' IDENTIFIED BY 'Bgx123.com';
mysql> FLUSH PRIVILEGES;

6.2.5 启动MyCat中间件

1
2
3
4
5
6
7
8
9
10
11
12
# 启动MyCat
[root@Mycat ~]# /soft/mycat/bin/mycat start
Starting Mycat-server...

# 检查端口
[root@Mycat conf]# lsof -i :8066
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 5352 root 76u IPv6 52537 0t0 TCP *:8066 (LISTEN)

[root@Mycat conf]# lsof -i :9066
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 5352 root 72u IPv6 52535 0t0 TCP *:9066 (LISTEN)

端口说明

  • 8066:应用连接端口
  • 9066:管理端口

6.2.6 测试MyCat中间件

1
2
3
4
5
6
7
8
9
# 需要开启日志为debug可查看详细分离情况
[root@Mycat ~]# vim /soft/mycat/conf/log4j2.xml
<asyncRoot level="debug" includeLocation="true">

# 查看日志
[root@Mycat ~]# tail -f /soft/mycat/log/mycat.log |grep "222222"

# 连接MyCat
[root@Mycat ~]# mysql -h127.0.0.1 -P8066 -ublog -p123456

测试读写分离

1
2
3
4
5
6
-- 连接MyCat使用不规则语句插入与查询,便于查看策略
mysql> INSERT INTO blog.b VALUES (222222);
-- 写操作会发送到Master

mysql> SELECT * FROM blog.b WHERE id = '222222';
-- 读操作会发送到Slave(根据balance配置)

验证:通过日志可以看到读写操作分别发送到不同的数据库服务器。


7. MySQL数据库架构演变

7.1 架构演变历程

根据业务需求和技术发展,MySQL数据库架构经历了以下演变:

阶段1:单机架构

特点

  • 单台MySQL服务器
  • 所有读写操作都在一台服务器
  • 简单但存在单点故障

适用场景

  • 小型应用
  • 开发测试环境

阶段2:主从复制架构

特点

  • 一主一从
  • 主库负责读写
  • 从库用于备份

优势

  • 数据备份
  • 读写分离基础

阶段3:读写分离架构

特点

  • 一主一从
  • 主库负责写
  • 从库负责读

优势

  • 减轻主库压力
  • 提高读性能

阶段4:一主多从架构

特点

  • 一个主库,多个从库
  • 读操作分散到多个从库
  • 提高读性能和可用性

优势

  • 更高的读性能
  • 更好的可用性

阶段5:一主多从负载均衡

特点

  • 一主多从 + LVS+Keepalived
  • 使用负载均衡器分发读请求
  • 自动故障切换

优势

  • 高可用性
  • 负载均衡
  • 自动故障切换

阶段6:双主架构

特点

  • 两个主库互相复制
  • 高可用性
  • 支持双写(需注意冲突)

优势

  • 高可用性
  • 无单点故障

阶段7:双主双从架构

特点

  • 双主互相复制
  • 每个主库有独立的从库
  • 最高可用性和性能

优势

  • 最高可用性
  • 最高性能
  • 完善的容灾方案

7.2 架构选择建议

小型应用

推荐:主从复制架构

  • 成本低
  • 配置简单
  • 满足基本需求

中型应用

推荐:一主多从 + 读写分离

  • 性能提升明显
  • 成本适中
  • 可用性较好

大型应用

推荐:双主双从 + 负载均衡

  • 高可用性
  • 高性能
  • 完善的容灾

7.3 架构演进注意事项

1. 数据一致性

  • 主从复制存在延迟
  • 需要考虑最终一致性
  • 关键业务需要强一致性

2. 故障切换

  • 需要自动化故障切换
  • 使用Keepalived或MHA
  • 定期演练故障切换

3. 性能优化

  • 使用并行复制
  • 优化网络延迟
  • 合理配置从库数量

4. 监控告警

  • 监控复制延迟
  • 监控主从状态
  • 及时发现问题

8. 总结

8.1 主从复制的核心价值

  1. 数据备份:从库可以独立备份,不影响业务
  2. 高可用性:主库故障可以快速切换
  3. 读写分离:提高系统整体性能
  4. 负载均衡:分散读操作压力

8.2 复制方式选择

  1. 传统复制:适用于MySQL 5.6及以下
  2. GTID复制:推荐,MySQL 5.7+,配置简单
  3. 多源复制:数据汇总场景
  4. 双主复制:高可用性要求

8.3 架构师建议

  1. 优先使用GTID:简化配置和管理
  2. 合理规划架构:根据业务需求选择
  3. 监控复制状态:及时发现和解决问题
  4. 定期演练:测试故障切换流程
  5. 文档维护:记录架构和配置信息

8.4 主从复制检查清单

  • 主从复制是否正常
  • 复制延迟是否在可接受范围
  • 故障切换流程是否完善
  • 监控告警是否配置
  • 备份策略是否合理
  • 文档是否完整

相关文章