MyCat — MySQL 分布式中间件
架构概览
MyCat 是基于 MySQL 协议的透明数据库代理,应用无需修改代码即可实现分库分表。
应用 ──► MyCat(MySQL 协议代理)──► MySQL1(分片1)
──► MySQL2(分片2)
──► MySQL3(分片3)
MyCat 核心配置文件:
server.xml → 用户、端口、全局配置
schema.xml → 逻辑库、逻辑表、数据节点
rule.xml → 分片规则核心配置
schema.xml
xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 逻辑库 -->
<schema name="order_db" checkSQLschema="false" sqlMaxLimit="100">
<!-- 分片表 -->
<table name="order" dataNode="dn1,dn2,dn3,dn4"
rule="order-sharding-rule" primaryKey="order_id">
<!-- 子表(与父表同分片) -->
<childTable name="order_item" joinKey="order_id" parentKey="order_id"/>
</table>
<!-- 全局表(每个节点都有完整数据) -->
<table name="province" type="global" dataNode="dn1,dn2,dn3,dn4"/>
<!-- 不分片的表(只在 dn1) -->
<table name="config" dataNode="dn1"/>
</schema>
<!-- 数据节点 -->
<dataNode name="dn1" dataHost="host1" database="order_db"/>
<dataNode name="dn2" dataHost="host2" database="order_db"/>
<dataNode name="dn3" dataHost="host3" database="order_db"/>
<dataNode name="dn4" dataHost="host4" database="order_db"/>
<!-- 数据主机(支持主从) -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native"
switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="mysql1:3306" user="root" password="password">
<readHost host="hostS1" url="mysql1-slave:3306" user="root" password="password"/>
</writeHost>
</dataHost>
</mycat:schema>rule.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="order-sharding-rule">
<rule>
<columns>user_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<!-- 取模分片 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<property name="count">4</property> <!-- 分片数 -->
</function>
<!-- 范围分片(按 ID 范围) -->
<function name="range-long" class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
<!-- 一致性哈希 -->
<function name="murmur" class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property>
<property name="count">4</property>
<property name="virtualBucketTimes">160</property>
</function>
<!-- 按日期分片 -->
<function name="sharding-by-month" class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2024-01-01</property>
</function>
</mycat:rule>server.xml
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> <!-- 管理端口 -->
<property name="processors">8</property>
<property name="processorBufferPool">409600</property>
<property name="sequnceHandlerType">2</property> <!-- 全局序列类型:2=时间戳方式 -->
</system>
<user name="mycat_user" defaultAccount="true">
<property name="password">mycat_password</property>
<property name="schemas">order_db</property>
</user>
</mycat:server>全局序列(分布式 ID)
xml
<!-- server.xml 配置序列类型 -->
<!-- 0: 本地文件方式(不推荐,重启后可能重复) -->
<!-- 1: 数据库方式 -->
<!-- 2: 时间戳方式(18位,推荐) -->
<property name="sequnceHandlerType">2</property>sql
-- 使用全局序列
INSERT INTO order (order_id, user_id, amount)
VALUES (next value for MYCATSEQ_ORDER, 123, 99.9);读写分离配置
xml
<dataHost name="host1" balance="1" writeType="0">
<!-- balance 参数:
0: 不开启读写分离,所有读写都到 writeHost
1: 全部读操作随机分发到 readHost(writeHost 不参与读)
2: 所有读操作随机分发到 writeHost 和 readHost
3: 所有读操作随机分发到 readHost(writeHost 不参与读,与1类似)
-->
<!-- writeType 参数:
0: 所有写操作发送到第一个 writeHost
1: 所有写操作随机发送到 writeHost(不推荐)
-->
<writeHost host="M1" url="mysql-master:3306" user="root" password="pwd">
<readHost host="S1" url="mysql-slave1:3306" user="root" password="pwd"/>
<readHost host="S2" url="mysql-slave2:3306" user="root" password="pwd"/>
</writeHost>
</dataHost>管理命令
bash
# 连接管理端口
mysql -h127.0.0.1 -P9066 -umycat -pmycat_password
# 查看数据源状态
show @@datasource;
# 查看连接池
show @@connection;
# 查看后端连接
show @@backend;
# 重新加载配置(不重启)
reload @@config;
reload @@config_all;
# 查看慢查询
show @@slow where schema='order_db';
# 切换主从(主库宕机时手动切换)
switch @@datasource where name='host1' and index=1;故障处理案例
案例一:主库宕机,自动切换失败
现象:主库宕机后,MyCat 未自动切换到备库。
排查:
bash
# 查看数据源状态
mysql -P9066 -e "show @@datasource;"
# 手动切换
mysql -P9066 -e "switch @@datasource where name='host1' and index=1;"配置自动切换:
xml
<dataHost switchType="1"> <!-- 1: 自动切换 -->
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
</dataHost>案例二:跨分片 JOIN 性能问题
现象:涉及多个分片的 JOIN 查询非常慢。
原因:MyCat 需要从多个分片获取数据,在内存中做笛卡尔积 JOIN。
解决:
- 使用 ER 表(子表与父表同分片)
- 使用全局表(字典表每个分片都有)
- 在应用层做 JOIN(分两次查询)
案例三:连接池耗尽
现象:应用报 No connections available。
解决:
xml
<dataHost maxCon="1000" minCon="10">
<!-- 增大连接池 -->
</dataHost>xml
<!-- server.xml 增大处理线程 -->
<property name="processors">16</property>
<property name="processorExecutor">32</property>MyCat vs ShardingSphere
| 维度 | MyCat | ShardingSphere |
|---|---|---|
| 接入方式 | 代理(语言无关) | JDBC(Java)/ 代理 |
| 性能 | 有代理开销 | JDBC 模式无额外开销 |
| 功能 | 基础分库分表 | 功能更丰富(数据迁移、加密等) |
| 社区活跃度 | 较低 | Apache 顶级项目,活跃 |
| 适用场景 | 老项目改造,多语言 | 新项目,Java 生态 |