MySQL 主从复制与读写分离
一、整体架构概述
MyCat2 作为 MySQL 中间件,基于 MySQL 原生主从复制实现读写分离:
- 主库(Master):吃力所有写操作(insert / update / delete / DDL),通过 binlog 记录数据变更
- 从库(Slave):同构 I/O 线程拉取主库 binlog,SQL 线程重放实现数据同步,处理读请求
- MyCat2:自动路由 SQL,写操作发往主库,读操作分发至从库,提升系统吞吐量
二、环境准备(示例)
| 角色 | IP 地址 | 服务器 ID | MySQL 版本 | 说明 |
|---|---|---|---|---|
| 主库 | 192.168.1.100 | 1 | 8.0.x | 开启 binlog,可读写 |
| 从库 | 192.168.1.101 | 2 | 8.0.x | 开启 relay-log,只读 |
| MyCat2 | 192.168.1.102 | - | 1.21+ | 数据库中间件 |
三、MySQl 主从复制搭建
3.1 主库配置
-
修改
/etc/my.cnfini[mysqld] server-id=1 # 唯一ID,不可重复 log-bin=mysql-bin # 开启二进制日志 binlog-format=mixed # 混合模式(推荐) binlog-do-db=testdb # 需要同步的数据库 binlog-ignore-db=mysql # 忽略系统库 sync-binlog=1 # 每次事务提交同步binlog -
重启 MySQL 并创建复制用户:
bashsystemctl restart mysqld mysql -uroot -p # 创建复制用户 CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'Repl@123456'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES; # 查看主库状态(记录File和Position) SHOW MASTER STATUS\G
3.2 从库配置
-
修改
/etc/my.cnf:ini[mysqld] server-id=2 # 与主库不同 relay-log=mysql-relay-bin # 开启中继日志 read_only=1 # 普通用户只读(对super用户无效) log-slave-updates=1 # 从库同步后记录binlog(级联复制用) -
重启 MySQL 并配置主从复制:
bashsystemctl restart mysqld mysql -uroot -p # 配置主从连接 CHANGE MASTER TO MASTER_HOST='192.168.1.100', MASTER_USER='repl', MASTER_PASSWORD='Repl@123456', MASTER_LOG_FILE='mysql-bin.000001', # 主库SHOW MASTER STATUS结果 MASTER_LOG_POS=156; # 主库SHOW MASTER STATUS结果 # 启动复制并验证 START SLAVE; SHOW SLAVE STATUS\G # 确保以下状态为Yes # Slave_IO_Running: Yes # Slave_SQL_Running: Yes
四、MyCat 安装部署
4.1 安装依赖与下载
bash
# 安装JDK 11+(MyCat2需要)
yum install java-11-openjdk-devel -y
# 下载MyCat2安装包
cd /opt
wget http://dl.mycat.org.cn/2.0/install-template/mycat2-install-template-1.21.zip
wget http://dl.mycat.org.cn/2.0/1.21-release/mycat2-1.21-release-jar-with-dependencies.jar
# 解压并部署
unzip mycat2-install-template-1.21.zip
mv mycat2-1.21-release-jar-with-dependencies.jar mycat/lib/
chmod +x mycat/bin/*
4.2 基础配置
-
修改
mycat/conf/server.xml(设置用户与逻辑库):xml<mycat:server xmlns:mycat="http://io.mycat/"> <user name="mycat"> <property name="password">123456</property> <property name="schemas">testdb</property> <!-- 逻辑库名 --> </user> </mycat:server> -
启动 MyCat2:
bash# 初始化(首次启动) mycat/bin/mycat init # 启动/停止/状态 mycat/bin/mycat start mycat/bin/mycat stop mycat/bin/mycat status
五、MyCat2 读写分离配置(核心)
5.1 配置数据源(通过 MyCat2 SQL 命令)
连接 MyCat2 并执行以下 SQL 配置主从数据源:
sql
-- 连接MyCat2
mysql -umycat -p123456 -h127.0.0.1 -P8066
-- 创建主库数据源(READ_WRITE模式)
/*+ mycat:createDataSource{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"instanceType":"READ_WRITE",
"maxCon":1000,
"minCon":1,
"name":"master_ds",
"password":"123456",
"url":"jdbc:mysql://192.168.1.100:3306/testdb?useSSL=false&serverTimezone=UTC",
"user":"root"
} */;
-- 创建从库数据源(READ_ONLY模式)
/*+ mycat:createDataSource{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"instanceType":"READ_ONLY",
"maxCon":1000,
"minCon":1,
"name":"slave_ds",
"password":"123456",
"url":"jdbc:mysql://192.168.1.101:3306/testdb?useSSL=false&serverTimezone=UTC",
"user":"root"
} */;
5.2 配置集群与逻辑库
sql
-- 创建集群(主从模式)
/*+ mycat:createCluster{
"clusterType":"MASTER_SLAVE",
"heartbeat":"select user()",
"masters":["master_ds"], -- 主库数据源
"name":"my_cluster",
"readBalanceType":"BALANCE_ALL", -- 读负载均衡策略
"replicas":["slave_ds"], -- 从库数据源
"switchType":"SWITCH"
} */;
-- 创建逻辑库并关联集群
/*+ mycat:createSchema{
"customTables":{},
"defaultCluster":"my_cluster", -- 关联集群
"name":"testdb" -- 逻辑库名,与server.xml一致
} */;
5.3 负载均衡策略说明
| 策略名称 | 取值 | 说明 |
|---|---|---|
| BALANCE_ALL | 1 | 所有读请求分发到从库,从库不可用则用主库 |
| BALANCE_ALL_READ | 2 | 主库也参与读负载,从库优先 |
| BALANCE_SLAVE_FIRST | 3 | 优先从库,从库不可用才用主库 |
| MASTER_ONLY | 4 | 所有读写都走主库 (禁用读写分离) |
六、验证与测试
6.1 验证主从复制
-
在主库插入数据:
sqlmysql -uroot -p123456 -h192.168.1.100 USE testdb; CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20)); INSERT INTO users(name) VALUES('test1'),('test2'); -
在从库验证同步:
sqlmysql -uroot -p123456 -h192.168.1.101 USE testdb; SELECT * FROM users; -- 应显示刚插入的数据
6.2 验证读写分离
通过 MyCat2 连接并执行以下测试:
sql
-- 连接MyCat2
mysql -umycat -p123456 -h127.0.0.1 -P8066 -Dtestdb
-- 测试写操作(应路由到主库)
INSERT INTO users(name) VALUES('test3');
-- 测试读操作(应路由到从库)
SELECT @@server_id; -- 返回2(从库server-id)
-- 测试事务中的读(应路由到主库)
BEGIN;
SELECT @@server_id; -- 返回1(主库server-id)
COMMIT;
-- 测试写操作后立即读(应路由到主库,避免数据延迟)
INSERT INTO users(name) VALUES('test4');
SELECT * FROM users WHERE name='test4'; -- 路由到主库确保数据一致性
七、高级配置与优化
7.1 主从延迟配置
-
配置从库延迟阈值:
sql/*+ mycat:alterCluster{ "name":"my_cluster", "delayThreshold":3000 -- 延迟超过3秒的从库不参与读负载 } */; -
强制读主库的场景:
- 事务中的所有 SQL(自动路由到主库)
- 执行
/*+ mycat:db_type=master */ SELECT * FROM users强制读主库
7.2高可用配置
MyCat2 支持自动主从切换,示例:
sql
/*+ mycat:alterCluster{
"clusterType":"MASTER_SLAVE",
"heartbeat":"select 1", -- 心跳检测SQL
"masters":["master_ds"],
"name":"my_cluster",
"readBalanceType":"BALANCE_ALL",
"replicas":["slave_ds"],
"switchType":"AUTO_SWITCH", -- 自动切换模式
"switchThreshold":3 -- 连续3次心跳失败触发切换
} */;