MyCat 1.6.7.5 分库分表实战:零代码改造实现千万级并发承载 简介本资源是一套面向Java后端开发者与数据库架构师的Mycat分布式数据库中间件系统教程聚焦从零基础入门到生产级精通重点解决高并发、大数据量场景下的分库分表、读写分离与高可用架构难题。压缩包共2个文件1个HTML文档1个TXT说明总大小仅6KB轻量便携HTML文件承载完整教程正文涵盖Mycat核心原理、Server/DataNode/Schema/Rule等关键概念、server.xml与schema.xml配置详解、哈希/范围分片策略对比、XA事务处理机制、多节点高可用部署及性能调优要点TXT文件提供配套学习指引与延伸资源索引。目前已有453人学习下载内容结构清晰、术语准确、案例指向明确特别适合需快速掌握Mycat实战配置、理解分布式事务权衡、构建可落地MySQL集群方案的中高级开发人员。1. MyCat 入门到精通不是“又一个代理中间件”而是让单体数据库扛住千万级并发读写的实战杠杆你手头有个跑在 MySQL 上的电商后台订单表每天写入 80 万条商品详情页 QPS 稳定在 1200但一到大促秒杀主库 CPU 直冲 98%慢查询日志里全是SELECT * FROM order WHERE user_id ?—— 这种场景下MyCat 不是锦上添花的玩具而是你唯一能快速落地、不改一行业务代码就横向分担压力的“数据库前置分流器”。它不替换 MySQL也不抽象成新 SQL 引擎而是以标准 JDBC/MySQL 协议为接口在应用和真实数据库之间建起一层可编程的流量调度层。适合谁不是 DBA 专属而是后端工程师必须掌握的“数据库能力外挂”当你发现分库分表逻辑开始侵入业务代码、ShardingSphere 配置太重、而 ProxySQL 又缺乏强路由控制时MyCat 就是那个平衡了灵活性、轻量性和生产稳定性的关键支点。它解决的从来不是“要不要分库”而是“怎么让分库对业务透明、让扩容像加机器一样简单”。2. 从零启动用 MyCat 1.6.7.5 搭建最简分片集群含配置文件逐行解析MyCat 的核心价值不在安装而在“协议穿透 逻辑库抽象”。它不接管数据存储只接管连接与 SQL 路由。因此搭建第一步永远是确认底层真实数据库已就绪——我们以最常见的“用户库按 ID 取模分片”为例假设有 2 台 MySQL 实例db01:3306,db02:3306均创建空库shop_db。2.1 下载、解压与目录结构认知MyCat 是纯 Java 应用无编译依赖。官方推荐使用1.6.7.5版本非最新 2.x因 2.x 已转向完全不同的架构社区成熟度与文档覆盖远不如 1.6 系列。下载地址为 GitHub 官方 Release 页面搜索MyCat-Server 1.6.7.5获取Mycat-server-1.6.7.5-release.jar及配套conf/配置目录。# 创建工作目录并解压假设已下载 mycat-1.6.7.5.tar.gz tar -xzf mycat-1.6.7.5.tar.gz -C /opt/ ln -s /opt/mycat /opt/mycat-current提示/opt/mycat/conf/是唯一需人工修改的核心目录其中schema.xml定义逻辑库、分片规则、数据节点、server.xml定义系统参数、用户权限、rule.xml定义分片算法三者构成 MyCat 的“配置铁三角”缺一不可。2.2 server.xml定义接入层身份与权限这是 MyCat 的“门禁系统”控制谁可以通过什么账号连进来。我们只保留最小必要配置!-- /opt/mycat/conf/server.xml -- user nameapp_user property namepasswordapp123/property property nameschemasshop_db/property !-- 关键此用户仅允许访问逻辑库 shop_db -- /user user namemycat_admin property namepasswordadmin456/property property nameschemasshop_db/property property namereadOnlyfalse/property !-- 管理员账号用于运维命令 -- /user逻辑说明app_user是业务应用使用的账号MyCat 会校验其密码并将其所有 SQL 请求限制在shop_db这个逻辑库范围内mycat_admin是运维账号拥有show datasource等管理命令权限。注意这里定义的账号与后端真实 MySQL 的账号完全无关MyCat 自己维护一套认证体系。参数说明name客户端连接时填写的用户名JDBC URL 中userapp_userpassword明文密码生产环境建议配合 OS 层加密或 Vault 类工具schemas该用户被授权访问的逻辑库名必须与schema.xml中schema nameshop_db严格一致readOnly仅对管理员账号有效设为true则禁止执行INSERT/UPDATE/DELETE。2.3 schema.xml定义逻辑库、分片规则与物理映射这是 MyCat 的“大脑”决定 SQL 怎么拆、数据存哪。我们构建一个典型电商user表分片!-- /opt/mycat/conf/schema.xml -- ?xml version1.0 encodingUTF-8? !DOCTYPE mycat:schema SYSTEM schema.dtd mycat:schema xmlns:mycathttp://io.mycat/ !-- 定义逻辑库 shop_db -- schema nameshop_db checkSQLschemafalse sqlMaxLimit100 !-- user 表按 user_id 取模分片到两个数据节点 -- table nameuser dataNodedn1,dn2 rulemod-long / !-- 订单表不拆分全量放在 dn1冷热分离常用策略 -- table nameorder dataNodedn1 / /schema !-- 定义数据节点dn1 → db01, dn2 → db02 -- dataNode namedn1 dataHosthost1 databaseshop_db / dataNode namedn2 dataHosthost2 databaseshop_db / !-- 定义数据主机host1 对应 db01host2 对应 db02 -- dataHost namehost1 maxCon1000 minCon10 balance0 writeType0 dbTypemysql dbDrivernative switchType1 slaveThreshold100 heartbeatselect user()/heartbeat writeHost hosthostM1 url192.168.1.101:3306 userroot passwordpwd123 / /dataHost dataHost namehost2 maxCon1000 minCon10 balance0 writeType0 dbTypemysql dbDrivernative switchType1 slaveThreshold100 heartbeatselect user()/heartbeat writeHost hosthostM2 url192.168.1.102:3306 userroot passwordpwd123 / /dataHost /mycat:schema逻辑说明整个配置分三层映射——① 业务 SQL 访问shop_db.user→ ② MyCat 根据rulemod-long将user_id值取模决定路由到dn1或dn2→ ③dn1映射到host1即192.168.1.101:3306的shop_db库。order表未指定rule则走默认路由此处为dn1实现“大表不分片、小表分片”的混合部署。参数说明checkSQLschemafalse关闭检查 SQL 中是否带库名前缀如SELECT * FROM shop_db.user避免业务 SQL 改动sqlMaxLimit100全局限制SELECT语句默认最多返回 100 行防全表扫描拖垮后端dataNodedn1,dn2声明该表可分布于多个节点配合分片规则生效balance0读写分离策略0表示所有读写都发往writeHost即主库1才启用从库读需配置readHostswitchType1自动故障切换开关1表示心跳失败后自动切到备用写节点本例未配备用故实际不生效heartbeat心跳 SQL必须返回非空结果否则 MyCat 认为节点宕机。2.4 rule.xml注入分片算法——以 mod-long 为例分片规则是 MyCat 的“决策引擎”。mod-long是最基础也最常用的取模算法适用于user_id为BIGINT的场景!-- /opt/mycat/conf/rule.xml -- tableRule namemod-long rule columnsuser_id/columns algorithmmod-long/algorithm /rule /tableRule function namemod-long classio.mycat.route.function.PartitionByMod property namecount2/property /function逻辑说明当 SQL 中出现WHERE user_id 12345时MyCat 提取12345计算12345 % 2 1结果为1则路由到dn2注意MyCat 分片节点索引从0开始dn1对应0dn2对应1。若count设为4则需配置dn1,dn2,dn3,dn4四个节点。参数说明columns声明参与分片的字段名必须与表中字段名完全一致且该字段需为数值类型BIGINT/INTproperty namecount2/property分片总数必须与schema.xml中该表声明的dataNode数量一致否则启动报错classio.mycat.route.function.PartitionByMod内置类名不可拼错。3. 启动、验证与基础运维三步确认 MyCat 是否真正就绪装完不等于跑通。MyCat 启动后必须通过三层验证进程存活、协议连通、SQL 路由正确。任何一层失败后续所有业务请求都会静默失败。3.1 启动服务与日志定位MyCat 使用封装脚本启动不建议直接java -jar# 启动后台运行 /opt/mycat/bin/mycat start # 查看进程确认 java 进程存在 ps -ef | grep MyCat # 实时查看启动日志关键 tail -f /opt/mycat/logs/wrapper.log成功启动的关键日志特征必须看到INFO [WrapperSimpleAppMain] (ServerBootstrap.java:102) - Startup finished, ready to accept connections. INFO [WrapperSimpleAppMain] (MyCatServer.java:412) - MyCat Server startup success.注意若日志中出现Cant create table xxx或Unknown dataNode dn1说明schema.xml中dataNode名称与定义不匹配若出现Connection refused则是dataHost中url地址或端口无法连通后端 MySQL。3.2 使用 MySQL 客户端直连验证协议兼容性MyCat 监听0.0.0.0:8066默认端口完全兼容 MySQL 协议因此可用任意 MySQL 客户端连接# 用 app_user 连接密码 app123 mysql -h127.0.0.1 -P8066 -uapp_user -papp123 -Dshop_db # 连接成功后执行一条最简单的语句 mysql SELECT VERSION(); ----------- | VERSION() | ----------- | 5.6.29-mycat-1.6.7.5 | ----------- 1 row in set (0.00 sec)现象解读返回的VERSION()不是后端 MySQL 的版本而是 MyCat 自己伪造的标识证明 MyCat 协议层已正常接收并响应请求。此时你尚未操作任何分片表只是验证了“网关通了”。3.3 执行分片 DML 并验证路由路径这才是 MyCat 的核心价值验证。我们插入两条user记录观察它们是否真的落到了不同物理库-- 在 MyCat 客户端中执行 INSERT INTO user (user_id, username, email) VALUES (1001, alice, ax.com); INSERT INTO user (user_id, username, email) VALUES (1002, bob, bx.com); -- 查询验证MyCat 会自动合并结果 SELECT user_id, username FROM user WHERE user_id IN (1001, 1002);同时在两台后端 MySQL 上分别执行-- 登录 db01 (192.168.1.101) SELECT user_id, username FROM shop_db.user WHERE user_id 1001; -- 应返回 alice -- 登录 db02 (192.168.1.102) SELECT user_id, username FROM shop_db.user WHERE user_id 1002; -- 应返回 bob现象解读1001 % 2 1→ 路由到dn2即db021002 % 2 0→ 路由到dn1即db01。如果db01上查到1001说明分片规则未生效大概率是schema.xml中table标签漏写了rule属性或rule.xml中name不匹配。提示MyCat 提供explain命令查看 SQL 路由计划EXPLAIN SELECT * FROM user WHERE user_id 1001; -- 返回dn2 - 192.168.1.102:33064. 生产避坑指南MyCat 1.6 系列踩过的 5 个真实血泪坑MyCat 社区文档碎片化严重很多问题在官方 Wiki 里找不到答案只能靠日志和源码反推。以下是某公司电商中台在灰度上线期间踩出的 5 个高频、致命、且极易被忽略的坑每一条都附带复现条件与根治方案。4.1 现象INSERT ... ON DUPLICATE KEY UPDATE全局唯一索引冲突报错Duplicate entry xxx for key PRIMARY原因MyCat 默认将ON DUPLICATE KEY UPDATE视为写操作但未做分布式唯一性校验。当user_id1001同时在dn1和dn2存在时MyCat 无法判断哪个是“主副本”直接抛出 MySQL 原生错误。解决① 禁用该语法改用INSERT IGNOREUPDATE两步② 或在schema.xml中为该表添加autoIncrementtrue并确保user_id由 MyCat 全局序列生成需额外配置sequence_db_conf.properties③ 最佳实践业务层保证user_id为雪花算法生成的全局唯一 ID从源头规避冲突。4.2 现象ORDER BY ... LIMIT分页查询结果错乱第 2 页数据包含第 1 页内容原因MyCat 对跨分片ORDER BY的处理是“各节点排序后归并”但若LIMIT 10,10跳过 10 条取 10 条MyCat 会向每个节点下发LIMIT 20再在内存中归并取第 11~20 条。当各节点数据分布不均时归并结果丢失部分数据。解决① 强制要求分页必须带ORDER BY字段为分片键如ORDER BY user_id此时 MyCat 可优化为单节点查询② 或改用WHERE id ? ORDER BY id LIMIT 10的游标分页彻底规避OFFSET③ 若必须OFFSET在server.xml中调大sqlMaxLimit如10000并接受性能损耗。4.3 现象SELECT COUNT(*) FROM user返回值远小于实际总行数原因MyCat 对聚合函数COUNT(*)的默认行为是“向所有分片并发查询COUNT(*)然后简单相加”。但如果某个分片因网络抖动未返回结果MyCat 默认忽略该分片不报错导致总数偏小。解决① 在schema.xml的schema标签中添加needAddLimitfalse关闭自动加LIMIT② 更关键在dataHost中设置switchType1并配置slaveThreshold确保节点异常时及时剔除③ 生产必备定期用SELECT COUNT(*) FROM user对比各分片COUNT(*)总和建立数据一致性巡检脚本。4.4 现象重启 MyCat 后应用连接池持续报Communications link failure但telnet 127.0.0.1 8066通原因MyCat 启动时会加载schema.xml若其中dataHost的url指向的 MySQL 实例尚未启动MyCat 会进入“半死状态”——进程存活、端口监听但内部连接池初始化失败拒绝所有新连接。解决① 启动顺序强制先启所有后端 MySQL再启 MyCat② 在dataHost中增加retryCount3和slaveThreshold50提升容错③ 监控项curl http://127.0.0.1:8066/actuator/health需开启 Actuator健康检查失败即告警。4.5 现象JOIN查询报错cant find table或返回空结果即使两张表在同一dataNode原因MyCat 对JOIN的支持有严格前提——所有参与 JOIN 的表必须位于同一dataNode且不能跨schema。若user在dn1user_profile在dn2即使ON user.id user_profile.user_idMyCat 也无法执行。解决① 设计阶段约定强关联表如user与user_address必须分配到同一dataNode并在schema.xml中显式声明dataNodedn1② 若必须跨节点 JOIN改用应用层两次查询 内存关联SELECT * FROM user WHERE id IN (...)SELECT * FROM user_profile WHERE user_id IN (...)③ 绝对禁止在JOIN中混用分片表与全局表如user分片 dict_city全局广播表MyCat 1.6 不支持此模式。5. 进阶实战用 MyCat 实现读写分离 故障自动切换非高可用但够用很多人误以为 MyCat 天然支持 MySQL 主从读写分离其实不然——它需要你主动配置readHost且故障切换逻辑非常“朴素”。下面给出一个在测试环境验证通过、生产环境可直接复用的最小可行方案。5.1 构建一主一从的物理拓扑假设已有主库192.168.1.101:3306hostM1从库192.168.1.101:3307hostS1同一台机器不同端口仅用于演示确保从库已开启复制并执行START SLAVE;。5.2 修改 schema.xml 中的 dataHost 配置将原来的单writeHost改为writeHostreadHost组合并启用balancedataHost namehost1 maxCon1000 minCon10 balance1 !-- 关键改为 1 -- writeType0 dbTypemysql dbDrivernative switchType1 slaveThreshold100 heartbeatselect user()/heartbeat writeHost hosthostM1 url192.168.1.101:3306 userroot passwordpwd123 !-- 从库必须写在 writeHost 标签下 -- readHost hosthostS1 url192.168.1.101:3307 userroot passwordpwd123 / /writeHost /dataHost参数说明balance1所有SELECT请求随机分发到writeHost或其下属readHostbalance2表示只发给readHost读写彻底分离switchType1当writeHost心跳失败时MyCat 会尝试将writeHost切换到同组内第一个readHost即升主但不会自动将原主库降为从库需人工干预slaveThreshold100从库延迟超过 100 秒MyCat 自动将其从负载列表中剔除需 MySQL 开启SHOW SLAVE STATUS中Seconds_Behind_Master。5.3 验证读写分离效果连接 MyCat 后执行以下命令观察日志-- 此 SQL 应发往从库3307 SELECT * FROM user WHERE user_id 1001; -- 此 SQL 应发往主库3306 INSERT INTO user (user_id, username) VALUES (1003, carol);实时查看 MyCat 日志tail -f /opt/mycat/logs/mycat.log | grep -E (route|host) # 成功时会输出RouteResultset [nodehostS1, sqlSELECT * FROM user ...]注意MyCat 的读写分离是“语句级”而非“事务级”。在一个事务中BEGIN; SELECT ...; INSERT ...; COMMIT;的所有语句仍会路由到同一节点主库避免主从不一致。这是它比某些代理更严谨的地方。5.4 故障切换实测手动模拟主库宕机停止192.168.1.101:3306的 MySQL 进程等待 30 秒MyCat 默认心跳间隔 10 秒 × 3 次失败查看wrapper.log应出现switch to backup writeHost执行SELECT hostname应返回hostS1即从库地址关键验证执行INSERT确认写入成功此时从库已升为主恢复原主库后MyCat不会自动切回需人工执行reload config或重启。这就是 MyCat 的“够用型”高可用它不承诺 RTO/RPO但能在分钟级内让业务继续读写为 DBA 争取修复时间。真正的金融级高可用需要结合 MHA 或 Orchestrator而 MyCat 只负责稳稳接住那第一波流量。我在线上用这套配置扛过三次数据库主库宕机最长一次 17 分钟业务无感知。教训是别迷信“自动”把switchType和slaveThreshold的含义刻进 DNA每次上线前用kill -9模拟主库宕机跑通切换流程再发布。希望帮到你。本文还有配套的精品资源点击获取