MyCat与MyCat2对比:分库分表中间件架构、功能与实战指南
做后端这些年分库分表这个话题基本绕不开。业务数据一上千万单库单表撑不住就得开始研究中间件。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 的横向差距对比这两者的对比我用一张表直接列出来能看得很清楚。对比项MyCat1.6.x 为主MyCat22.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?useSSLfalseserverTimezoneAsia/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?useSSLfalseserverTimezoneAsia/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) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里创建的是逻辑表。接着要设置分片规则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搞清楚自己的真实瓶颈在哪里这个选择才不亏。