从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

    • Redis

    • Mybatis

    • Lucene

    • Elasticsearch

    • MQ

    • MyCat

      • MyCat2-尚硅谷
      • MyCat 是什么,为什么要用
      • 搭建环境
      • MyCat 概念
      • MyCat 的配置文件
      • 一主一从复制
      • 一主一从读写分离
      • 双主双从复制方案
        • 环境说明
        • 配置 MySQL
        • 在 master 上创建用户并授权
        • 查询 Master 的状态
        • 配置 slave
        • 配置双主之间互相复制
        • 创建数据库
        • 修改 MyCat 的集群配置
        • 验证
        • 读写分离配置扩展
        • 常见问题
      • 分库分表
      • MyCat安全设置
      • Mycat2-UI
    • Lombok

  • SpringMVC

  • SpringBoot

  • Java
  • 主流框架
  • MyCat
2023-06-28
目录

双主双从复制方案

# 70.双主双从复制方案

接下来我们搭建双主双从的环境。 一个主机 m1 用于处理所有写请求,从机 s1,主机 m2 和 从机 s2 负责所有读请求。当 m1 主机宕机后,m2 主机负责写请求,m1、m2 互为备机:

对于 Java 应用而言,不需要关系哪个数据库是 master,哪个是从机,只需将请求发送到 MyCat 即可。 ‍

# 环境说明

这里说明下环境:

编号 角色 IP 地址 机器名
1 Master1 192.168.56.101 node1
2 Slave1 192.168.56.103 node2
3 Master2 192.168.56.104 node3
4 Slave2 192.168.56.105 node4

‍

# 配置 MySQL

在开始配置之前,由于我们还是打算使用 mydb1 来复制,因此可以先删除该数据库:

DROP DATABASE IF EXISTS mydb1;
1

# 配置 master1

/etc/my.conf:

#主服务器唯一ID
server-id=1


#启用二进制日志
log-bin=mysql-bin


# 设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
binlog-ignore-db=information_schema


#设置需要复制的数据库
binlog-do-db=mydb1


#设置logbin格式
binlog_format=STATEMENT


# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates


#表示自增长字段每次递增的量,指自增字段的起始值,其默认值是1,取值范围是 1 .. 65535
auto-increment-increment=2


# 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1 .. 65535
auto-increment-offset=1
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

‍ 和之前的配置相比,主要是多了后续的 3 个配置。

为什么作为从机时,也要写入日志:这是因为 master1 有可能宕机,恢复后就会作为从机,此时也需要写入日志,这样 slave1 才能读取到写入的操作。

为什么自增长量设置为 2:因为有两个 master,想要区分开来。然后下一行设置从 1 开始自增,这样数字就是 1,3,5,7,9....

# 配置 master2

#主服务器唯一ID
server-id=3


#启用二进制日志
log-bin=mysql-bin


# 设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
binlog-ignore-db=information_schema


#设置需要复制的数据库
binlog-do-db=mydb1


#设置logbin格式
binlog_format=STATEMENT


# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates


#表示自增长字段每次递增的量,指自增字段的起始值,其默认值是1,取值范围是 1 .. 65535
auto-increment-increment=2


# 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1 .. 65535
auto-increment-offset=2
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

注意 server-id 要修改。注意,自增的时候我们从 2 开始,这样数字就是 2,4,6,8.....

# 配置从机

从机的配置就比较简单了,例如 slave1:

#从服务器唯一ID
server-id=2


#启用中继日志
relay-log=mysql-relay
1
2
3
4
5
6

slave2:注意 server-id 要改

#从服务器唯一ID
server-id=4


#启用中继日志
relay-log=mysql-relay
1
2
3
4
5
6

‍

# 重启 MySQL

我们重启每台机器上的 MySQL 服务:systemctl restart mysqld

重启完后记得检查下是否正常:systemctl status mysqld

注意检查防火墙是否开放了端口,或者直接关闭防火墙 ‍

# 在 master 上创建用户并授权

为了方便区分,我们在两个 master 上新建一个用户:

create user 'slave2'@'%' identified by 'Mycat0520@';
ALTER USER slave2@'%' IDENTIFIED WITH mysql_native_password BY 'Mycat0520@';

grant replication slave on *.* to 'slave2'@'%';
flush privileges;
1
2
3
4
5

‍

# 查询 Master 的状态

查询 master1 的状态:

mysql> show master STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |     157  | mydb1        |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
1
2
3
4
5
6
7

‍ master2:

mysql> show master STATUS;
+------------------+----------+--------------+--------------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB         | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+-------------------+
| mysql-bin.000001 |     1157 | mydb1        | mysql,information_schema |                   |
+------------------+----------+--------------+--------------------------+-------------------+
1 row in set (0.00 sec)
1
2
3
4
5
6
7

分别记录下 File 和 Position 的值。执行完此步骤后不要再操作 MYSQL,防止主服务器状态值变化

# 配置 slave

配置 Slava1 复制 Master1,Slava2 复制 Master2,配置的格式:

CHANGE MASTER TO MASTER_HOST='主机的IP地址',
MASTER_USER='用户名',
MASTER_PASSWORD='密码',
MASTER_LOG_FILE='binlog文件名', 
MASTER_LOG_POS='position的值';  
1
2
3
4
5

我们在 slave1 上执行:

CHANGE MASTER TO MASTER_HOST='192.168.56.101',
MASTER_USER='slave2',
MASTER_PASSWORD='Mycat0520@',
MASTER_LOG_FILE='mysql-bin.000001', 
MASTER_LOG_POS=157;
1
2
3
4
5

‍ 在 slave2 上执行:

CHANGE MASTER TO MASTER_HOST='192.168.56.104',
MASTER_USER='slave2',
MASTER_PASSWORD='Mycat0520@',
MASTER_LOG_FILE='mysql-bin.000001', 
MASTER_LOG_POS=1157;
1
2
3
4
5

然后开启复制,在两台 slave 上都执行:

start slave;
1

‍ 检查状态:

show slave status\G;
1

‍ 如果下面两个参数都是 Yes,则说明主从配置成功

# Slave_IO_Running: Yes
# Slave_SQL_Running: Yes
1
2

‍

# 配置双主之间互相复制

现在我们搭建好了 Master1 和 slave1 之间的复制,以及 Master2 和 slave2 之间的复制,还差两个 master 之间的复制了:

‍

配置 Master2 复制 Master1,在 Master2 中执行:

CHANGE MASTER TO MASTER_HOST='192.168.56.101',
MASTER_USER='slave2',
MASTER_PASSWORD='Mycat0520@',
MASTER_LOG_FILE='mysql-bin.000001', 
MASTER_LOG_POS=157;
1
2
3
4
5

‍ 配置 Master1 复制 Master2,在 Master1 中执行:

CHANGE MASTER TO MASTER_HOST='192.168.56.104',
MASTER_USER='slave2',
MASTER_PASSWORD='Mycat0520@',
MASTER_LOG_FILE='mysql-bin.000001', 
MASTER_LOG_POS=1157;
1
2
3
4
5

然后在两个 master 上开始复制:start slave;

start slave;
1

‍ 查看状态:show slave status\G; ‍

# 创建数据库

此时我们配置好后,就可以创建数据库和表了:

create database mydb1;
use mydb1;
CREATE TABLE mytbl (id INT, NAME VARCHAR(50));
INSERT INTO mytbl VALUES (1, "zhang3");
1
2
3
4

‍ 然后我们可以在其他 MySQL 上查看是否有数据:

 select * from mytbl;
1

‍

# 修改 MyCat 的集群配置

明确角色划分:m1 主机,m2 备机(也负责读),s1 从机,s2 从机

增加 m2 和 s2 两个数据源:

/*+ mycat:createDataSource{ "name":"rwSepw2","url":"jdbc:mysql://192.168.56.104:3306/mydb1?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true", "user":"root","password":"Mycat0520@" } */;

/*+ mycat:createDataSource{ "name":"rwSepr2","url":"jdbc:mysql://192.168.56.105:3306/mydb1?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true", "user":"root","password":"Mycat0520@" } */;
1
2
3

‍ 可以看到 MyCat 也多了 2 个配置文件:

ll /usr/local/mycat/conf/datasources
总用量 20
-rw-r--r--. 1 root root 436 6月  19 21:17 prototypeDs.datasource.json
-rw-r--r--. 1 root root 576 6月  21 07:50 rwSepr2.datasource.json
-rw-r--r--. 1 root root 575 6月  20 07:32 rwSepr.datasource.json
-rw-r--r--. 1 root root 576 6月  21 07:50 rwSepw2.datasource.json
-rw-r--r--. 1 root root 575 6月  20 07:24 rwSepw.datasource.json
1
2
3
4
5
6
7

‍ 之前我们已经配置好了逻辑库,现在只需修改集群的信息。

配置文件:/usr/local/mycat/conf/clusters/prototype.cluster.json,修改后:

{
        "clusterType":"MASTER_SLAVE",
        "heartbeat":{
                "heartbeatTimeout":1000,
                "maxRetryCount":3,
                "minSwitchTimeInterval":300,
                "showLog":false,
                "slaveThreshold":0.0
        },
        "masters":[
                "rwSepw","rwSepw2"
        ],
        "maxCon":2000,
        "name":"prototype",
        "readBalanceType":"BALANCE_ALL",
        "replicas":[
                "rwSepr","rwSepr2","rwSepw2"
        ],
        "switchType":"SWITCH"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

‍ 我们主要修改了第 11 行(增加了 master),和第 17 行(增加了 m2 和 s2,也负责读请求)。然后我们重启 MyCat:

cd /usr/local/mycat/bin
./mycat restart
1
2

最好也检查下重启的日志

然后可以查看集群信息,可以看到有新增的数据源:

/*+ mycat:showClusters{} */;
1

# 验证

同理,我们 insert 一个主机名,使得每个数据库的数据不一样:

INSERT INTO mytbl VALUES(2, @@hostname);
1

‍ 然后查询多次,可以看到是轮流查询每个数据库的数据

# 读写分离配置扩展

通过对集群配置的修改,可以根据需求实现更多种情况的读写分离配置,总结如下 ‍ (1)读写分离(一主一从,无备,m 是主,s 是从)

{
    "clusterType":"MASTER_SLAVE",
    "heartbeat":{
        "heartbeatTimeout":1000,
        "maxRetryCount":3,
        "minSwitchTimeInterval":300,
        "slaveThreshold":0
    },
    "masters":[
        "m"
    ],
    "replicas":[
        "s"
    ],
    "maxCon":200,
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL",
    "switchType":"SWITCH" ,
    "timer":{
        "initialDelay": 30,
        "period":5,
        "timeUnit":"SECONDS"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

‍ (2)读写分离(一主一从,一备,m 是主,s 是从备)

{
    "clusterType":"MASTER_SLAVE",
    "heartbeat":{
        "heartbeatTimeout":1000,
        "maxRetryCount":3,
        "minSwitchTimeInterval":300,
        "slaveThreshold":0
    },
    "masters":[
        "m","s"
    ],
    "replicas":[
        "s"
    ],
    "maxCon":200,
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL",
    "switchType":"SWITCH" ,
    "timer":{
        "initialDelay": 30,
        "period":5,
        "timeUnit":"SECONDS"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

(3)读写分离(一主一从一备,m 是主,s 是从,b 是备)

{
    "clusterType":"MASTER_SLAVE",
    "heartbeat":{
        "heartbeatTimeout":1000,
        "maxRetryCount":3,
        "minSwitchTimeInterval":300,
        "slaveThreshold":0
    },
    "masters":[
        "m","b"
    ],
    "replicas":[
        "s"
    ],
    "maxCon":200,
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL",
    "switchType":"SWITCH" ,
    "timer":{
        "initialDelay": 30,
        "period":5,
        "timeUnit":"SECONDS"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

(4)MHA(一主一从一备)(m 是主,s 是从,b 是备,READ_ONLY 判断主)

{
    "clusterType":"MHA",
    "heartbeat":{
        "heartbeatTimeout":1000,
        "maxRetryCount":3,
        "minSwitchTimeInterval":300,
        "slaveThreshold":0
    },
    "masters":[
        "m","b"
    ],
    "replicas":[
        "s"
    ],
    "maxCon":200,
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL",
    "switchType":"SWITCH" ,
    "timer":{
        "initialDelay": 30,
        "period":5,
        "timeUnit":"SECONDS"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

‍ (5)MGR(一主一从一备)(m 是主, s 是从, b 是备, READ_ONLY 判断主)

{
    "clusterType":"MGR",
    "heartbeat":{
        "heartbeatTimeout":1000,
        "maxRetryCount":3,
        "minSwitchTimeInterval":300,
        "slaveThreshold":0
    },
    "masters":[
        "m","b"
    ],
    "replicas":[
        "s"
    ],
    "maxCon":200,
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL",
    "switchType":"SWITCH" ,
    "timer":{
        "initialDelay": 30,
        "period":5,
        "timeUnit":"SECONDS"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

(6)GARELA_CLUSTER(一主一从,一备,m 是主,s 是从,b 多主)

{
    "clusterType":"GARELA_CLUSTER",
    "heartbeat":{
        "heartbeatTimeout":1000,
        "maxRetryCount":3,
        "minSwitchTimeInterval":300,
        "slaveThreshold":0
    },
    "masters":[
        "m","b"
    ],
    "replicas":[
        "s"
    ],
    "maxCon":200,
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL",
    "switchType":"SWITCH" ,
    "timer":{
        "initialDelay": 30,
        "period":5,
        "timeUnit":"SECONDS"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

‍

# 常见问题

‍

# UUIDs

Last_IO_Error: Fatal error: The replica I/O thread stops because source and replica have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
1

‍ 原因:在 mysql 5.6 的复制引入了 uuid 的概念,主从的 server_uuid 得保证不一样。可以通过以下语句查询:

show variables like 'server_uuid';
1

而由于我的从机是直接用虚拟机复制的方式生成的,导致一样。 ‍ 解决方法:文件 /var/lib/mysql/auto.cnf 里存储了 UUID,我们修改里面的内容,和另一个 UUID 不同即可。

修改完后记得重启,然后再次查询下 UUID。 ‍

上次更新: 2025/5/17 12:26:09
一主一从读写分离
分库分表

← 一主一从读写分离 分库分表→

最近更新
01
语雀文档一键下载至本地教程
07-04
02
要成功,就不要低估环境对你的影响
07-03
03
血泪教训:电子设备要定期开机
07-02
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式