如何在Mycat中配置主从复制?

首先要明确核心结论:Mycat 不负责实现主从复制,仅依赖 MySQL 自身的主从复制机制,再通过 Mycat 配置将读请求转发到从库、写请求转发到主库(即读写分离)。
之前的对话中已经提到:Mycat 是数据库中间件,作用是「请求路由」,而非「数据同步」。数据同步(主从复制)的核心是 MySQL 自身的功能,Mycat 只需要感知主从节点的存在,就能实现读写分离。
因此,你问的「Mycat 中配置主从复制」,本质是 「先搭建 MySQL 主从复制(数据同步),再在 Mycat 中配置主从节点关联(请求路由)」 。以下是完整的分步实操(基于 CentOS 环境,MySQL 8.0 + Mycat 1.6.x):

一、核心前提:先搭建 MySQL 主从复制(数据同步核心)

Mycat 读写分离的基础是「主从数据一致」,必须先让 MySQL 主库和从库完成数据同步,Mycat 仅负责转发请求。

环境准备

  • 主库(Master):IP 192.168.1.101,MySQL 8.0,数据库 db1
  • 从库(Slave):IP 192.168.1.103,MySQL 8.0,数据库 db1(需手动创建,与主库同名)
  • 主从库网络互通,关闭防火墙或开放 3306 端口(MySQL 通信端口)

步骤 1:配置主库(Master)

1. 编辑 MySQL 配置文件

bash
运行
# CentOS 8+ 编辑 MySQL 配置(不同系统路径可能为 /etc/my.cnf)
vim /etc/my.cnf.d/mysql-server.cnf
在 [mysqld] 节点下添加以下配置(开启二进制日志,指定主库唯一 ID):
ini
[mysqld]
server-id = 101  # 主库唯一 ID(1-2^32-1,不能与从库重复)
log-bin = mysql-bin  # 开启二进制日志(主从复制的核心,记录所有写操作)
binlog-do-db = db1  # 仅同步 db1 数据库(按需配置,不写则同步所有库)
binlog-ignore-db = mysql  # 忽略同步系统库(可选)
expire_logs_days = 7  # 二进制日志保留 7 天(避免占用磁盘)

2. 重启主库并验证配置

bash
运行
# 重启 MySQL 服务
systemctl restart mysqld

# 登录主库 MySQL,验证配置是否生效
mysql -uroot -p
mysql> show variables like 'server_id';  # 结果应为 101
mysql> show variables like 'log_bin';    # 结果应为 ON

3. 主库创建复制用户并授权

从库需要通过该用户连接主库同步数据:
sql
-- 主库执行(创建复制用户 repl,允许从库访问)
CREATE USER 'repl'@'192.168.1.103' IDENTIFIED BY 'Repl123!';  # 仅允许从库 IP 连接
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.103';     # 授予复制权限
FLUSH PRIVILEGES;  # 刷新权限

-- 查看主库状态(记录 File 和 Position 值,从库配置需用)
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      156 | db1          | mysql            |                   |
+------------------+----------+--------------+------------------+-------------------+
  • 注意:记录 File(如 mysql-bin.000001)和 Position(如 156),后续从库配置需要用到。

步骤 2:配置从库(Slave)

1. 编辑 MySQL 配置文件

bash
运行
vim /etc/my.cnf.d/mysql-server.cnf
在 [mysqld] 节点下添加以下配置(指定从库唯一 ID,开启中继日志):
ini
[mysqld]
server-id = 103  # 从库唯一 ID(与主库不同)
relay-log = relay-bin  # 开启中继日志(从库同步主库日志的临时文件)
replicate-do-db = db1  # 仅同步 db1 数据库(与主库一致)
replicate-ignore-db = mysql  # 忽略同步系统库(可选)
read_only = 1  # 从库设为只读(避免直接写从库,root 用户除外)

2. 重启从库并验证配置

bash
运行
systemctl restart mysqld

# 登录从库 MySQL,验证配置
mysql -uroot -p
mysql> show variables like 'server_id';  # 结果应为 103
mysql> show variables like 'relay_log';  # 结果应为 ON

3. 从库配置主库信息并启动同步

sql
-- 从库执行(停止之前的同步进程,首次配置可跳过)
mysql> stop slave;

-- 配置主库信息(替换为实际主库 IP、复制用户、日志文件和位置)
mysql> change master to
  master_host='192.168.1.101',        # 主库 IP
  master_user='repl',                  # 主库创建的复制用户
  master_password='Repl123!',          # 复制用户密码
  master_log_file='mysql-bin.000001',  # 主库 show master status 中的 File
  master_log_pos=156;                  # 主库 show master status 中的 Position

-- 启动从库同步
mysql> start slave;

-- 验证主从同步状态(核心:Slave_IO_Running 和 Slave_SQL_Running 均为 Yes)
mysql> show slave status\G;
  • 关键验证项:
    • Slave_IO_Running: Yes(从库 IO 线程正常,能连接主库并读取二进制日志)
    • Slave_SQL_Running: Yes(从库 SQL 线程正常,能执行中继日志中的 SQL)
  • 若为 No,查看 Last_IO_Error 或 Last_SQL_Error 字段排查原因(如密码错误、日志文件 / 位置错误、主从数据不一致)。

4. 验证主从复制效果

在主库 db1 中创建表并插入数据,查看从库是否同步:
sql
-- 主库执行(创建表 + 插入数据)
use db1;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO user (id, name, age) VALUES (1, '张三', 20);

-- 从库执行(查询数据,确认同步成功)
use db1;
select * from user;  # 应能看到 id=1 的「张三」记录

二、Mycat 配置:关联主从节点(实现读写分离)

MySQL 主从复制搭建完成后,Mycat 只需配置「主库(写节点)」和「从库(读节点)」,即可实现读写分离(写请求走主库,读请求走从库)。

步骤 1:修改 Mycat 核心配置文件(schema.xml)

bash
运行
vim /usr/local/mycat/conf/schema.xml
配置逻辑库、分片、主从节点关联,核心是 balance="1"(开启读写分离)和 readHost(关联从库):
xml
<?xml version="1.0" encoding="UTF-8"?>
<mycat:schema xmlns:mycat="http://io.mycat/">
  <!-- 逻辑库:应用连接的虚拟库 -->
  <schema name="mycat_db" checkSQLschema="false" sqlMaxLimit="100">
    <!-- 逻辑表:关联到主从库所在的分片 dn1 -->
    <table name="user" dataNode="dn1" primaryKey="id" />
  </schema>

  <!-- 分片:对应真实数据库(主从库的 db1) -->
  <dataNode name="dn1" dataHost="host1" database="db1" />

  <!-- 主从节点配置(核心) -->
  <dataHost name="host1"
            maxCon="1000" minCon="10"
            balance="1"  <!-- 开启读写分离:读请求转发到从库 -->
            writeType="0"  <!-- 写请求转发到第一个可用的 writeHost(主库) -->
            dbType="mysql" dbDriver="native">
    <!-- 心跳检测:确保数据库存活 -->
    <heartbeat>select 1</heartbeat>

    <!-- 主库配置(writeHost:负责写请求) -->
    <writeHost host="master-101"
               url="192.168.1.101:3306"
               user="mycat"  <!-- Mycat 连接主库的用户(之前创建的 mycat/123456) -->
               password="123456">
      <!-- 从库配置(readHost:负责读请求,关联到父 writeHost) -->
      <readHost host="slave-103"
                url="192.168.1.103:3306"
                user="mycat"  <!-- Mycat 连接从库的用户(需在从库授权) -->
                password="123456" />
    </writeHost>
  </dataHost>
</mycat:schema>

步骤 2:从库授权 Mycat 访问

Mycat 需要连接从库执行读请求,需在从库创建 Mycat 连接用户并授权:
sql
-- 从库执行(授权 Mycat 连接)
GRANT ALL ON *.* TO 'mycat'@'%' IDENTIFIED BY '123456';
FLUSH PRIVILEGES;

步骤 3:重启 Mycat 并验证

bash
运行
# 停止 Mycat(若已启动)
/usr/local/mycat/bin/mycat stop

# 前台启动 Mycat(查看日志,确认无报错)
/usr/local/mycat/bin/mycat console
  • 启动成功标志:日志中出现 Mycat Server startup successfully

三、验证 Mycat 读写分离效果

步骤 1:连接 Mycat 执行读写操作

bash
运行
# 用 MySQL 客户端连接 Mycat(8066 端口)
mysql -h127.0.0.1 -umycat_app -p123456 -P8066

# 切换到逻辑库
use mycat_db;

# 1. 写操作(INSERT:Mycat 转发到主库)
INSERT INTO user (id, name, age) VALUES (2, '李四', 22);

# 2. 读操作(SELECT:Mycat 转发到从库)
SELECT * FROM user;

步骤 2:确认请求分发正确

1. 验证写请求走主库

登录主库,查看 MySQL 日志,确认有 INSERT 操作:
sql
-- 主库执行(开启通用日志,临时查看)
set global general_log = on;
set global log_output = 'table';  # 日志写入 mysql.general_log 表

-- 查询写操作日志
select * from mysql.general_log where argument like '%INSERT INTO user%';
  • 结果:能看到 Mycat 转发的 INSERT 请求(用户为 mycat_app)。

2. 验证读请求走从库

登录从库,查看日志,确认有 SELECT 操作:
sql
-- 从库执行(开启通用日志)
set global general_log = on;
set global log_output = 'table';

-- 查询读操作日志
select * from mysql.general_log where argument like '%SELECT * FROM user%';
  • 结果:能看到 Mycat 转发的 SELECT 请求(主库日志无该 SELECT 记录)。

3. 验证数据一致性

从库执行查询,确认主库的 INSERT 数据已同步:
sql
-- 从库执行
use db1;
select * from user;  # 应能看到 id=2 的「李四」记录(主从复制生效)

四、常见问题排查

1. MySQL 主从同步失败(Slave_IO_Running=No)

  • 原因:主库 IP / 端口错误、复制用户密码错误、主库防火墙未开放 3306 端口。
  • 解决方案:
    • 验证从库能否 ping 通主库:ping 192.168.1.101
    • 验证从库能否连接主库复制用户:mysql -urepl -pRepl123! -h192.168.1.101 -P3306
    • 主库开放 3306 端口:firewall-cmd --permanent --add-port=3306/tcp && firewall-cmd --reload

2. MySQL 主从同步失败(Slave_SQL_Running=No)

  • 原因:主从库数据不一致(如主库已存在表,从库无)、SQL 语法不兼容。
  • 解决方案:
    • 备份主库 db1 并导入从库:mysqldump -uroot -p db1 > db1.sql(主库),mysql -uroot -p db1 < db1.sql(从库)。
    • 从库执行 stop slave; reset slave; 后,重新执行 change master to ... 配置。

3. Mycat 读请求仍走主库

  • 原因:schema.xml 中 balance 参数配置错误(如 balance="0",未开启读写分离)。
  • 解决方案:确认 balance="1"(读请求转发到从库),重启 Mycat。

4. Mycat 连接从库失败

  • 原因:从库未授权 Mycat 用户、从库 3306 端口未开放、从库 MySQL 未启动。
  • 解决方案:
    • 从库重新授权 Mycat 用户:GRANT ALL ON *.* TO 'mycat'@'%' IDENTIFIED BY '123456';
    • 开放从库 3306 端口:firewall-cmd --permanent --add-port=3306/tcp && firewall-cmd --reload

核心总结

  1. Mycat 不实现主从复制,仅依赖 MySQL 自身的主从复制保证数据一致,Mycat 负责「请求路由」(写主读从)。
  2. 配置流程:先搭 MySQL 主从复制(数据同步)→ 再配置 Mycat 关联主从节点(读写分离)。
  3. 关键验证点:MySQL 主从同步状态(两个 Yes)、Mycat 读写请求分发正确(写主读从)。
按照以上步骤,即可完成「MySQL 主从复制 + Mycat 读写分离」的完整配置,实现系统并发能力提升~
阅读剩余
THE END