简介这是一份面向需要在CentOS7等Linux环境部署分布式数据库中间件的开发与运维人员的Mycat 1.6.7.1安装包解决大规模数据分库分表、读写分离与高可用问题。压缩包共95个文件大小16.74MB主要包含42个Java依赖库如MySQL驱动、Druid连接池、Netty通信组件、16个properties配置文件、14个txt规则说明、10个xml核心配置与4个启停Shell脚本以及适配不同Linux架构的动态库可直接用于生产或学习环境。已有494人学习下载。通过配置server.xml、schema.xml等文件可快速规划数据节点与分片策略包内自带多种分片规则、序列生成方案及ZooKeeper相关配置便于理解Mycat路由机制配套的启动脚本和日志配置能帮助读者完成基础部署与调试。适合希望从零搭建数据库中间件集群、深入掌握分片规则和连接池调优的进阶读者。1. 从 Mycat-server-1.6.7.1-release-20190213150257-linux.tar.gz 说起分库分表中间件的落地价值Mycat 1.6.7.1 是我在多个生产项目里反复用过的 MySQL 分库分表中间件版本包文件名里的 20190213150257 是 2019 年 2 月 13 日的构建时间戳linux.tar.gz 表示面向 Linux 平台的发布产物。这个版本解决的核心问题是当单库单表扛不住流量和数据量时业务代码不需要大改就能把数据分布到多台 MySQL 实例上。对后端开发者来说它把分片路由、读写分离、连接复用这些逻辑收了进去应用层面对的仍是一个逻辑数据库。适合正在做数据量预估超过单机 MySQL 承载范围的中小型团队或者想在不改动 SQL 的前提下完成水平拆分的存量系统。2. 部署前的一个关键问题JDK 与 tar 包解压的完整准备2.1 版本与环境的匹配为什么 JDK 版本不能乱选Mycat 1.6.7.1 用 Java 编写官方要求的运行环境是 JDK 1.7 或 1.8。我在实际部署时强烈建议用 JDK 1.8 的最新补丁版本因为 1.6.7.1 的某些代码路径依赖了 Java 8 才稳定的 NIO 行为如果直接上 JDK 11 或更高版本会出现启动后 CPU 占用异常或者集群通信超时的问题。这类问题不报错、不崩溃只在流量上来之后以性能劣化的方式暴露排查成本很高。常见的做法是在服务器的 /etc/profile 或 ~/.bashrc 里固定 JAVA_HOME然后用一个干净的 shell 窗口来启动防止环境变量污染。先看 JDK 是否就位java -version # 期望输出 1.8.0_xxx不要用 openjdk 11 以上版本跑 1.6.7.1终端里输出结果必须包含准确的版本行如果系统里装了多个 JDK可以用which java和readlink -f $(which java)确认实际指向的路径。我在某公司内部服务器上遇到过默认 java 指向 jre 而不是 jdk导致后续mycat start脚本找不到 tools.jar 而报错。这是启动脚本里的JAVA_HOME/lib/tools.jar依赖导致的所以环境变量里必须写 JDK 的根目录不能写 JRE 目录。2.2 解压 tar 包与目录结构哪些目录可以动哪些不能动拿到Mycat-server-1.6.7.1-release-20190213150257-linux.tar.gz后解压得到 mycat 根目录。常见的部署位置是/opt/mycat或/usr/local/mycat我一般固定放在/opt/mycat并做一个软链用于版本切换。解压命令如下tar -zxvf Mycat-server-1.6.7.1-release-20190213150257-linux.tar.gz -C /opt/ mv /opt/mycat /opt/mycat-1.6.7.1 ln -s /opt/mycat-1.6.7.1 /opt/mycat解压后目录的核心分这几块bin目录放启动脚本和命令行工具conf目录放核心配置文件lib目录放依赖 jar 包logs目录在启动后生成运行日志。conf目录是整个中间件的配置中心schema.xml、server.xml、rule.xml三个文件决定了路由逻辑和对外表现。如果不需要切换版本软链这步可以跳过但建议保留因为 Mycat 的升级通常不是小版本平滑替换保留完整旧目录能让你在灰度失败时快速切回。ls /opt/mycat/ # 预期看到 bin conf lib logs 等目录注意解压出来的目录归属一定是执行解压的用户如果后面用 systemd 或自定义脚本托管需要把整个 mycat 目录的 owner 改为运行用户。我踩过权限坑启动用户对 lib 目录没有读权限时进程能起但一旦执行到某个异步线程加载类就会抛 NoClassDefFoundError表象非常迷惑。2.3 启动方式的选择console 模式适合第一次部署Mycat 1.6.7.1 的启动脚本在bin目录下支持start和console两种方式。第一次部署我一定用console模式因为它把日志直接打到当前终端配置错误、端口占用、参数读取异常都能在第一时间看到。后台启动只截图报错日志时会漏掉标准输出里的关键堆栈。/opt/mycat/bin/mycat console # 前台运行CtrlC 可以停止适合首次验证配置启动成功的标志是看到Mycat Server startup successfully字样然后终端开始输出 MyCAT 的欢迎日志。确认无误后再CtrlC停掉改用mycat start后台启动/opt/mycat/bin/mycat start /opt/mycat/bin/mycat status # status 命令会输出进程和端口情况日志文件位置是logs/mycat.log和logs/wrapper.log。启动失败时先看logs/wrapper.logJVM 层面没有被捕获的异常都在这里比如端口被占、堆内存分配失败mycat.log里主要是业务层面的路由和连接池信息。两个日志分开看能避免堆栈信息混杂这是排查的基础。3. 三张核心配置server.xml、schema.xml、rule.xml 的联动与参数详解3.1 server.xml用户权限、逻辑库与系统级参数Mycat 对外暴露的是逻辑库和逻辑表应用连接 Mycat 时使用 MySQL 协议所以在server.xml里要定义一套用户账号。这套账号和后端 MySQL 账号无关只是 Mycat 作为 MySQL Server 对应用暴露的凭证。server.xml的 user 节点里重点配置逻辑库权限schema属性指定这个用户能看到哪个逻辑库readOnly控制只读dml控制 CRUD 四种操作是否允许。配置示例user nameapp_user defaultAccounttrue property namepasswordApp123456/property property nameschemasorder_db/property property namereadOnlyfalse/property /user参数说明name是用户名password是明文密码Mycat 1.6.7.1 没有加密机制配置文件权限要收紧到仅限运维账号可读schemas指向逻辑库这个逻辑库必须在schema.xml里存在否则启动直接报错readOnly设为 true 后该用户只能执行 SELECT 和 SHOW。权限粒度只能到库不能到表这是 Mycat 的边界如果业务要求字段级权限就不能靠 Mycat 实现。system节点里还有几个生产必调参数maxStringLiteralLength控制大 SQL 的解析兼容性defaultSqlParser决定 SQL 解析器的行为。1.6.7.1 默认用的解析器对于多表 JOIN 和子查询的支持已经比较成熟但遇到GROUP BY加聚合函数的复杂查询仍可能出现路由到所有分片再合并的情况这不算 bug而是分片中间件的通用取舍。3.2 schema.xml逻辑库到物理节点的映射schema.xml是整个 Mycat 的架构灵魂它定义了逻辑库、物理数据节点、后端 MySQL 实例三者之间的映射关系。一个schema标签代表一个逻辑库库里的table标签声明了哪些表需要分片、分片键是什么、分片规则叫什么。不声明table的表会被当作全局表默认每台物理库都同步一份。配置片段schema nameorder_db checkSQLschemafalse sqlMaxLimit100 table nameorder_info dataNodedn1,dn2 rulemod-long / table nameglobal_config typeglobal dataNodedn1,dn2 / /schema dataNode namedn1 dataHosthost1 databaseorder_db_1 / dataNode namedn2 dataHosthost2 databaseorder_db_2 /checkSQLschema设为 false 更稳妥设为 true 时如果应用 SQL 里带了库名前缀Mycat 会自动截掉但在一些老版本里这个动作有性能损耗。sqlMaxLimit是防误查的兜底客户端不带 limit 的 SELECT 会被自动追加上限避免应用写了个全表查询直接把所有分片压垮。dataNode的database属性指向物理库名物理库要提前在 MySQL 里建好Mycat 不会自动建库建表。在我用 1.6.7.1 搭建的模拟项目 X 中遇到过一种很容易犯的错误把表分片了但数据导入脚本里用了INSERT ... ON DUPLICATE KEY UPDATE这种 SQL 在分片键更新时会被 Mycat 拒绝或路由到错误节点。分片表要求写操作必须携带分片键且不能更新分片键字段这是规则层面写死的约束不是参数能改的。3.3 rule.xml分片规则与函数的对应rule.xml里定义了表的切分策略。每张分片表通过tableRule把表名、分片键、分片函数绑定在一起。分片函数是function节点它决定了数据行的目标节点。1.6.7.1 内置了取模、范围、枚举、一致性哈希等函数用的最多的是mod-long取模和partition-by-long范围。一个典型配置tableRule namemod-long rule columnsid/columns algorithmmod-long-function/algorithm /rule /tableRule function namemod-long-function property namecount2/property /functioncolumns指定分片键algorithm引用 function 名称count是分片数量。这个数量必须和schema.xml里对应表的 dataNode 个数一致否则启动不报错但路由结果会出现数据落在不存在的节点上。我习惯把 count 写成分片总数而不是某个分片区的编号这样后续扩容时只需要新增 function 逻辑不容易产生歧义。4. 分片规则的实际行为取模、范围、枚举在 1.6.7.1 里的边界条件4.1 取模分片简单直接但要提前想好扩容策略取模分片把分片键的值对分片数求余结果对应节点编号。比如 count2id5 会落到 dn1id6 落到 dn2。这个规则的最大优点是数据分布均匀写入压力能平均分摊到各物理库。最大缺点是扩容要找数从 2 个分片扩到 3 个分片取模结果全体变化几乎每个数据行都可能要搬家这个过程必须用离线迁移工具或者应用双写补偿。取模分片适合高写入量的流水型业务比如订单流水、日志表。我在某舆情项目的存储层里用过这方案数据量大但 key 是单调递增的自增 ID流量均匀节点间数据量差距不超过 5%。但如果分片键不是自增主键而是业务随机字符串取模的分布还相对均匀一旦分片键有明确的业务坡度比如按时间递增取模后的热点会漂移需要配合索引和查询条件来规避。4.2 范围分片区间稳定但容易形成数据倾斜范围分片用枚举分区函数实现核心思路是按分片键的数值区间划分节点。id 在 1 到 1000 之间走 dn11001 到 2000 走 dn2。它的好处是扩容时只需要新增节点并调整区间存量数据不用大规模搬迁坏处是数据分布完全取决于业务自增的节奏如果某段时间业务爆发一个区间灌满其他区间闲置中间件层面没有任何自动均衡机制。function namerange-long property namemapFilepartition-range.txt/property property namedefaultNode0/property /functionmapFile指向一个文本文件内容格式每行如0-10000表示 0 到 1000 区间的数据落到节点 0defaultNode兜底落在哪个节点如果分片键不在此文件内的任何区间则走默认节点。这个兜底策略很重要不然数据会直接报 cant find any valid datanode 的异常。4.3 枚举分片按业务维度归档适合区域性数据枚举分片适合分片键是有限取值集合的业务比如按省份、按渠道、按机房 ID。它把每个枚举值映射到一个固定节点控制力最强但也最容易出现节点不均。某省份数据量大该节点永远是热点。1.6.7.1 的partition-by-enum支持枚举到节点的多对一映射也就是多个枚举值可以指向同一个节点这能在一定程度上缓解热点但无法自动感知数据量。经验上用枚举分片时不要把节点数设得太少否则一旦某个枚举值的数据爆发式增长只能靠手动迁移。迁移时要注意枚举文件改动后必须重启 Mycat 才生效没有热加载机制。我见过某开发者用reload config指令做配置重载发现枚举文件不刷新最后手动重启才生效。这块文档写得不明确容易耽误事。4.4 join 和全局表跨分片查询的正确打开方式分片表之间的 JOIN 是 Mycat 最容易翻车的地方。两张大表都分片且关联字段不是同一套分片键JOIN 会在中间件层产生大量跨节点数据传输性能不可控。常见做法是必须 JOIN 的维度表定义为global全局表每台物理库放一份完整副本分片表可以与其直接 JOIN两张分片表之间的 JOIN 要么通过冗余字段解耦要么把 JOIN 下沉到应用层分多次查询后在内存里聚合。全局表的问题是写放大每次写全局表都会广播到所有节点。我在一个订单系统里把用户表设为全局表注册高峰时写放大直接拖慢所有分片。后来改成按用户 ID 取模分片其他表也按用户 ID 分片这样同一个用户的数据天然落在同一节点JOIN 就变成单节点内部 JOIN中间件不需要跨库传输。这个设计思路比任何配置调优都重要。5. 生产落地避坑Mycat 1.6.7.1 的启动失败与运行异常排查清单5.1 启动即失败日志里只有 Java 异常没有 Mycat 相关输出现象执行mycat console后终端直接抛 java.lang.ClassNotFoundException 或 java.lang.NoClassDefFoundError根本看不到 Mycat 自己的日志。原因最常发生在 JDK 版本不对或者环境变量指向了 JRE。Mycat 的启动脚本会在 classpath 里加载$JAVA_HOME/lib/tools.jarJRE 目录下不存在该文件启动直接失败。解决先执行echo $JAVA_HOME确认路径再确认$JAVA_HOME/bin/java存在。如果系统里同时装了多个 JDK显式在启动脚本前覆盖变量export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk export PATH$JAVA_HOME/bin:$PATH /opt/mycat/bin/mycat start5.2 进程起来了但连不上 8066 端口端口绑定与配置库的对应关系现象mycat status显示进程存在但应用连接 8066 端口超时telnet 127.0.0.1 8066不通。原因8066 是 Mycat 的默认连接端口但有可能被server.xml或wrapper.conf里的参数覆盖。还有一种情况是只启动了管理端口 9066业务端口没起。解决先看logs/mycat.log里Server startup successfully附近有没有端口打印再用netstat -anp | grep java查看实际监听端口。如果配置没被改动过但还是连不上检查 iptables 和云平台安全组是否放行 8066。生产上遇到过 9066 通、8066 不通的情况多半是防火墙规则没放全。5.3 连接池报错 Connection refused 或 Too many connections现象应用日志表明 Mycat 能连上但执行 SQL 时报后端 MySQL 连接失败错误信息是Connection refused或Data source rejected establishment of connection。原因Mycat 与后端 MySQL 的连接池配置在dataHost节点里maxCon参数控制每个 dataHost 的最大连接数。如果后端 MySQL 的max_connections不够或者 balance 配置导致请求全部打到一个后端实例就会出现连接耗尽。解决后端 MySQL 的max_connections要调大同时 Mycat 的maxCon要小于它。典型配置dataHost namehost1 maxCon100 minCon10 balance0 writeType0 dbTypemysql dbDriverjdbc heartbeatselect user()/heartbeat writeHost hosthost1w url192.168.1.10:3306 usermycat_user passwordxxx / /dataHostbalance0表示不做读负载均衡只走写库balance1和balance2决定读写分离时如何分配读请求。writeType0表示写请求只发到第一个 writeHostwriteType1表示所有 writeHost 都参与写。如果配了多写而中间件版本对事务支持不够会造成一致性问题1.6.7.1 建议先把多写关掉用主从复制解决写扩展。5.4 心跳语句选错导致误判主从切换现象什么都没动但 Mycat 日志里频繁出现switch datasource或者从库被标记为不可用。原因heartbeat标签里的检测语句决定 Mycat 怎么判断后端 MySQL 是否存活。选select 1对 SQL 权限要求最低但它只能证明 MySQL 进程活着无法证明该库能正确服务业务查询。如果 MySQL 处于锁定状态或半连接状态select 1依然会成功Mycat 误以为一切正常反之如果用select user()且账号授权不全心跳失败就会触发误切。解决心跳语句统一使用select 1同时在后端 MySQL 侧检查 mycat_user 的权限确保至少拥有 SHOW DATABASES 和 SELECT 权限。如果主从之间延迟大可以在心跳里加时间字段检测但 1.6.7.1 对主从延迟的内建处理不完善更稳妥的手段是查看 MySQL 自己的 Seconds_Behind_Master 指标在应用层配合重试机制。5.5 SQL 能查到数据但与分片预期不符现象对分片表执行SELECT COUNT(*)结果比实际少或者根据分片键查某条数据偶尔查不到。原因这是分片键选择问题而不是 Mycat bug。分片查询的套路是SQL 里带了分片键的条件时Mycat 能直接路由到对应节点不带分片键条件时Mycat 会把 SQL 发到全部分片然后合并结果。COUNT(*)在全分片合并时没有问题但如果业务里用了LIMIT配合ORDER BY且排序字段不是分片键Mycat 可能只取每个节点排序后的前 N 条再合并时已经丢失了全局正确顺序。解决业务 SQL 必须保证分片键等值条件存在分页查询里不要用LIMIT 1000,20这种深分页Mycat 和 MySQL 一样会全分片扫描。排序字段尽量和分片键绑定要么就让排序只对单分片内数据有意义。这是中间件方案的通用约束改配置解决不了得改应用 SQL。6. 交付验收的小技巧用 status 和日志定位问题而不是猜收尾直接给一个我常用的验收习惯每套 Mycat 环境交付前我会把mycat status、logs/mycat.log尾部输出、netstat端口监听三项数据留档。后续运维介入时这几份快照能省两小时的排查时间。启动成功后依次执行/opt/mycat/bin/mycat status tail -n 50 /opt/mycat/logs/mycat.log netstat -anp | grep -E 8066|9066status能看到进程 ID 和运行时长确认不是僵尸进程日志尾部重点看有没有异常堆栈端口监听看有没有绑定到 127.0.0.1 而不是 0.0.0.0后者会导致远程应用连不上。再往下看数据正确性可以从应用层读取一条已知分片键的数据确认它落在预期的物理库。分片键取 1 和取 2 分别测一次就能覆盖不同节点的路由。生产环境我会再创建一个只读监控账号定期执行SELECT COUNT(1) FROM information_schema.tables对比各分片的数据量分布提前发现倾斜。这个习惯挽回过一次事故某业务分片键是自增主键但中间有段时间导入了历史数据导致新数据全走一个分片另一个分片几乎空闲应用查询响应开始抖动。如果只盯着 Mycat 层面的日志根本看不到这个走向。最后想说的是Mycat 1.6.7.1 是我用过的版本里比较稳定的一个 1.6 终结版它谈不上完美但你对它的分片边界理解得越清楚踩的坑就越少。每次把分片键选错、把全局表滥用、把连接池调爆折腾下来都是一轮血泪经验。希望这篇笔记能帮你在选型和技术落地的第一个月就避开这些坑把时间花在业务数据模型的设计上而不是和中间件本身纠缠。本文还有配套的精品资源点击获取