Mycat 读写分离 - 双主双从
双主双从:Master1 写、Master2 备,两台主库互为主备;S1、S2 与备用的 M2 一起分担读请求。主库宕机后由另一台主库接管写,靠
switchType自动切换。
一、架构介绍
一个主机 Master1 用于处理所有写请求,它的从机 Slave1 和另一台主机 Master2 还有它的从机 Slave2 负责所有读请求。当 Master1 主机宕机后,Master2 主机负责写请求,Master1、Master2 互为主备。
┌── M1 ──复制──▶ S1 (主)
应用程序 ─▶ MyCat ┤ ↕ 复制(互为主备)
└── M2 ──复制──▶ S2 (备)
| 特点 | 说明 |
|---|---|
| 写 | 平时只有 Master1 承担写 |
| 读 | S1、S2,以及备用的 M2 都可参与 |
| 故障 | Master1 挂掉后,Master2 接管写 |
二、准备工作
需要准备 5 台服务器:
| 编号 | 地址(示例) | 预装软件 | 角色 |
|---|---|---|---|
| 1 | 1.2.3.4 | MyCat、MySQL | MyCat 中间件服务器 |
| 2 | 1.2.3.5 | MySQL | M1 |
| 3 | 1.2.3.6 | MySQL | S1 |
| 4 | 1.2.3.7 | MySQL | M2 |
| 5 | 1.2.3.8 | MySQL | S2 |
关闭以上所有服务器的防火墙:
systemctl stop firewalld
systemctl disable firewalld
三、搭建
3.1 主库配置
Master1(1.2.3.5) 修改 /etc/my.cnf:
# mysql 服务 ID,保证整个集群环境中唯一,取值范围 1 ~ 2^32-1,默认为 1
server-id=1
# 指定同步的数据库
binlog-do-db=db01
binlog-do-db=db02
binlog-do-db=db03
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
Master2(1.2.3.7) 修改 /etc/my.cnf:
# 服务 ID 与 Master1 不同
server-id=3
binlog-do-db=db01
binlog-do-db=db02
binlog-do-db=db03
# 作为从库时,写入也要更新二进制日志
log-slave-updates
两台主库都要重启:
systemctl restart mysqld
log-slave-updates是双主互备的关键:M2 从 M1 复制来的写操作,还要再写进自己的 binlog,才能继续传给 S2(以及反向复制)。
3.2 从库配置
Slave1(1.2.3.6):
server-id=2
Slave2(1.2.3.8):
server-id=4
重启 MySQL:
systemctl restart mysqld
四台机器的
server-id必须互不相同。
3.3 两台主库创建账户并授权
在两台主库上分别执行:
-- 创建 itcast 用户,可在任意主机连接
CREATE USER 'itcast'@'%' IDENTIFIED WITH mysql_native_password BY '你的密码';
-- 分配主从复制权限
GRANT REPLICATION SLAVE ON *.* TO 'itcast'@'%';
查看两台主库的二进制日志坐标:
SHOW MASTER STATUS;
记下各自的
File与Position,下一步配置从库时要用到。
3.4 两台从库配置关联的主库
CHANGE MASTER TO
MASTER_HOST='主库地址',
MASTER_USER='itcast',
MASTER_PASSWORD='你的密码',
MASTER_LOG_FILE='binlog.000002',
MASTER_LOG_POS=1383;
| 从库 | 对应主库 |
|---|---|
| Slave1 | Master1 |
| Slave2 | Master2 |
注意 slave1 对应的是 master1,slave2 对应的是 master2,不要配反。
启动主从复制并查看状态:
START SLAVE;
SHOW SLAVE STATUS\G
3.5 两台主库相互复制
Master2 复制 Master1,Master1 复制 Master2:在两台主库上分别执行 CHANGE MASTER TO,指向对方。
CHANGE MASTER TO
MASTER_HOST='对方主库地址',
MASTER_USER='itcast',
MASTER_PASSWORD='你的密码',
MASTER_LOG_FILE='binlog.000002',
MASTER_LOG_POS=1383;
START SLAVE;
SHOW SLAVE STATUS\G
MySQL 8.0.23+ 可使用
CHANGE REPLICATION SOURCE TO/START REPLICA,参数名对应SOURCE_*,见 主从复制 - 搭建。
3.6 测试主从同步
分别在两台主库 Master1、Master2 上执行 DDL、DML 语句,查看涉及到的数据库服务器的数据同步情况:
CREATE DATABASE db01;
USE db01;
CREATE TABLE tb_user(
id INT(11) NOT NULL PRIMARY KEY,
name VARCHAR(50) NOT NULL,
sex VARCHAR(1)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO tb_user(id, name, sex) VALUES (1, 'Tom', '1');
INSERT INTO tb_user(id, name, sex) VALUES (2, 'Trigger', '0');
INSERT INTO tb_user(id, name, sex) VALUES (3, 'Dawn', '1');
INSERT INTO tb_user(id, name, sex) VALUES (4, 'Jack Ma', '1');
INSERT INTO tb_user(id, name, sex) VALUES (5, 'Coco', '0');
INSERT INTO tb_user(id, name, sex) VALUES (6, 'Jerry', '1');
在 M1 写入后,S1、M2、S2 都应能查到;在 M2 写入后,S2、M1、S1 也应同步。
四、双主双从读写分离配置
Mycat 控制后台数据库的读写分离和负载均衡由 schema.xml 文件 dataHost 标签的 balance 属性控制,通过 writeType 及 switchType 来完成失败自动切换。
<schema name="ITCAST_RW2" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn7">
<!-- <table name="tb_user" dataNode="dn7" primaryKey="id" /> -->
</schema>
<dataNode name="dn7" dataHost="dhost7" database="db01" />
<dataHost name="dhost7" maxCon="1000" minCon="10" balance="1"
writeType="0" switchType="1" dbType="mysql" dbDriver="jdbc">
<heartbeat>select user()</heartbeat>
<writeHost host="master1" url="jdbc:mysql://1.2.3.5:3306?useSSL=false"
user="root" password="你的密码">
<readHost host="slave1" url="jdbc:mysql://1.2.3.6:3306?useSSL=false"
user="root" password="你的密码" />
</writeHost>
<writeHost host="master2" url="jdbc:mysql://1.2.3.7:3306?useSSL=false"
user="root" password="你的密码">
<readHost host="slave2" url="jdbc:mysql://1.2.3.8:3306?useSSL=false"
user="root" password="你的密码" />
</writeHost>
</dataHost>
server.xml 中加上逻辑库:
<user name="root" defaultAccount="true">
<property name="password">你的密码</property>
<property name="schemas">SHOPPING,ITCAST,ITCAST_RW2</property>
</user>
4.1 balance
balance="1":代表全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡。
简单说,当双主双从模式(M1 → S1,M2 → S2,并且 M1 与 M2 互为主备),正常情况下,M2、S1、S2 都参与 select 语句的负载均衡。
4.2 writeType
| 取值 | 含义 |
|---|---|
0 | 写操作都转发到第 1 台 writeHost,writeHost1 挂了,会切换到 writeHost2 上 |
1 | 所有的写操作都随机地发送到配置的 writeHost 上 |
4.3 switchType
| 取值 | 含义 |
|---|---|
-1 | 不自动切换 |
1 | 自动切换 |
五、测试
登录 MyCat,测试查询及更新操作,判定是否能够进行读写分离,以及读写分离的策略是否正确:
-- 写:默认走 master1;master1 挂掉后应切到 master2
INSERT INTO tb_user(id, name, sex) VALUES (7, 'Alice', '0');
-- 读:参与负载均衡的是 M2、S1、S2
SELECT * FROM tb_user WHERE id = 7;
再验证当主库挂掉一个之后,是否能够自动切换。
速查
<!-- schema.xml:双主双从 -->
<dataNode name="dn7" dataHost="dhost7" database="db01" />
<dataHost name="dhost7" maxCon="1000" minCon="10" balance="1"
writeType="0" switchType="1" dbType="mysql" dbDriver="jdbc">
<heartbeat>select user()</heartbeat>
<writeHost host="master1" url="jdbc:mysql://1.2.3.5:3306"
user="root" password="你的密码">
<readHost host="slave1" url="jdbc:mysql://1.2.3.6:3306"
user="root" password="你的密码" />
</writeHost>
<writeHost host="master2" url="jdbc:mysql://1.2.3.7:3306"
user="root" password="你的密码">
<readHost host="slave2" url="jdbc:mysql://1.2.3.8:3306"
user="root" password="你的密码" />
</writeHost>
</dataHost>
# M1 /etc/my.cnf
server-id=1
binlog-do-db=db01
log-slave-updates
# S1
server-id=2
# M2
server-id=3
binlog-do-db=db01
log-slave-updates
# S2
server-id=4
-- 两台主库建复制账号
CREATE USER 'itcast'@'%' IDENTIFIED WITH mysql_native_password BY '你的密码';
GRANT REPLICATION SLAVE ON *.* TO 'itcast'@'%';
-- 从库指向各自主库;两台主库再相互指向对方
CHANGE MASTER TO
MASTER_HOST='主库地址',
MASTER_USER='itcast',
MASTER_PASSWORD='你的密码',
MASTER_LOG_FILE='binlog.000002',
MASTER_LOG_POS=1383;
START SLAVE;
SHOW SLAVE STATUS\G
| 参数 | 作用 |
|---|---|
balance="1" | 所有 readHost + 备用 writeHost 参与读负载均衡 |
writeType="0" | 写第 1 台,挂了切第 2 台 |
switchType="1" | 主库故障自动切换 |
log-slave-updates | 从库写入也记 binlog,双主互备必需 |
相关
- Mycat 读写分离 - 一主一从:
writeHost/readHost基础配置 - 主从复制 - 搭建:
CHANGE REPLICATION SOURCE与状态检查 - Mycat 配置:
dataHost属性全表 - Mycat 管理与监控:查看数据源与集群状态