mycat是开源mysql中间件,通过sql路由实现读写分离、分库分表与故障切换;依赖稳定主从复制,需正确配置schema.xml中writehost嵌套readhost及server.xml的balance参数,并注意sql兼容性限制。

MyCat 是一个开源的 MySQL 中间件,它在应用层和数据库层之间做 SQL 路由,支持读写分离、分库分表、故障切换等能力。MySQL 5.7 本身不内置读写分离逻辑,MyCat 正是为弥补这一缺口而设计的代理层方案。
但要注意:MyCat 不是“开箱即用”的黑盒,它依赖主从复制已稳定运行,且对 SQL 兼容性有明确限制——比如不支持存储过程、部分子查询、INSERT ... ON DUPLICATE KEY UPDATE 在某些版本中会路由异常。
MyCat 启动前必须确认主从复制状态正常
MyCat 不负责同步数据,只负责把 SELECT 发给从库、INSERT/UPDATE/DELETE 发给主库。如果从库延迟大或 Slave_IO_Running 为 No,读请求就会拿到旧数据甚至报错。
- 登录每个从库执行
show slave status\G - 确保
Seconds_Behind_Master接近 0,且两个关键字段都为Yes:Slave_IO_Running: YesSlave_SQL_Running: Yes - 若
Seconds_Behind_Master持续增长,先排查网络、大事务、从库磁盘 I/O 或 binlog 格式(MySQL 5.7 默认ROW,但某些场景需设为MIXED)
schema.xml 中配置 readHost 必须显式声明 writeHost
MyCat 的 schema.xml 里,一个 dataHost 下可定义一个 writeHost 和多个 readHost。但容易被忽略的是:
-
readHost不能单独存在,必须嵌套在writeHost内部 - 所有
readHost共享该writeHost的连接池参数(如maxCon、minCon),不是独立配置 - 如果只配了
readHost没配writeHost,启动时会报错:java.lang.RuntimeException: can't find writeHost
示例片段(正确):
<datahost name="host1" ...><writehost host="master" url="192.168.4.10:3306" user="mycat" password="123456"><readhost host="slave1" url="192.168.4.20:3306" user="mycat" password="123456"></readhost><readhost host="slave2" url="192.168.4.30:3306" user="mycat" password="123456"></readhost></writehost></datahost>
server.xml 中 balance 属性决定读负载策略
MyCat 对 readHost 的负载方式由 dataHost 的 balance 属性控制,不是靠随机或轮询自动生效:
-
balance="0":不开启读写分离,所有读也走writeHost -
balance="1":所有readHost参与负载,但仅当writeHost健康时才启用;若主库宕机,整个 dataHost 不可用 -
balance="2":即使writeHost宕机,readHost仍可提供只读服务(适合灾备读场景) -
balance="3":同balance="1",但还支持readHost之间的权重(需配合weight属性)
常见误配:设了多个 readHost 却没改 balance,结果所有读请求仍打到主库,压测时发现从库 CPU 零负载。
SQL 被错误路由的典型原因
MyCat 依赖 SQL 解析判断读写类型,不是简单看是否含 SELECT 关键字:
- 包含
FOR UPDATE或LOCK IN SHARE MODE的SELECT会被强制路由到writeHost - 子查询中若外层是
SELECT、内层含INSERT,整条语句可能被判定为写操作 - 使用了
@@tx_isolation、SELECT USER()等系统函数,部分版本会误判为写
验证方法:开启 MyCat 的 debug 日志,在 logs/mycat.log 中搜索 route 关键字,看实际路由目标是 master 还是 slave1。
真正难处理的是跨库 JOIN 或全局序列(nextval),这些在 MyCat 5.7 兼容模式下基本不可靠,得提前规避或换方案。
MyCat 的核心价值在于透明路由,但它不会帮你修主从延迟、不会自动剔除慢从库、也不校验 SQL 是否真能被下推。一旦上线,必须持续监控 mycat.log 中的路由日志和从库同步延迟,否则“读写分离”只是个假象。











