简介:该资源基于 MyCat 1.6.7.6 正式版源码修改,面向需要在分库分表场景中实现按月自动分表的后端开发与运维人员,重点解决 subTables 正则配置无法按月份动态生成子表的问题。通过 subTables="tableName_$202101-?"、subTableWay="BYMONTH" 与 rule="sharding-by-month" 的组合配置,只需指定起始月份,问号即代表当前日期月份并动态变化,配合 MySQL 中真实存在或动态创建的子表即可实现子表自动增长。压缩包共 111 个文件,约 24.86MB,以 53 个 jar 依赖、18 个 properties 配置、10 个 xml 与 14 个 txt 说明为主,另含 sh 启动脚本、so 本地库及 sql、bak 备份文件,覆盖服务端运行与配置所需。已有 379 人学习下载,适合研究 MyCat 分表规则改造、需要按月归档或滚动建表的中高级开发者参考,可据此理解源码改动点与配置方式,快速落地按月分表方案。
1. 拿到一个按月分表的 MyCat 包,先别急着解压
上周有个做订单系统的同行发来一个压缩包,名字叫mycat-1.6.7.6_BYMONTH.zip,问我能不能直接上生产。他的场景很典型:订单表一年几千万行,单表查询越来越慢,想按月份把数据拆开,又不想改太多业务代码。这个包的核心价值就在这儿——它把 MyCat 1.6.7.6 里按月分表(subTables 配合 month 规则)那套配置和依赖整理成了一个可直接跑的骨架,省去你自己拼 schema.xml、rule.xml 的时间。
适合谁:手里有 MySQL 分库分表需求、想用 MyCat 做中间件、并且数据天然带时间维度的团队。不适合谁:数据量还没到单表瓶颈、或者团队没人愿意维护中间件的。下面我按「这东西怎么落地 → 配置怎么写 → 坑在哪」的顺序拆,能抄的配置我都贴出来。
2. 按月分表的原理与这个包的骨架:subTables 到底怎么切
2.1 先搞清楚 MyCat 的 month 分片规则在干什么
MyCat 的分片规则本质是「路由函数 + 分片节点映射」。按月分表用的是rule.xml里的sharding-by-month规则,它拿分片字段(通常是create_time这类日期列)去算月份,再映射到dataNode。关键在于subTables这个属性:它允许一个逻辑表在同一个物理库下再按月份拆成多张物理表,比如orders_202401、orders_202402。这跟「分库」是两回事——subTables 是库内分表,减少的是单表体积,不是单库连接压力。
这个包把 1.6.7.6 版本的schema.xml、rule.xml、server.xml模板和启动脚本放在了一起,目录大致是conf/、lib/、bin/三块。conf/rule.xml里已经预置了 month 规则的function和tableRule,你主要改的是schema.xml里的逻辑表名、分片字段和dataNode列表。理解这一点很重要:包给的是「规则骨架」,不是「开箱即用的业务配置」,业务表名、库名、月份范围都得你自己填。
2.2 逻辑表、物理表、dataNode 三者的对应关系
假设订单逻辑表叫orders,分片字段create_time,按月拆到 12 张物理表。配置里要体现三层:
- 逻辑表:
orders,业务 SQL 里只写这个名字 - 物理表:
orders_202401到orders_202412,由 subTables 机制拼接 - dataNode:指向具体 MySQL 实例和库,比如
dn1
schema.xml里大致这样写(节选,字段按你实际表结构调整):
<schema name="ORDER_DB" checkSQLschema="false" sqlMaxLimit="100"> <!-- 逻辑表 orders,subTables 开启库内按月分表 --> <table name="orders" dataNode="dn1" rule="sharding-by-month" subTables="orders_$2024$01-12" primaryKey="id"/> </schema> <dataNode name="dn1" dataHost="host1" database="order_db"/>subTables的写法是逻辑前缀_$年份$月份范围,MyCat 会按规则算出的月份去拼物理表名。这里有个容易翻车的点:$2024$01-12这种写法在不同小版本里解析行为不完全一致,1.6.7.6 里建议先用单月验证拼接结果,再放开全年范围。primaryKey必须写,否则后续做全局序列和主键路由会出问题。
2.3 为什么选库内分表而不是一上来就分库
很多团队一听到分表就想直接分库,结果运维复杂度翻倍。按月分表 + subTables 的好处是:业务代码零改动(还是查orders),单库内的表体积可控,历史月份可以直接归档或删表。代价是单库连接数和磁盘 IO 还是共享的,等单库也扛不住了,再往分库演进。这个包的定位就是帮你把「库内按月分表」这一步先跑通,属于渐进式方案,不是终局架构。选型时想清楚:你的瓶颈是单表扫描慢,还是单库写入打满?前者用这个包够用,后者得直接上分库。
3. 把包跑起来:配置、启动与一条 SQL 的完整路由验证
3.1 环境准备与目录落位
先确认 JDK 版本。MyCat 1.6.x 系列对 JDK 8 兼容最好,JDK 11 以上容易在启动时遇到模块反射相关的报错。解压后进目录看一眼结构:
unzip mycat-1.6.7.6_BYMONTH.zip -d /opt/mycat cd /opt/mycat ls conf/ lib/ bin/ # 确认 rule.xml 里存在 sharding-by-month grep -n "sharding-by-month" conf/rule.xml如果grep没输出,说明包里的规则名可能被改过,去rule.xml里搜month关键字确认实际tableRule名,后面schema.xml的rule属性要和它严格一致。这一步别跳过,规则名对不上启动不报错,但查询会全路由到默认节点,属于典型的「静默翻车」。
3.2 改 schema.xml 和 server.xml 的最小集
server.xml主要配逻辑库账号和权限,最小改动是加一个能登录的用户:
<user name="app_user" defaultAccount="true"> <property name="password">your_password</property> <property name="schemas">ORDER_DB</property> </user>schema.xml按 2.2 的模板填逻辑表、dataNode、dataHost。dataHost里要写真实 MySQL 的地址、账号、读写节点:
<dataHost name="host1" maxCon="100" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1"> <heartbeat>select user()</heartbeat> <writeHost host="m1" url="127.0.0.1:3306" user="root" password="root_pwd"/> </dataHost>balance="0"表示不读分离,先跑通再说;switchType="1"是默认主从切换策略。参数含义:maxCon是连接池上限,按月分表场景下物理表多,连接消耗会比单表高,建议先给到 100 观察。改完配置别急着起服务,先做 3.3 的物理表准备。
3.3 物理表建表与月份表批量生成
MyCat 不会帮你建物理表,orders_202401这些得自己在 MySQL 里建好。用一段 SQL 批量生成建表语句,避免手写 12 张:
-- 在 MySQL 里执行,生成 2024 年 12 张月表的建表语句 SELECT CONCAT( 'CREATE TABLE orders_2024', LPAD(n, 2, '0'), ' LIKE orders_template;' ) AS ddl FROM ( SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 ) t;先建一张orders_template作为结构模板,把上面查出来的 DDL 复制执行。逻辑说明:LPAD(n,2,'0')保证月份是两位,和subTables里的$01-12对齐;用LIKE复制结构比逐张写字段省事,但注意LIKE不带外键和部分索引属性,建完抽查一张确认索引在。这一步的坑是月份补零——orders_20241和orders_202401在 MyCat 眼里是两张表,拼错就查不到数据。
3.4 启动并用 EXPLAIN 验证路由
cd /opt/mycat/bin ./mycat start tail -f ../logs/mycat.log # 另开窗口连上逻辑库 mysql -h127.0.0.1 -P8066 -uapp_user -p ORDER_DB连上后执行一条带分片字段的查询,并用EXPLAIN看路由:
EXPLAIN SELECT * FROM orders WHERE create_time = '2024-03-15 10:00:00';正常应该只路由到dn1且物理表是orders_202403。如果EXPLAIN显示路由到所有节点,八成是rule属性名和rule.xml里的tableRule不一致,或者分片字段类型和规则里的columns对不上。验证通过后再跑一条不带分片字段的查询,观察是否全路由——这是预期行为,业务上要尽量避免。
4. 避坑清单:按月分表最容易翻车的五个地方
4.1 现象:查询报「table doesn't exist」,但物理表明明建了
原因:subTables拼接出的表名和你实际建的表名不一致,最常见是月份没补零,或者$年份$月份范围的写法里年份位数不对。解决:在 MySQL 里SHOW TABLES LIKE 'orders_%'对照,再用EXPLAIN看 MyCat 实际拼的表名,两边对齐。我一般会先只配一个月($2024$03)验证拼接,通了再放开全年。
4.2 现象:插入数据成功,但查不到
原因:插入时create_time传了NULL或格式不是yyyy-MM-dd HH:mm:ss,month 规则算不出月份,数据被路由到默认节点或报错丢弃。解决:分片字段在业务层强制非空,并在 MyCat 侧确认rule.xml里 month 规则的dateFormat和你的入参格式一致。这个坑很隐蔽,因为插入不报错。
4.3 现象:跨月查询把 12 张表全扫一遍,慢得离谱
原因:SQL 的WHERE里没有分片字段,或者用了create_time的函数包裹(如DATE_FORMAT(create_time,...)),规则无法下推。解决:查询条件直接写create_time BETWEEN '2024-03-01' AND '2024-03-31',别在字段上套函数;报表类跨月查询走单独的汇总表,别指望 MyCat 帮你优化全路由。
4.4 现象:启动正常,但连接一会儿就断
原因:dataHost的maxCon给太小,月表多、并发一上来连接池打满;或者 MySQL 侧wait_timeout比 MyCat 心跳间隔短。解决:maxCon按并发估,先 100 起步;heartbeat保持默认select user(),并确认 MySQL 的wait_timeout大于心跳周期。日志里搜connection关键字能快速定位。
4.5 现象:历史月份数据想归档,直接 DROP 表后 MyCat 报错
原因:subTables范围里还包含被删的月份,路由到不存在的表。解决:归档前先改schema.xml缩小subTables范围并 reload,再删物理表;或者保留空表结构只清数据。顺序反了就得回滚配置,血泪经验是「先改配置后动数据」。
5. 进阶:用全局序列和按月归档把方案跑成闭环
跑通基本路由只是第一步,真正上生产还得解决主键和归档两件事。按月分表后,自增主键在每张月表里独立,跨表会重复,必须换全局序列。MyCat 支持本地文件、数据库、ZK 等方式,小规模用数据库方式最省事:在某个库建MYCAT_SEQUENCE表,schema.xml的table上加autoIncrement="true"并配sequenceHandlerType。我一般会在server.xml里把sequnceHandlerType设为 2(数据库方式),然后建表:
CREATE TABLE MYCAT_SEQUENCE ( name VARCHAR(50) NOT NULL, current_value BIGINT(20) NOT NULL, increment INT NOT NULL DEFAULT 1, PRIMARY KEY (name) ) ENGINE=InnoDB; INSERT INTO MYCAT_SEQUENCE(name, current_value, increment) VALUES ('orders', 100000, 1);逻辑说明:current_value是当前已分配到的值,increment是步长,MyCat 每次取一批缓存在本地,减少数据库往返。参数上步长别设太大,否则重启后 ID 跳变明显;也别设 1,高并发下会频繁打库。配完重启,插入一条不带id的记录,看是否自动填上全局 ID。
归档这块,我的习惯是每月初跑一个脚本:先把上上个月的表数据INSERT INTO orders_archive_YYYYMM SELECT * FROM orders_YYYYMM,确认行数一致后再TRUNCATE原月表,最后改schema.xml的subTables范围并 reload。顺序不能乱,先归档再缩范围再清表,任何一步失败都能回退。验证方法很简单:归档后跑一条跨归档月的查询,确认 MyCat 不再路由到已清空的表,同时业务侧读历史数据走归档表。
从那以后我每次拿到这种「预置规则」的中间件包,都强制先只配一个月、跑通一条EXPLAIN再放开全年范围——这个习惯帮我躲过了至少三次静默路由错误。希望帮到你。
本文还有配套的精品资源,点击获取