简介:该资源基于MyCat 1.6.7.6正式版源码修改,面向使用MyCat做分库分表、需要按月自动扩展子表的后端开发与运维人员,重点解决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脚本,覆盖服务端运行与配置所需。已有377人学习下载,适合需要研究按月分表规则配置与源码改造思路的读者参考。
1. 拿到 mycat-1.6.7.6_BYMONTH.zip:一个按月分表的现成起点
上周有个做订单系统的同行问我,MyCat 里按月分表到底怎么配才不翻车。他手上压着几千万条历史订单,单表查询已经开始肉眼可见地变慢,想按月份把数据拆开,又不想从零写分片算法。我翻出自己留的mycat-1.6.7.6_BYMONTH.zip给他看,这个包的核心价值就在名字里:基于 MyCat 1.6.7.6 版本,预置了一套按月分表(subTables 按月)的配置与规则样例,省掉了从官方裸包开始改 schema.xml、rule.xml 的重复劳动。它适合已经跑着 MySQL、准备做时间维度水平拆分的后端和运维,也适合想先跑通再改参数的新手。下面我按「这包是什么、怎么落地、哪里会翻车」的顺序拆给你看。
2. 拆包看结构:BYMONTH 分表规则到底改了什么
拿到压缩包先别急着往生产环境扔,解压后花十分钟把目录和关键配置文件过一遍,能省掉后面一半的排查时间。这个包本质是 MyCat 1.6.7.6 的一份定制发行目录,差异集中在conf/下的分片规则与 schema 定义,lib/、bin/基本沿用原版。理解它的前提是先搞清 MyCat 的分表模型:逻辑表(logic table)对上层应用透明,底下按规则映射到多个物理表(dataNode 上的实际表),而「按月」这件事,靠的是分片算法把时间字段折算成月份序号,再取模或直接定位。
2.1 目录与关键文件清单
解压后重点看这几个位置,其余可以当原版对待:
| 路径 | 作用 | 是否需要改 |
|---|---|---|
conf/schema.xml | 定义逻辑库、逻辑表、dataNode 映射 | 必改,换成自己的库名和节点 |
conf/rule.xml | 分片规则与算法定义,BYMONTH 相关在此 | 按需改,确认算法类与参数 |
conf/server.xml | 用户、逻辑库授权 | 必改,换成自己的账号 |
conf/sequence_conf.properties | 全局序列配置 | 视是否用自增而定 |
lib/ | 依赖 jar,含分片算法相关类 | 一般不动 |
bin/ | 启动脚本 | 一般不动,注意 JVM 参数 |
schema.xml里能看到逻辑表通过rule属性挂到某个分片规则上,rule.xml里则能找到对应的<tableRule>和<function>。BYMONTH 的定制点就在<function>的class与property上——它把「按时间字段取月份」这件事封装成了可配置的算法,而不是让你在应用层自己算好月份再传进来。
2.2 按月分表的算法逻辑
按月分表有两种常见思路,这个包走的是「时间字段 → 月份序号 → 定位物理表」这条线。核心是把一个datetime或date类型的列,折算成从某个基准时间起的月份偏移量,再对物理表数量取模或直接作为下标。常见做法是基准时间设为一个固定年份的 1 月,偏移量 = (年差 × 12 + 月差),这样 2024-03 会稳定落到某个确定的表上,跨年也不会错位。
需要提醒的是,分片字段必须是查询条件里高频出现的列,否则 MyCat 会走全路由,把 SQL 广播到所有物理表再聚合,性能反而更差。按月分表的天然约束是:你的查询大多带时间范围(比如「查某月订单」),这时路由能精准命中单表;如果业务大量按用户 ID 查而不带时间,那这套规则就不合适,得考虑别的维度。选型阶段想清楚这一点,比后面调参数重要得多。
2.3 先跑通再改:本地验证的最小步骤
别一上来就接生产库。我一般先在本地起两个 MySQL 实例(或用同一实例的两个库模拟),把包解压到独立目录,改完配置直接启动验证路由。步骤大致是:建物理库和按月命名的物理表、改schema.xml的 dataHost 与 dataNode、改server.xml的账号、启动 MyCat、用客户端连 8066 端口插几条不同月份的数据、再去各物理表里核对落点。这套流程跑通,你才算真正理解了这个包的映射关系,后面改参数心里才有底。
3. 配置落地:schema.xml 与 rule.xml 的改法
这一章是能直接抄作业的部分。所有改动都在conf/下,改之前先备份原文件,出问题能一键回滚——这是血泪经验,我第一次改分片规则没备份,调错一个属性导致启动直接报错,翻了半小时日志才定位到是 rule.xml 里 function 的 class 写错。
3.1 schema.xml:逻辑表挂到 BYMONTH 规则
先看逻辑表怎么定义。下面是一段精简后的结构,重点是rule属性和 dataNode 的对应关系:
<!-- conf/schema.xml 片段:逻辑库与按月分表的逻辑表 --> <schema name="order_db" checkSQLschema="false" sqlMaxLimit="100"> <!-- 逻辑表 order_info,rule 指向 rule.xml 中定义的 bymonth 规则 --> <table name="order_info" dataNode="dn_order_$0-11" rule="bymonth" /> </schema> <!-- 物理库与节点:dn_order_0 到 dn_order_11 对应 12 个月份槽位 --> <dataNode name="dn_order_0" dataHost="host1" database="order_2024_01" /> <dataNode name="dn_order_1" dataHost="host1" database="order_2024_02" /> <!-- 其余节点按月份依次定义,此处省略 -->逻辑说明:dataNode="dn_order_$0-11"是 MyCat 的区间写法,等价于展开成 12 个节点,配合按月规则正好一个月份一个物理库(或物理表)。rule="bymonth"把这张表交给 rule.xml 里的规则处理。参数上,sqlMaxLimit限制单次返回行数,防止误查全表把内存打爆;checkSQLschema关掉可以避免应用带库名前缀时路由异常。改的时候把order_db、order_2024_xx换成你自己的命名,节点数量要和规则里的模数对齐,否则会出现算出来的下标找不到节点。
3.2 rule.xml:确认 BYMONTH 算法与参数
规则定义是这套方案的心脏,结构如下:
<!-- conf/rule.xml 片段:按月分片规则 --> <tableRule name="bymonth"> <rule> <!-- 分片字段:必须是表里真实存在的时间列 --> <columns>create_time</columns> <algorithm>byMonthFunc</algorithm> </rule> </tableRule> <function name="byMonthFunc" class="io.mycat.route.function.PartitionByMonth"> <!-- 基准日期,决定月份偏移的起点 --> <property name="dateFormat">yyyy-MM-dd</property> <property name="sBeginDate">2024-01-01</property> <!-- 物理节点/表数量,需与 dataNode 数量一致 --> <property name="sPartionDay">31</property> </function>逻辑说明:columns指定用哪一列做分片,这里必须是create_time这类时间列,写错列名会导致路由失败或全广播。class指向按月分区的算法实现,sBeginDate是偏移基准,dateFormat要和实际入库格式一致,sPartionDay控制每个分区的跨度。参数怎么改:如果你的物理表是按「每月一张」建的,分区跨度就按自然月对齐;如果按固定天数切,就调sPartionDay。改完务必保证sBeginDate早于或等于最早的业务数据时间,否则早期数据会算不出落点。
3.3 启动与连通性验证
配置改完,用bin/下的启动脚本拉起 MyCat,然后从客户端连 8066 端口验证:
# 启动 MyCat(后台运行,日志在 logs/ 下) ./bin/mycat start # 用 mysql 客户端连 MyCat 逻辑库,端口默认 8066 mysql -h127.0.0.1 -P8066 -uroot -p -D order_db # 插入两条不同月份的数据,观察落点 INSERT INTO order_info(id, create_time, amount) VALUES (1, '2024-01-15 10:00:00', 100); INSERT INTO order_info(id, create_time, amount) VALUES (2, '2024-03-20 12:00:00', 200);逻辑说明:启动后先看logs/mycat.log有没有报错,常见的是 dataHost 连不上或 rule 引用找不到。插入验证时,两条数据应分别落到 1 月和 3 月对应的物理库,去底层 MySQL 里select一下就能确认路由是否正确。参数上,8066 是默认服务端口,9066 是管理端口,排查路由可以用管理端口的explain命令看 SQL 被分发到哪些节点——这个技巧后面排错会反复用到。
4. 避坑与排查:按月分表最容易翻车的五处
这套配置跑通不难,难的是上线后不出幺蛾子。下面五条是我和同行踩过的真实坑,按「现象 → 原因 → 解决」记下来,遇到时对着查。
4.1 查询不带时间字段导致全表广播
现象:某列表页突然变慢,慢查询日志里 SQL 被发到所有物理库。原因:查询条件里没有create_time,MyCat 无法计算月份,只能广播到全部节点再聚合。解决:要么在查询里补上时间范围,要么给这类查询单独建一张不分片的汇总表;实在避不开,就在应用层限制必须带时间条件,别指望数据库兜底。
4.2 基准日期晚于历史数据
现象:插入早期数据时报错或落到错误的表。原因:sBeginDate设得比最早业务数据晚,月份偏移算出负数或越界。解决:把sBeginDate调到早于最早数据的时间点,改完重启并回归测试历史数据的查询路由。
4.3 dataNode 数量与分区数不一致
现象:部分月份的数据插入失败,日志提示找不到节点。原因:schema.xml里定义的节点数少于规则算出的下标范围。解决:节点数量、物理表数量、规则分区数三者必须对齐,改一处就要同步另外两处,改完用管理端口explain抽查几个月份的落点。
4.4 时间格式不一致导致解析失败
现象:明明有时间字段,路由却报解析异常。原因:dateFormat与实际入库格式不匹配,比如配置是yyyy-MM-dd而数据带时分秒。解决:把dateFormat调成与实际存储格式一致,或统一在应用层做格式规整,别让数据库层猜。
4.5 跨月边界数据落点漂移
现象:月末最后一天的数据偶尔落到下个月的表。原因:分区跨度按固定天数算时,自然月天数不等导致边界偏移。解决:按自然月分表就用自然月对齐的算法参数,别混用固定天数;上线前专门造一批月末、月初、闰年二月的数据做边界测试,这是最容易被忽略的后悔药。
5. 进阶:用管理端口验证路由与扩容思路
跑通之后,真正决定这套方案能不能长期用的是两件事:怎么快速验证某条 SQL 的路由,以及数据涨上来后怎么加月份。验证路由我习惯用 9066 管理端口,连上去执行explain加你的 SQL,它会告诉你语句被分发到哪些 dataNode,比翻日志快得多。扩容方面,按月分表的天然优势是新月份直接加节点和物理表,不用动历史数据;但要注意规则里的分区总数变化会影响取模结果,所以更稳妥的做法是「一个月份一个固定槽位」的直接定位,而不是取模,这样加月份只是追加节点,历史落点不变。我一般会在上线前把未来 12 个月的节点一次性建好,避免每月手动加表。从那以后我每次改分片规则,都强制先在本地用explain把典型 SQL 的路由跑一遍再上生产,这个习惯帮我挡掉了好几次配置错位。希望帮到你。
本文还有配套的精品资源,点击获取