☰
MyCat与MyCat2对比:分库分表中间件架构、功能与实战指南
2026/10/5 7:41:22 网站建设 项目流程

做后端这些年,分库分表这个话题基本绕不开。业务数据一上千万,单库单表撑不住,就得开始研究中间件。MyCat 在国内数据库中间件里算是老面孔了,而 MyCat2 作为新一代版本,这些年争议一直不少——有人说它是换皮,有人说它彻底重构了。我实际把两个版本都部署过,也接过线上项目迁移,这篇就结合真实使用体验,把 MyCat 和 MyCat2 的功能、优缺点、实战用法一次说清楚。如果你正在技术选型,或者刚接手一个用了 MyCat 的项目,这篇文章能帮你少走不少弯路。

1. 先聊清楚 MyCat 到底是干什么的

1.1 单库单表顶不住的时候,问题到底出在哪

很多团队一开始都是单库单表跑业务,MySQL 连上就完事。数据量到了千万级、亿级之后,问题会从几个方向同时冒出来。

第一个是连接数。应用服务一扩容,连接池一开大,MySQL 默认的 max_connections 很快被打满,数据库直接拒绝新连接。第二个是单表太大,索引失效和锁竞争越来越严重。一个几千万行的订单表,即使走索引,随机 IO 的延迟也在涨,更不用说大批量统计查询。第三个是备份和恢复,一张大表逻辑备份动不动几十 GB,恢复时间按小时算。

这时候分库分表是绕不开的方案。但让业务团队直接改底层表结构、改 SQL、改事务边界,工作量巨大,而且很容易改出线上事故。MyCat 这类数据库中间件的作用,就是把这层复杂度接过去。

1.2 MyCat 的核心定位:数据库代理中间件

MyCat 的架构用一句话说,就是在前端模拟一个 MySQL 服务,应用侧只管连jdbc:mysql://mycat_ip:8066/逻辑库,完全不知道自己背后连的是多台 MySQL 实例。MyCat 拿到 SQL 后,基于配置好的逻辑库、逻辑表、分片规则做路由,把 SQL 拆分和下发到后端真实的物理节点,再把多个节点的结果集合并返回。

从应用视角来看,你看到的是:一个数据库、一张表、一条普通的 INSERT 或 SELECT。从实际物理部署看,数据可能散落在 3 个库、每个库 5 张物理表里。MyCat 把这两层映射关系管理起来,这就是它最核心的价值。

这个设计对应用是透明的。老项目接入 MyCat,不需要改业务代码里的 SQL 逻辑,只需要把数据源连接串从 MySQL 改成 MyCat 的地址,把普通驱动换成支持 MySQL 协议的方式,大部分场景下改完就能跑。相比直接在业务代码里用 ShardingSphere-JDBC 这类嵌入式方案,MyCat 的代理模式让中间件与业务解耦,运维层面可以独立调整和升级,这也是很多传统团队选它的原因。

1.3 能力矩阵:分片、读写分离、全局序列和事务

MyCat 能提供的能力比很多人以为的要完整。分库分表是基础能力,包括水平分片、垂直分库、全局表和 ER 表(分片关联表);读写分离也很成熟,支持一主多从的负载均衡策略和基于 MySQL 主从复制的主从切换;全局序列提供了多种方案解决分片后自增 ID 冲突的问题,比如本地时间戳、数据库序列、雪花算法等;分布式事务方面,传统 MyCat 主推弱 XA 方案,适合对一致性要求没那么极端的业务场景,真正强一致的场景,官方更推荐结合 XA 或最终一致性方案处理。

另外还有 SQL 黑名单、白名单、拦截器、监控统计这些能力。一句话说清楚:它想当的角色,就是数据库前面的一道统一入口,把路由、分片、读写分离这些脏活累活收进去。

2. MyCat2 不只是换了版本号,是思路变了

2.1 MyCat2 整体架构和设计思路

MyCat2 发布到现在,很多人的印象还停留在"MyCat1 的升级版"。实际看代码和配置方式会发现,MyCat2 几乎是把内核推倒重写了。

MyCat1 的年代,整体设计基于传统的 IO 多线程模型,很多核心机制是围绕 XML 静态配置展开的,配置了 schema.xml 之后要重启才能生效,动态调整能力很弱。MyCat2 基于 Java 的异步模型重构,同时对配置体系做了彻底的动态化改造。

MyCat2 不再使用传统的 schema.xml、rule.xml 这套静态配置文件。它在底层引入了 DataSource、ReplicaGroup、Cluster 这些抽象的配置模型:

  • DataSource:对应一个实际的 MySQL 连接池,里面配了连接地址、账号、最大连接数等。
  • ReplicaGroup:一组 DataSource 的组合,用于表示主从复制关系,比如一个写节点配多个读节点。
  • Cluster:一个逻辑集群,负责把逻辑库映射到具体的 ReplicaGroup 上。

配置方式也从 XML 变成了 JSON 文件,目录下会看到 datasource.json、replica-group.json、cluster.json、user.json 这些文件。更关键的是,MyCat2 提供了配套的管理 SQL,你可以直接连接到 MyCat 执行 SQL 来创建数据源、添加分片规则、查看集群状态,很多操作在线完成,不用重启服务。这一点在实际运维中价值非常大。

原因很简单:线上分库分表的一个常态是"加节点、调权重、改分片逻辑"。如果每改一次都要重启,等于频繁释放连接、切断在线业务,这在生产环境是难以接受的。MyCat2 把动态配置做成核心特性,是真正踩过传统 MyCat 运维痛点之后做出来的选择。

2.2 SQL 解析和路由:从规则匹配到语法级处理

MyCat1 对 SQL 的处理,更接近关键词匹配和规则路由。遇到分片表查询,它根据表名找到分片规则,再根据分片键的值算路由。这种方式的优点是实现简单、性能开销小,但缺点是很多复杂 SQL 处理不了。比如子查询、多表 JOIN、复杂的聚合函数,经常出现"支持情况看版本看运气"的情况。我见过很多 MyCat1 项目,DBA 只能把复杂查询改造成多个简单查询,或者在应用层先查出 ID 列表再批量查,非常别扭。

MyCat2 引入了更完整 SQL 解析和优化机制。它在内部真正解析 SQL 的语法结构,识别 select、insert、update、delete 的类型,分析查询条件中的分片键,判断是否可以下推、是否需要在中间件层做结果集合并。像一些简单的 JOIN 查询,MyCat2 能识别出左表或右表是否分片、关联键是否一致,从而决定是全部下推还是拉取到中间件做关联处理。

这里有一个很核心的理念差异:MyCat1 的重点是"怎么把 SQL 拆出去",MyCat2 的重点是"怎么让更多 SQL 不用拆或者拆得聪明"。面对一张分片表上的普通查询,MyCat1 可能直接把 SQL 广播到所有节点再合并,而 MyCat2 会根据查询条件里的分片键精确计算出需要访问的节点,减少无谓的查询压力。

2.3 MyCat 与 MyCat2 的横向差距对比

这两者的对比,我用一张表直接列出来,能看得很清楚。

对比项MyCat(1.6.x 为主)MyCat2(2.x 系列)
架构基础经典多线程 IO,静态配置异步重构,动态配置模型
配置文件schema.xml / rule.xml / server.xmldatasource.json / cluster.json / user.json 等
配置生效方式修改后需重启在线管理,通过 SQL 动态变更
SQL 处理能力关键词匹配为主,复杂 SQL 支持弱语法级解析,子查询和聚合支持更好
分片算法取模、枚举、范围、一致性哈希等保留基础算法,算法扩展方式更轻量
运维上手成本配置项多,学习曲线陡配置项相对收敛,但文档仍需完善
社区资料多,踩坑文章遍地相对少,很多问题靠看源码
生产案例很多老项目在用新项目逐步采纳,案例还在积累

拿 MyCat1 那套 XML 配置来说,一个简单的分片表,要同时改 schema.xml、rule.xml、server.xml 三个文件,还要搞清楚 dataNode、dataHost 之间的引用关系。这对于没接触过的人,光看配置就能劝退。MyCat2 把配置拆成按职责区分的 JSON 文件,整体清晰很多,但网上资料确实少,遇到问题经常需要自己翻源码。

3. 功能、优缺点的全维度剖析

3.1 两个版本共同具备的核心功能

先看共性部分。无论 MyCat 还是 MyCat2,都具备这些基础能力:

  • 分库分表路由:支持水平分片和垂直分库,逻辑表映射物理表,通过分片键路由到目标节点。
  • 读写分离:配置主从复制关系后,自动把 SELECT 路由到从库,把 INSERT/UPDATE/DELETE 路由到主库。读请求还支持多从库负载均衡。
  • 全局序列:解决分片后主键冲突,常见的有数据库自增序列、本地时间戳、雪花 ID。
  • SQL 拦截与权限控制:可以配置用户权限、限制某些危险 SQL 下发到后端,做基本的防火墙功能。
  • MySQL 协议兼容:应用层无需替换驱动,直接用 MySQL 连接方式接入,Java 用 JDBC 就行。

对应用来说,接入 MyCat 系列中间件之后,代码里正常写的INSERT、SELECT、UPDATE、DELETE都能继续用。团队只需要理解两个核心概念:逻辑库(schema)和逻辑表。逻辑库对应 MyCat 对外开放的一个虚拟库名,逻辑表对应虚拟库下的一张表,物理存储位置由分片规则决定。

3.2 MyCat 的优缺点:成熟但沉重

MyCat 最大的优点是成熟。1.6 版本发展了多年,踩坑案例多,社区问答多,方案稳定。很多公司的核心交易链路从 2015 年左右就开始跑在 MyCat 上,经过大促考验的案例不少。如果你接手的是一个老系统,大概率能找到前人留下的排障博客和运维日报,上手有迹可循。

但它的问题也很明显。

第一是性能瓶颈。MyCat 本身是一个中间层,所有 SQL 都要过一遍代理。在分片键命中的场景下性能损耗可控,但遇到不带分片键的查询,MyCat 会广播到所有节点,性能会急剧下降。MyCat1 由于 IO 模型较老,连接数高时 CPU 消耗明显,吞叶量上不去。我测过一台普通虚拟机,纯查询场景下 MyCat1 能支撑的 QPS 大概是直连 MySQL 的六到七成,一旦混入大量广播查询,损耗更明显。

第二是配置太复杂。schema.xml 里 dataHost、dataNode、table 的层层嵌套,rule.xml 里 function 和 tableRule 的对应关系,还有 server.xml 里的系统参数,新手很难一次配对。更头疼的是,修改配置必须重启,重启一次意味着所有后端连接池重建,线上连接数会在重启瞬间飙升。

第三是复杂 SQL 支持有限。MyCat1 对子查询、WITH 语句、复杂多表 JOIN 的处理一直比较弱。很多场景下,MyCat1 会直接把不支持的部分抛回给应用层,导致应用需要自己改写 SQL。如果一个团队没有 DBA 或者高级开发兜底,这个坑会比较难填。

3.3 MyCat2 的优缺点:更现代,但文档是硬伤

MyCat2 的优点,首先是性能明显提升。内核对异步模型的重构带来更低的线程切换开销,连接处理和 SQL 处理的吞吐量都上来了。我在相近的硬件条件下做了简单压测,MyCat2 的 QPS 比 MyCat1 高了不少,CPU 占用率也更低。其次,动态配置给了运维很大的自由度,新增数据源、调整主从权重这类操作,不用再像以前那样动辄重启。再者,SQL 支持能力更强,子查询、聚合、部分 JOIN 场景下都能产出可用结果,应用侧的 SQL 兼容度更高。

但 MyCat2 的短板同样明显。最头疼的是文档,官网资料不全,版本差异大,很多接口和配置项在 2.0、2.1 之间都有变化。遇到问题搜索出来的一堆结果可能已经在旧版本上失效了。其次是生态还没完全跟上,周边工具、监控插件、自动化运维脚本都比较少,很多基础能力需要自己造。最后是一个实际选型问题:MyCat2 的新项目案例还不够多,真正发生过亿级数据量、复杂查询模型的线上验证还不多,团队如果依赖社区经验,需要更谨慎地做测试。

在我看来,MyCat 适合已经有成熟库存量的历史系统,更换成本高,加上团队对它有很强的修复经验,继续用并不丢人;MyCat2 适合新项目或者愿意花时间做迁移和压测的团队,它的性能优势和技术先进性都是实打实的,但前提是团队愿意为它的不成熟买单。

4. 实战用法:从 0 到 1 搭一套分库分表

4.1 环境准备与安装步骤

这里以 MyCat2 为例做演示,因为新项目选它更合理。准备一台 Linux 服务器,装好 JDK 8 以上版本,后端准备两个 MySQL 实例(模拟主库和从库),提前在主库建好逻辑库对应的物理库,比如db_order、db_user。MyCat2 的安装包不需要编译,解压即用。

下载好安装包后,解压到指定目录,比如/opt/mycat2。目录结构大概是这样:bin目录放启动脚本,conf目录放配置文件,lib目录放依赖 jar 包,logs目录放日志。修改conf下的user.json,配置一个可登录 MyCat 的账号。我一般这么配:

{ "users": { "root": { "username": "root", "password": "123456", "ip": [] } } }

然后启动服务:

cd /opt/mycat2 ./bin/mycat start

启动后可以先看日志确认状态:

tail -f logs/mycat.log

如果看到类似startup success的日志,说明 MyCat 已经正常起来了。默认账户连接方式为:

mysql -h127.0.0.1 -P8066 -uroot -p123456

连上之后执行show databases;能看到 MyCat 对外暴露的逻辑库列表。这一步能通,基础环境就算是跑起来了。

4.2 第 1 层配置:数据源与复制组

接下来要做的,是把后端真实的 MySQL 连接信息告诉 MyCat。打开conf/datasource.json,添加两个数据源,一个指向主库,一个指向从库。参考配置如下:

{ "datasources": [ { "name": "ds-master", "dbType": "MySQL", "dbDriver": "native", "maxCon": 500, "minCon": 10, "url": "jdbc:mysql://192.168.1.10:3306/db_order?useSSL=false&serverTimezone=Asia/Shanghai", "user": "dbuser", "password": "dbpass123" }, { "name": "ds-slave", "dbType": "MySQL", "dbDriver": "native", "maxCon": 500, "minCon": 10, "url": "jdbc:mysql://192.168.1.11:3306/db_order?useSSL=false&serverTimezone=Asia/Shanghai", "user": "dbuser", "password": "dbpass123" } ] }

name是自定义的数据源名字,后面别的配置文件会引用它。dbDriver用的是 MyCat 原生驱动,这种方式对 MySQL 协议的支持更好,性能也更优。maxCon和minCon是连接池参数,初始不要配太大,我一般先用 10 到 500 的范围,后续按业务峰值调。

数据源配好后,再打开conf/replica-group.json,把主从关系定义出来:

{ "repGroups": { "rg-order": { "rType": "MASTER_SLAVE", "writeDataSource": "ds-master", "readDataSources": ["ds-slave"] } } }

这个复制组的概念,就是告诉 MyCat 哪些数据源构成一组主从架构。writeDataSource指定写节点,readDataSources列出读节点。MyCat 会自动做读请求的负载均衡。

4.3 第 2 层配置:逻辑集群与逻辑库映射

有了数据源和复制组,还需要把逻辑库映射到复制组上。打开conf/cluster.json,配置一个集群,把逻辑库和复制组关联起来:

{ "clusters": { "c-order": { "mapping": { "db_order": "rg-order" } } } }

这个配置的含义是:当应用连上 MyCat 访问db_order这个逻辑库时,MyCat 会把请求路由到rg-order这个复制组对应的物理库上。

到这一步,基础的读写分离链路已经通了。应用连上 MyCat 后,写入操作会走ds-master,读取操作会被均衡到ds-slave,而应用代码里只需要连接jdbc:mysql://mycat:8066/db_order,一切对外透明。这里有个小提醒,mapping里配置的db_order逻辑库名,建议和后端物理库名保持一致,否则后续排查问题时,脑内映射要额外绕一道,容易出错。

4.4 实战核心:真正把一张表分到多个物理节点

读写分离只是热身的,分库分表才是真正的核心。假设现在有一张订单表t_order,数据量预计很快到千万级,想要按订单 ID 取模分成 3 个物理表。MyCat2 里支持直接登录 MyCat 执行 SQL 来创建逻辑表并绑定分片规则,整体思路比 MyCat1 的 XML 配置要轻很多。

在 MyCat 中执行:

CREATE TABLE db_order.t_order ( id bigint NOT NULL, order_no varchar(64) DEFAULT NULL, user_id bigint DEFAULT NULL, amount decimal(10,2) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这里创建的是逻辑表。接着要设置分片规则,MyCat2 支持通过 SQL 给表添加分片算法,我常用的是取模分片:

ALTER TABLE db_order.t_order ADD RULE ( shardingKey = 'id', type = 'mod', targetName = 'rg-order', shardingCount = 3 );

这段 SQL 的含义是:按id字段取模,模数 3,分片落在rg-order复制组上。执行完成后,MyCat 会在后端物理库上自动创建三张物理表。后续插入t_order的数据,MyCat 会根据id的哈希值决定数据落到哪张物理表。

验证方式很简单:

INSERT INTO db_order.t_order (id, order_no, user_id, amount) VALUES (101, 'NO2025011001', 1001, 99.90); INSERT INTO db_order.t_order (id, order_no, user_id, amount) VALUES (102, 'NO2025011002', 1002, 199.00); INSERT INTO db_order.t_order (id, order_no, user_id, amount) VALUES (103, 'NO2025011003', 1003, 59.90);

执行查询:

SELECT * FROM db_order.t_order WHERE id = 101; SELECT * FROM db_order.t_order WHERE id = 102;

观察日志或者查看后端库,会发现 101、102、103 各自落在不同的物理表上。只有带上分片键id的查询,MyCat 才能精确路由到对应分片;不带id的全表扫描查询,就会广播到所有分片节点,这是生产环境需要极力避免的查询方式。

4.5 一个完整的分片规则选择思路

取模分片是最容易理解用的分片算法,但并不意味着所有场景都适合。取模分片的优点是数据分布均匀,扩容的时候要重新计算数据分布,迁移成本大。实际选型时,要考虑增长速度、单键查询频率、是否需要按时间归档等。

比如日志流水类数据,按月分片就很直观,每个月一个物理表,归档直接切表;订单类数据如果用户查询频率远高于后台运营查询,可以按user_id分片,让同一用户的所有订单落在同一分片,后续查"我的订单列表"只需要路由到单个分片;如果查询场景以时间范围为主,可以采用范围分片,按时间区间划分。

MyCat2 支持的分片类型包括取模、范围、枚举、一致性哈希等。实操经验上,我建议初期尽量保持单一分片键,并且分片键要选择查询频率最高、分布足够均匀的字段。一个常见误区是用order_no这种随机字符串做分片键,虽然分布均匀,但业务上按用户查订单时无法带上分片键,反而导致广播查询成常态。

5. 常见问题与排查技巧实录

5.1 高频报错与对应解法

用 MyCat 的过程中,大家踩的坑高度相似。我把常见的几类整理成了速查表,直接对照排查:

现象可能原因排查与解法
应用连不上 MyCat,报连接超时MyCat 未启动、端口被防火墙拦截先看 mycat.log,再netstat -tlnp确认 8066 端口监听
连接上了,但show databases看不到预期的库cluster.json 的 mapping 未配置或配置错误检查逻辑库名与后端物理库名的映射关系,确认复制组是否健康
插入数据时提示找不到分片目标分片键未配置或规则未生效检查ALTER TABLE添加分片规则是否执行成功,分片键字段类型是否与规则匹配
查询不带分片键,性能极差全局广播查询导致改造 SQL 带上分片键;或改用跨分片聚合查询方案
主从切换后读写走了错误节点复制组状态未更新通过 MyCat 管理 SQL 查看复制组状态,必要时手动调整写节点
个别 SQL 在 MyCat 执行报错,直连 MySQL 正常MyCat 的 SQL 兼容性局限简化 SQL,拆分复杂子查询,或者用视图下推的方式规避

5.2 我在排障过程中踩过的几个坑

第一个坑是连接池参数拍脑袋。刚开始用 MyCat2,我把maxCon直接配成了 2000,结果后端 MySQL 连接数被打到接近上限,数据库响应明显变慢。后来才回过神,连接池的大小不只是 MyCat 一个点决定的,后端 MySQL 的max_connections、应用端的连接池配置都要联合考虑。合理的做法是先把 MyCat 连接数设定在 MySQL 总连接数的 70% 左右,留出余量给运维工具和直连排查用,然后压测再逐步上调。

第二个坑是分片键的隐形陷阱。碰到过一次诡异的数据丢失现象——某条订单数据插入成功,但查询查不出来。后来排查才发现,我把分片规则配到了user_id,但查询时用的条件却是order_no。由于查询条件不带分片键,MyCat 广播到所有分片,理论上应该能查到,但实际因为不同分片的物理表结构不一致,部分分片上的数据有差异,导致结果集不全。这本质上不是 MyCat 的问题,而是分片键选择和数据建模没配合好。

第三个坑是日志里的"客户端 IP"居然是 MyCat 的 IP。有次排查一个疑似慢 SQL 的问题,在 MySQL 慢查询日志里看到大量来自 MyCat 服务器 IP 的查询,一开始以为应用在直连,后来才意识到,代理模式下所有应用请求都通过 MyCat 中转,后端数据库看到的客户端 IP 全是 MyCat 的 IP。如果想做更细粒度的应用追踪,需要让应用在 SQL 注释里携带标识,或者基于 MyCat 的前端日志做关联,这是个很容易误导人的细节。

第四个坑是配置文件热加载并不等于全量热加载。MyCat2 虽然支持动态配置,但有些参数修改后需要触发对应组件的 reload 动作,比如reload @@config、reload @@datasource之类的管理指令需要熟练掌握。我曾经改完 datasource.json 直接重启 MyCat,结果连接池全部重建,一瞬间应用大量报连接错。后来养成了习惯:先改配置文件,再执行对应 reload 指令,最后观察日志确认配置生效,再逐步放流量。

5.3 保留有效的排障习惯和监控思路

排障的核心,是先确认问题出在哪一层。遇到报错不要一上来就怀疑后端 SQL,先看 MyCat 的logs/mycat.log,里面会打印 SQL 路由结果和异常堆栈。再看后端 MySQL 的慢查询日志,判断是不是 SQL 本身执行慢。最后才是看应用日志,确认连接是否正常。

监控方面,MyCat2 自带了一些监控相关的能力,但说实话开箱功能有限。我在实际项目中会额外配置对 8066 端口存活、MyCat 进程 CPU 使用率、后端数据源连接池膨胀情况的告警。连接池膨胀是很容易被忽略的指标,它往往预示着后端 MySQL 出现慢查询导致大量连接被占用,最终引发雪崩。

6. 快速上手建议和选型倾向

结合个人经验,给准备动手的读者几个建议。

如果负责的是已有系统,且数据量暂时没有爆发式增长,先把现有架构吃透,不要轻易从 MyCat1 迁移到 MyCat2。迁移的成本不只是换中间件那么简单,还包括 SQL 兼容性回归、分片规则重写、监控体系重建,以及团队学习成本的投入。

如果是新项目,在确认数据量规划和分片键设计之后,MyCat2 是更值得考虑的方向。性能、动态配置、SQL 兼容性是实打实的进步,只要团队里有掌握 MySQL 基本排查能力的人,搭配少量踩坑经验,上手难度并不高。

无论选哪个版本,有一个原则一定要坚持:分片表的分片键必须提前设计,并且在建表时确定下来,不要等业务上线了再回头改分片规则。分片键一改,意味着全量数据重分布,这是生产环境最伤筋动骨的运维操作。我个人每次设计分片方案,都会先列一张业务查询场景清单,把高频查询的过滤字段标出来,再决定谁能当分片键、谁是辅助索引。这个习惯帮我避免了不少返工。

最后再补一句心得:中间件的价值是降低复杂度,而不是引入复杂度。如果业务数据量短期没法突破单库瓶颈,优先把单库的性能优化做到位——索引、缓存、慢 SQL 治理,远比引入一个代理层更划算。千万别为了用 MyCat 而用 MyCat,搞清楚自己的真实瓶颈在哪里,这个选择才不亏。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询