MyCat
定位与版本边界
MyCat 是兼容 MySQL 协议的数据库代理,可提供逻辑库、读写分离和分片路由。MyCat 1.x 与 2.x 架构和配置不同,下面针对旧系统的 MyCat 1.6.7.5,不能把 schema.xml、server.xml 直接套用到 MyCat 2。
读写分离依赖已健康运行的 MySQL 主从复制。MyCat 不会自动建立复制关系,也不能替代可靠的主库选举和旧主隔离。两台 MyCat 前置 HAProxy/VIP 可以解决代理入口单点,但不会使后端数据库天然具备无损切换能力。
拓扑与安装
| 角色 | 示例地址 |
|---|---|
| MySQL 主库 | 10.0.0.10:3306 |
| MySQL 副本 | 10.0.0.11:3306、10.0.0.12:3306 |
| MyCat 代理 | 10.0.0.50、10.0.0.51 |
| MyCat 业务端口 | 8066 |
| MyCat 管理端口 | 9066,仅管理网 |
从官方发布页取得匹配平台的发行包,核对来源、校验值和 JDK 兼容性。1.6.7.5 常用 Java 8;Ubuntu 软件仓库是否提供对应 JDK 取决于发行版,不应直接假设 apt install openjdk-8-jdk 可用。
mkdir -p /data/softs /data/server
cd /data/softs
curl -fLO https://github.com/MyCATApache/Mycat-Server/releases/download/Mycat-server-1675-release/Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz
tar -xf Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz -C /data/server
java -version
使用专用非 root 用户运行。配置可能含数据库凭据,目录只允许管理员和运行用户访问;修改前备份原始 conf,不要把启动日志和 PID 从另一台主机复制过来。
MySQL 账号与权限
先由管理员创建需要的业务库。下面是新建示例,已有库不要重复执行初始化:
CREATE DATABASE jpress CHARACTER SET utf8mb4;
CREATE DATABASE wordpress CHARACTER SET utf8mb4;
CREATE DATABASE discuz CHARACTER SET utf8mb4;
CREATE USER 'mycat'@'10.0.0.50' IDENTIFIED BY 'REPLACE_WITH_DB_PASSWORD';
CREATE USER 'mycat'@'10.0.0.51' IDENTIFIED BY 'REPLACE_WITH_DB_PASSWORD';
GRANT SELECT, INSERT, UPDATE, DELETE ON jpress.* TO 'mycat'@'10.0.0.50', 'mycat'@'10.0.0.51';
GRANT SELECT, INSERT, UPDATE, DELETE ON wordpress.* TO 'mycat'@'10.0.0.50', 'mycat'@'10.0.0.51';
GRANT SELECT, INSERT, UPDATE, DELETE ON discuz.* TO 'mycat'@'10.0.0.50', 'mycat'@'10.0.0.51';
账号变更是否同步到副本取决于复制过滤等配置,必须逐副本验证。业务迁移和建表使用独立 DDL 账号;不要给代理账号 *.* 全局权限。旧驱动与 MySQL 8 认证插件有兼容差异,先验证对应版本,不通过开放弱认证或全局降级来绕过问题。
schema.xml
文件为 /data/server/mycat/conf/schema.xml。所有 REPLACE_WITH_DB_PASSWORD 要替换为上一步实际密码,XML 中的 &、<、引号等字符必须正确转义。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="jpress" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn_jpress"/>
<schema name="wordpress" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn_wordpress"/>
<schema name="discuz" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn_discuz"/>
<dataNode name="dn_jpress" dataHost="mysql_host" database="jpress"/>
<dataNode name="dn_wordpress" dataHost="mysql_host" database="wordpress"/>
<dataNode name="dn_discuz" dataHost="mysql_host" database="discuz"/>
<dataHost name="mysql_host" maxCon="200" minCon="5" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="-1">
<heartbeat>select 1</heartbeat>
<writeHost host="master" url="10.0.0.10:3306" user="mycat" password="REPLACE_WITH_DB_PASSWORD">
<readHost host="replica1" url="10.0.0.11:3306" user="mycat" password="REPLACE_WITH_DB_PASSWORD"/>
<readHost host="replica2" url="10.0.0.12:3306" user="mycat" password="REPLACE_WITH_DB_PASSWORD"/>
</writeHost>
</dataHost>
</mycat:schema>
本例只做按逻辑库映射和读写分离,没有分库分表。balance=1 将可分离读分配给符合配置的读节点;writeType=0 使用首个 writeHost。switchType=-1 关闭代理自动切换,由明确的后端高可用流程负责主库切换。
select 1 只检查连接,不判断复制延迟。要使用复制状态心跳、slaveThreshold 或其他版本特性,先核对对应 MySQL 版本的状态命令、监控权限和该 MyCat 版本的实现,不能认为填一个阈值就具备可靠的延迟隔离。
server.xml
在发行包的现有配置上调整以下内容,保留目标版本要求的其他配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="serverPort">8066</property>
<property name="managerPort">9066</property>
</system>
<user name="appuser">
<property name="password">REPLACE_WITH_APP_PASSWORD</property>
<property name="schemas">jpress,wordpress,discuz</property>
</user>
</mycat:server>
业务用户仅访问必要逻辑库。管理连接按目标发行包支持的账号配置和网络边界保护;不能把 9066 暴露给普通应用或公网。
启动与 systemd
假设 mycat 用户已创建且拥有必要目录,JDK 路径及 wrapper.conf 已验证:
[Unit]
Description=MyCat Server
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
User=mycat
Group=mycat
WorkingDirectory=/data/server/mycat
PIDFile=/data/server/mycat/logs/mycat.pid
ExecStart=/data/server/mycat/bin/mycat start
ExecStop=/data/server/mycat/bin/mycat stop
Restart=on-failure
RestartSec=5
TimeoutStartSec=120
TimeoutStopSec=60
UMask=0077
[Install]
WantedBy=multi-user.target
确认 PID 文件位置与发行包脚本一致后,保存为 /etc/systemd/system/mycat.service:
sudo systemctl daemon-reload
sudo systemctl enable --now mycat
sudo systemctl status mycat --no-pager
sudo journalctl -u mycat -n 100 --no-pager
sudo ss -lntp
代理启动失败时查看 logs/wrapper.log 和 logs/mycat.log,检查 Java、XML、目录权限、端口和后端认证。XML 可做语法校验,但路由、连接与权限还要通过实际 SQL 验证。
读写与事务验收
由管理员在主库创建测试表,运行账号仅执行业务 DML:
CREATE TABLE jpress.proxy_test (id BIGINT PRIMARY KEY, value VARCHAR(100));
通过代理连接:
mysql -h 10.0.0.50 -P 8066 -u appuser -p jpress
INSERT INTO proxy_test VALUES (1, 'hello');
SELECT * FROM proxy_test WHERE id = 1;
SELECT @@hostname, @@server_id;
START TRANSACTION;
UPDATE proxy_test SET value = 'updated' WHERE id = 1;
SELECT * FROM proxy_test WHERE id = 1;
COMMIT;
结合后端连接或受控查询日志确认读写实际落点,不能仅凭代理返回相同数据证明读请求已负载均衡。复制延迟会影响写后立即读;强一致查询、事务和关键状态确认应明确走主库。SQL Hint 等行为取决于版本,使用前验证,不能假设所有 SQL 都被正确解析。
双代理、备份与排障
第二台使用同一套受版本管理的配置和镜像/发行包,单独创建日志与运行目录,再由负载均衡器提供统一业务入口。健康检查应包含业务 SQL,不能只检查 8066 TCP。代理重启会中断现有连接,应用连接池需要重连与有界重试,写操作需要业务幂等。
备份 MyCat 配置、路由规则及恢复说明;真正的数据备份由 MySQL 完成。故障切换前先隔离旧主,验证新主复制位置与可接受丢失量,再更新代理并检查连接池。
| 现象 | 检查方向 |
|---|---|
| 连接代理失败 | 业务端口、监听、应用账号、逻辑库及防火墙 |
| 后端认证失败 | MySQL user/host、密码、认证插件和来源 IP |
| 写入后读取不到 | 复制延迟、读写路由、事务边界及业务一致性要求 |
| 连接耗尽 | MyCat maxCon、应用池总连接、MySQL max_connections 和慢查询 |
| SQL 不兼容 | MyCat 版本、SQL 解析器、分片限制、事务与 JOIN 范围 |
评论