Mycat 读写分离配置实战(CentOS 环境)

Mycat 读写分离的核心逻辑是:写请求(INSERT/UPDATE/DELETE)转发到主库(writeHost),读请求(SELECT)转发到从库(readHost),应用无需修改代码,仅需通过 Mycat 配置实现流量分发,从而提升系统并发能力。
以下基于之前的 Mycat 入门环境,详细讲解「一主一从」架构的读写分离配置(最常用场景),包含「主从复制准备→Mycat 配置→验证效果」全流程。

一、前置条件(必做)

1. 环境准备

  • 已安装 Mycat(1.6.x 稳定版,之前入门环境可直接复用)。
  • 2 台 MySQL 服务器(CentOS 系统),需先搭建 MySQL 主从复制(Mycat 不负责数据同步,仅负责请求转发,数据一致性依赖 MySQL 自身主从复制):
    • 主库(Master):192.168.1.101:3306,数据库 db1(已创建)。
    • 从库(Slave):192.168.1.103:3306,数据库 db1(需手动创建,与主库一致)。
  • 所有数据库已创建 Mycat 连接用户(mycat/123456),并授予权限:
    sql
    -- 主库、从库都执行(允许 Mycat 连接)
    GRANT ALL ON *.* TO 'mycat'@'%' IDENTIFIED BY '123456';
    FLUSH PRIVILEGES;
    

2. 关键前提:搭建 MySQL 主从复制

Mycat 读写分离的基础是「主从数据一致」,需先完成 MySQL 主从复制配置(以 MySQL 8.0 为例):

步骤 1:配置主库(192.168.1.101)

  1. 编辑 MySQL 配置文件:
    bash
    运行
    vim /etc/my.cnf  # 或 /etc/my.cnf.d/mysql-server.cnf(CentOS 8+)
    
  2. 添加以下配置(开启二进制日志,指定主库 ID):
    ini
    [mysqld]
    server-id = 101  # 唯一 ID(1-2^32-1,不能与从库重复)
    log-bin = mysql-bin  # 开启二进制日志(主从复制依赖)
    binlog-do-db = db1  # 仅同步 db1 数据库(按需配置,不写则同步所有库)
    
  3. 重启 MySQL 并验证:
    bash
    运行
    systemctl restart mysqld
    # 登录 MySQL,查看主库状态(File 和 Position 后续从库配置需用)
    mysql -uroot -p
    mysql> show master status;
    +------------------+----------+--------------+------------------+-------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +------------------+----------+--------------+------------------+-------------------+
    | mysql-bin.000001 |      156 | db1          |                  |                   |
    +------------------+----------+--------------+------------------+-------------------+
    

步骤 2:配置从库(192.168.1.103)

  1. 编辑 MySQL 配置文件:
    bash
    运行
    vim /etc/my.cnf
    
  2. 添加以下配置(指定从库 ID,开启中继日志):
    ini
    [mysqld]
    server-id = 103  # 唯一 ID(与主库不同)
    relay-log = relay-bin  # 开启中继日志(从库同步主库日志用)
    replicate-do-db = db1  # 仅同步 db1 数据库(与主库一致)
    
  3. 重启 MySQL 并配置同步:
    bash
    运行
    systemctl restart mysqld
    # 登录从库 MySQL
    mysql -uroot -p
    # 1. 停止从库同步(首次配置可跳过)
    mysql> stop slave;
    # 2. 配置主库信息(master_log_file 和 master_log_pos 取自主库 show master status 结果)
    mysql> change master to
      master_host='192.168.1.101',
      master_user='mycat',  # 主库的 Mycat 用户(需有复制权限)
      master_password='123456',
      master_log_file='mysql-bin.000001',  # 主库二进制日志文件名
      master_log_pos=156;  # 主库日志位置
    # 3. 启动从库同步
    mysql> start slave;
    # 4. 验证主从状态(Slave_IO_Running 和 Slave_SQL_Running 均为 Yes 则成功)
    mysql> show slave status\G;
    
  • 主从复制失败排查:
    • 若 Slave_IO_Running=No:检查主库 IP、端口、用户密码是否正确,主库防火墙是否开放 3306 端口。
    • 若 Slave_SQL_Running=No:可能是主从库数据不一致(如主库已存在表,从库无),需先同步初始数据(如备份主库 db1 导入从库)。

二、Mycat 读写分离核心配置(修改 schema.xml)

Mycat 读写分离通过 schema.xml 中的 balance 参数(负载均衡策略)和 readHost 标签(从库配置)实现,核心是「指定从库地址,并开启读请求转发」。

步骤 1:修改 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/">
  <!-- 逻辑库:与 server.xml 中 schema 一致 -->
  <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="host1-master" 
               url="192.168.1.101:3306" 
               user="mycat" 
               password="123456">
      <!-- 从库配置(readHost:负责读请求,关联到父 writeHost) -->
      <readHost host="host1-slave" 
                url="192.168.1.103:3306" 
                user="mycat" 
                password="123456" />
    </readHost>
  </dataHost>
</mycat:schema>

关键参数说明(重点理解)

参数 取值与含义
balance 读写分离负载均衡策略(核心参数):

- 0:不开启读写分离(所有请求走主库);

- 1:开启,读请求转发到所有 readHost;

- 2:开启,读请求转发到所有 writeHost 和 readHost;

- 3:开启,读请求转发到 readHost,且忽略 writeHost 的读权限

writeType 写请求转发策略:

- 0:写请求转发到第一个可用的 writeHost;

- 1:写请求随机转发到多个 writeHost(适合双主架构)

readHost 从库节点,必须嵌套在 writeHost 下,标识该从库是对应主库的从节点(Mycat 会自动关联主从关系)

步骤 2:保持 server.xml 配置不变

无需修改 server.xml,沿用之前的应用连接用户(mycat_app/123456):
xml
<user name="mycat_app">
  <property name="password">123456</property>
  <property name="schema">mycat_db</property>
  <property name="readOnly">false</property> <!-- 应用可读可写 -->
</user>

三、重启 Mycat 并验证读写分离

步骤 1:重启 Mycat

bash
运行
# 先停止之前的 Mycat 进程(若已启动)
/usr/local/mycat/bin/mycat stop

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

步骤 2:验证读写分离效果(核心环节)

通过「连接 Mycat 执行 SQL → 分别查看主库 / 从库日志 → 确认请求分发」的流程验证。

1. 连接 Mycat 并操作数据

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

# 切换到逻辑库
use mycat_db;

# 1. 写操作(INSERT:应该走主库)
INSERT INTO user (id, name, age) VALUES (5, '孙七', 30);

# 2. 读操作(SELECT:应该走从库)
SELECT * FROM user;

2. 验证写请求走主库

登录主库(192.168.1.101),查看 MySQL 日志,确认有写操作记录:
bash
运行
# 1. 开启主库通用日志(临时生效,重启失效)
mysql -uroot -p
mysql> set global general_log = on;
mysql> set global log_output = 'table';  # 日志写入 mysql.general_log 表

# 2. 查询日志,确认有 INSERT 操作(用户是 mycat_app)
mysql> select * from mysql.general_log where argument like '%INSERT INTO user%';
  • 结果:能看到 Mycat 转发的 INSERT 请求(主库日志有记录)。

3. 验证读请求走从库

登录从库(192.168.1.103),同样查看日志,确认有读操作记录:
bash
运行
# 1. 开启从库通用日志
mysql -uroot -p
mysql> set global general_log = on;
mysql> set global log_output = 'table';

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

4. 验证数据一致性

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

四、进阶配置:双主双从(高可用)

若需更高可用性(主库故障自动切换),可配置「双主双从」架构,核心是添加多个 writeHost 和 readHost
xml
<dataHost name="host1" 
          balance="1" 
          writeType="1"  <!-- 写请求随机转发到多个 writeHost -->
          switchType="1"  <!-- 主库故障自动切换(1=自动切换) -->
          dbType="mysql" dbDriver="native">
  <heartbeat>select 1</heartbeat>

  <!-- 主库 1 + 从库 1 -->
  <writeHost host="host1-master" url="192.168.1.101:3306" user="mycat" password="123456">
    <readHost host="host1-slave" url="192.168.1.103:3306" user="mycat" password="123456" />
  </writeHost>

  <!-- 主库 2 + 从库 2(主库 1 故障时,自动切换到主库 2) -->
  <writeHost host="host2-master" url="192.168.1.102:3306" user="mycat" password="123456">
    <readHost host="host2-slave" url="192.168.1.104:3306" user="mycat" password="123456" />
  </writeHost>
</dataHost>
  • 关键参数:switchType="1"(开启主库故障自动切换,基于心跳检测)。

五、新手常见坑与解决方案

常见问题 原因 解决方案
读请求仍走主库 1. balance 参数配置错误(如为 0);2. 从库未配置 readHost;3. 应用用户设置 readOnly="true" 1. 确认 balance="1";2. 检查 readHost 配置是否嵌套在 writeHost 下;3. 确保 server.xml 中 readOnly="false"
从库查询不到主库数据 MySQL 主从复制未生效 1. 重新检查主从配置(show slave status\G 确认两个 Yes);2. 主库执行 flush logs 触发日志同步;3. 从库执行 start slave 重启同步
Mycat 连接从库失败 1. 从库未开放 3306 端口;2. Mycat 用户无从库访问权限;3. 从库 MySQL 未启动 1. 开放端口:firewall-cmd --permanent --add-port=3306/tcp && firewall-cmd --reload;2. 从库重新授权 Mycat 用户;3. 启动从库 MySQL
主库故障后未自动切换 1. switchType 参数未设置为 1;2. 心跳检测失败;3. 备用主库不可用 1. 配置 switchType="1";2. 检查心跳语句 select 1 是否能正常执行;3. 确保备用主库 MySQL 正常运行

六、核心总结

  1. Mycat 读写分离的核心是「balance 参数 + readHost 配置」,无需修改应用代码,透明接入。
  2. 数据一致性依赖 MySQL 主从复制,Mycat 仅负责请求转发,需先确保主从同步正常。
  3. 新手优先从「一主一从」入手,熟悉后再拓展「双主双从」高可用架构。
  4. 排查问题时,优先查看 Mycat 日志(/usr/local/mycat/logs/mycat.log)和 MySQL 通用日志,定位请求转发是否正常。
通过以上配置,即可实现 Mycat 读写分离,让读请求分担到从库,显著提升系统并发处理能力~
阅读剩余
THE END