ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

MyCat实战指南:读写分离与分库分表配置及踩坑实录

MyCat实战指南:读写分离与分库分表配置及踩坑实录 简介一套针对Mycat分布式数据库中间件的入门到精通教程适合后端开发、DBA及架构师阅读帮助解决大数据场景下的分库分表、分布式事务和高可用难题。内容覆盖Mycat核心概念、Server/DataNode/Schema/Rule等组件与分片规则讲解安装配置、哈希/范围/列表等分片策略、XA两阶段提交分布式事务以及心跳检测和主从复制高可用方案同时给出SQL优化、连接池、负载均衡等调优思路并附监控日志、电商与社交实战案例及与ShardingSphere、Cobar的选型对比。压缩包共2个文件以1个HTML教程页面为主体另配1个TXT清单整体仅6KB轻量易读TXT中整理了15套Java架构师大型分布式综合项目实战视频课程及高端课程目录可作为后续进阶学习的检索索引。已有445人学习适合处于分库分表选型或Mycat实践入门阶段的开发者参考。 先说一个我自己的判断分布式数据库中间件这个领域概念一堆真正常年被生产环境检验的其实就那几个。MyCat属于老资历社区活跃度虽然比不过ShardingSphere但胜在轻、直接、配置上手快尤其在国内大量MySQL单机架构向读写分离、分库分表演进的过程中MyCat几乎是绕不开的一课。这篇文章我按照自己从零摸到生产落地的路径来写不走官方文档复读机路线。你会发现很多配置细节文档里不会明说只有把数据真正灌进去、把流量真正打过去才看得见坑在哪里。1. 什么项目该上MyCat先想清楚这四件事MyCat本质上是Java写的数据库路由中间层它伪装成一个MySQL服务器应用层用JDBC连它它再把SQL转发给后端的真实MySQL实例。所以底层不管是单实例、主从复制还是一套分布式存储对于业务代码来说都是透明的。那是不是所有项目都适合上我见过太多团队把MyCat当成银弹结果引入之后比原来更痛苦。我的判断标准很简单四个问题过一遍当前瓶颈到底是读还是写MyCat读写分离只能解决读压力。如果单库写入已经是瓶颈读写分离解决不了根本问题得走分库分表。业务SQL是否足够规整分库分表后不带分片键的查询、跨节点的JOIN、子查询、多表关联事务都会变成灾难。如果业务是报表类、复杂关联类SQL满天飞MyCat会把你折腾到怀疑人生。团队有没有MySQL主从复制经验MyCat读写分离只是路由主从延迟、数据一致性、故障切换这些底层能力依赖的是MySQL主从本身。主从都没玩明白就上MyCat等于房子地基没打就装门。数据量真的到了非分不可的地步吗我见过单表几百万行就喊着要分库分表的项目其实加了索引、做了归档完全能扛。分库分表是有代价的——查询复杂度上升、跨节点事务受限、扩容要重新分布数据。不到万不得已别主动给自己找事。如果这四个问题想清楚了确定要走这条路那MyCat确实是一个非常合适的切入点。它不像ShardingSphere那样需要改动数据源配置、侵入性相对强MyCat就是独立部署一个中间层业务代码改动最小。1.1 MyCat到底帮你做了什么打个比方MyCat就像一个前台客服客户应用提需求SQL客服根据需求单上的信息分片键快速判断该转给哪个部门后端MySQL节点然后等结果回来再回复客户。它核心做了三件事读写分离路由把SELECT走从库把INSERT/UPDATE/DELETE走主库从代码层面去掉了自己维护多数据源的麻烦。分库分表路由根据分片规则把一张逻辑表的数据分散到多个物理库的多个物理表中应用感知不到物理分布。连接复用与管理维护到后端MySQL的连接池避免应用每次请求都新建数据库连接。说白了MyCat就是一个带路由规则的连接池加SQL转发器。理解到这一层你已经超过一半只会配配置文件的人。2. 核心概念三件套逻辑库、数据节点、分片规则我第一次配schema.xml的时候被dataNode、dataHost、table这些标签绕得晕头转向。后来总结成三件套思路一下就清晰了。逻辑库schema面向应用暴露的虚拟数据库。应用连接的库名比如catdb在MyCat里就是一个schema。逻辑库底下挂逻辑表table逻辑表映射到物理表。数据节点dataNode逻辑表的数据真正落在哪儿。一个dataNode对应一个物理库的物理表格式是库名主机比如dn1host1。一个dataNode背后是dataHost——也就是一组真实的MySQL连接主库、从库。分片规则rule决定了数据行落到哪个dataNode。常见的有取模mod-long、按范围rang-long、按日期、按枚举等。分片规则配置在rule.xml里每个table标签通过rule属性引用。2.1 一张逻辑表映射N个物理表的完整链路拿最常见的订单表举例schema namecatdb checkSQLschemafalse sqlMaxLimit100 table namet_order dataNodedn1,dn2,dn3 rulemod-long / /schema dataNode namedn1 dataHosthost1 databasedb_order_01 / dataNode namedn2 dataHosthost1 databasedb_order_02 / dataNode namedn3 dataHosthost1 databasedb_order_03 / dataHost namehost1 maxCon1000 minCon10 balance3 writeType0 dbTypemysql dbDriverjdbc switchType1 writeHost hostmaster urljdbc:mysql://192.168.1.10:3306 usermycat password123456 readHost hostslave1 urljdbc:mysql://192.168.1.11:3306 usermycat password123456 weight1 / /writeHost /dataHost应用发出一条INSERT INTO t_order (id, user_id, amount) VALUES (1, 1001, 99.9)MyCat看到该表配置了mod-long规则就对分片键默认是主键id如果table标签没指定primaryKeyMyCat会取第一个字段取模1 % 3 1于是路由到dn2最终落到db_order_02.t_order这张物理表。查询的时候如果带分片键WHERE id 1MyCat能精准路由到dn2。如果不带分片键比如WHERE user_id 1001MyCat就不知道去哪张表找只能广播到dn1、dn2、dn3全部查一遍再合并结果。这就是为什么分片键选择如此重要——它决定了查询是精准路由还是全表扫描。2.2 全局表和ER分片表两类特殊表有些表数据量不大但几乎所有分片表都要和它关联比如用户类型字典、商品分类。这类表如果也分片那跨节点JOIN会变成噩梦。MyCat的解法是配置typeglobal的全局表每个dataNode上都存一份完整数据查询直接本地JOIN写操作则广播给所有节点。table namet_dict dataNodedn1,dn2,dn3 typeglobal /还有一类是父子关联表比如订单表和订单明细表。如果按订单id分片最好让同一个订单的明细和订单落在同一个分片这样JOIN就不用跨节点。MyCat的做法是erTables配置table namet_order dataNodedn1,dn2,dn3 rulemod-long childTable namet_order_item joinKeyorder_id parentKeyid / /table这样t_order_item会跟随父表t_order的分片结果落在同一个数据节点上。实际生产里这种ER分片设计比什么都用全局表要优雅得多也更能扛数据量增长。3. 读写分离配置实录schema.xml里最容易踩的坑读写分离的配置看起来简单就是一个dataHost下面挂一个writeHost、多个readHost但真正跑到生产环境你会发现细节里全是坑。先看我的标准配置dataHost namehost1 maxCon1000 minCon10 balance3 writeType0 dbTypemysql dbDriverjdbc switchType1 slaveThreshold100 heartbeatselect user()/heartbeat writeHost hostmaster urljdbc:mysql://192.168.1.10:3306 usermycat password123456 readHost hostslave1 urljdbc:mysql://192.168.1.11:3306 usermycat password123456 weight1 / readHost hostslave2 urljdbc:mysql://192.168.1.12:3306 usermycat password123456 weight2 / /writeHost /dataHost3.1 balance参数究竟怎么选balance是读写分离的总开关值是0到3很多人记不住区别。我在实践里用一句话总结balance0不开启读写分离所有请求都走主库。balance1读请求在所有从库和主库之间负载均衡。主库也参与读适合从库不多、主库负载不高的场景。balance2读请求只在从库之间负载均衡主库不参与读。这是最常见的配置主库专心写从库专心读。balance3读请求只在从库之间负载均衡主库完全不参与读而且从库的权重由weight决定。我生产环境一般用这个配合多个从库做权重分配。选型逻辑很简单如果从库只有一台balance2和balance3没区别如果从库有多台且配置性能不一用balance3加上weight比如新加的从库配置低就给weight1老的性能好给weight2。3.2 MySQL 8.0的加密插件坑这是我最想提醒的一个坑。MyCat默认的dbDriver老版本用的是com.mysql.jdbc.Driver而MySQL 8.0默认用caching_sha2_password加密插件老驱动根本连不上。解决办法有两个在MySQL里为MyCat单独建一个账号指定用mysql_native_passwordCREATE USER mycat% IDENTIFIED WITH mysql_native_password BY 你的密码; GRANT ALL PRIVILEGES ON *.* TO mycat%; FLUSH PRIVILEGES;或者升级到MyCat 1.6.7.6以上版本dataHost里配置dbDriverjdbc同时把MySQL驱动包放到MyCat的lib目录并更新驱动为新版mysql-connector-java-8.x.jar。我当时第一次连MySQL 8.0折腾了大半天最后是建了个native password账号才搞定。如果你用的是MyCat 1.6.5或者更早的版本直接换账号密码加密方式最省事。3.3 主从切换到底切了什么配置了switchType1之后MyCat会通过心跳检测主库状态。一旦主库挂了MyCat会把这个writeHost下的从库自动提升为新的writeHost应用继续读写不中断。听起来很美好但有两个隐藏问题主从复制是否配置了半同步如果主库宕机时还有一部分binlog没同步到从库从库被提升后这部分数据就丢了。MyCat只管切换不管数据补拉。生产环境建议给MySQL配置半同步复制把数据丢失的概率降到最低。切换是自动的但应用层事务会报错。主库瞬间不可用正在执行的事务SQL会直接抛异常。如果你的业务代码没有重试机制用户会看到报错。所以MyCat做主从切换业务侧一定要配SQL重试至少对INSERT/UPDATE类的操作做一次重试。另外switchType1表示主从切换为自动但它是判断主库挂了之后把从库顶上来不是把主库从故障中恢复回来再切回去。主库恢复后它默认会变成从库你需要手动去MyCat管理端执行switch datasource把它切回主库或者干脆保持现在的角色继续跑。这个逻辑我第一次没搞清楚主库修好之后流量一直在原从库上原主库因为还是写库配置数据又不一致了排查了很久才发现。4. 分库分表真的“分”对了吗分片字段选错引发的连锁事故读写分离解决的是读压力分库分表解决的是单库单表的数据量瓶颈。但分库分表的代价比读写分离大得多最核心的就是分片字段的选择。4.1 为什么分片字段不能随便选分片字段决定了数据分布也决定了查询能否精准路由。我用一个真实案例说明某电商系统订单表早期按user_id取模分片。用户查询自己的订单列表WHERE user_id ?精准路由效率很高。但运营要做订单分析按order_id或者order_time查——不带分片键MyCat广播到所有分片每个分片都查一遍再合并数据量一大慢查询直接拖垮整个集群。这就是分片键选择的第一个原则分片键必须是业务最高频的查询维度。订单表高频查询是按用户查那就按user_id分片如果后台按订单号查得也很多那就得考虑订单号里嵌入用户ID或者维护一个映射表。第二个原则分片键的值必须足够离散。如果取模字段大量值集中在少数几个值上比如按状态字段分片绝大多数订单都是“已完成”数据全部堆到同一个分片分库分表等于白分。4.2 跨分片查询和JOIN的代价分库分表之后两条SQL是最痛苦的不带分片键的查询广播所有分片结果合并。跨分片JOIN两个表分片规则不同数据不在同一个节点只能把一张表的数据拉到内存和另一张关联数据量一大直接OOM。规避手段我总结四种全局表字典类、配置类表每个分片存一份全量本地JOIN。ER分片表父子表绑定同一分片关联查询不需要跨节点。冗余字段在订单表里冗余用户昵称、商品名避免关联用户表、商品表。应用层聚合先查一批订单ID再根据订单ID去查关联表最后在应用里聚合。这也是ShardingSphere里叫“编程式事务”的思路。MyCat 1.6对跨分片JOIN做了不少优化支持catlet、全局序列等但说句实话能用冗余字段解决的别指望中间件因为跨节点数据合并的复杂度和故障概率是几何级上升的。4.3 分布式主键一个不容易注意的硬要求分库分表后数据库自增主键会重复。三张物理表各自从1开始自增合并到逻辑表后主键冲突。MyCat的解决办法是全局序列号配置在sequence_conf.properties里常见的有数据库方式、时间戳方式、分布式ID方式。实践中我更推荐直接用分布式ID方案比如雪花算法生成的long型主键这在MyCat里就是primaryKeyMyCat能识别它并做取模路由。相比MyCat自带的数据库序列号方案雪花算法不依赖额外数据库表性能更好而且ID本身带时间信息对订单类业务很有用。5. 踩坑实录MyCat生产环境最隐蔽的四个问题配置能跑通只是第一步生产环境真正让你头疼的往往是那些平时不暴露、一压测就现形的问题。我把亲身踩过的几个坑列出来每个都附上复盘思路。5.1 批量插入不分片MyCat默认对INSERT INTO t_order VALUES (...), (...), (...)这种多值批量插入是按第一条记录的分片键路由的——后面的值如果分片键不同会被直接丢弃或者报错。这是让很多人崩溃的问题。解决方法是开启批量插入的rewriteMyCat从1.6版本开始在server.xml里有rewriteBatchInsert配置项设置为true后MyCat会把批量插入拆分成逐条SQL根据每条的分片键路由到不同分片。system property namerewriteBatchInserttrue/property /system但这个方案性能损耗明显尤其是大批量导入场景。我的建议是业务代码里自己控制批量插入的分片键一致比如同一用户的订单放一批这不仅是性能问题更是数据一致性的问题。5.2 事务里混读写从库读到陈旧数据默认情况下MyCat把SELECT路由到从库把写操作路由到主库。但如果在同一个事务里先插入一条数据再查询这条数据SQL可能因为路由策略不同而分别执行到主库和从库。如果主从复制有延迟从库查不到刚插入的数据业务方就会看到“明明插入成功了却查不到”的诡异现象。解决手段有几种MySQL主从同步做成同步复制而不是异步复制。但这样写性能牺牲很大。业务上拆开需要实时一致性的查询强制走主库。MyCat提供了注释路由的方式在SQL前加/*#mycat:db_typemaster*/ SELECT ...可以强制走主库。事务隔离级别控制让MyCat里的事务路由规则改为事务内所有SQL都走主库。MyCat的txIsolation设置高一点同时配合reput参数让事务中的读请求跟随写请求走同一个数据源。实践里我通常用第二个方案业务对关键查询加注释强制走主库普通查询接受从库的秒级延迟。这也要求产品设计上能接受“最终一致”而不是任何时候都强一致。5.3 从库负载不均MyCat负载均衡算法默认是轮询理论上很均衡。但实际上如果某个从库的SQL执行特别慢连接会被它占住其他请求会堆到别的从库出现“慢库拖垮整个集群”的情况。更稳妥的做法是给MySQL配置max_execution_time把慢SQL直接杀在数据库层面而不是等它跑完。同时监控每个从库的Threads_running指标一旦超过阈值就要告警。MyCat的管理端也有show datasource命令可以看到每个数据源的活跃连接数配合定时采集就能发现倾斜。5.4 大字段和跨分片排序SELECT * FROM t_order ORDER BY create_time DESC LIMIT 10不带分片键MyCat广播所有分片每个分片各自排序取前10然后MyCat在内存里合并这30条再排序取前10。如果每个分片自己也是大表这种查询就是全分片扫描加内存排序数据量一大直接OOM。规避办法查询必须带分片键让路由变成精准路由。LIMIT的偏移量不能太大LIMIT 100000, 20在分片环境下要每个分片取100020条再合并代价非常大。业务上尽量用“下一页”模式代替页码模式比如WHERE create_time 上次最大时间 ORDER BY create_time DESC LIMIT 20彻底绕开大偏移量问题。6. 进阶从MyCat 1.6到MyCat2我为什么不急着升MyCat 2.0已经发布很长时间了我个人的建议是存量项目别急着升新项目可以认真评估。原因很简单MyCat 2.0的核心理念变了它不再像1.6那样依赖XML配置而是把配置改成了SQL化操作——用SQL来创建逻辑库、逻辑表、数据源。概念上确实更先进但迁移成本完全不低。MyCat 1.6的配置是集中式的schema.xml、rule.xml、server.xml三个文件搞定出了问题一眼能看全。MyCat 2.0把所有配置都存到数据库里通过SQL管理功能确实灵活但排查问题时要多一层“配置数据库”的链路学习曲线陡了不少。如果你刚入门我建议先精通1.6把读写分离、分库分表、全局序列、ER分片这些概念玩透再去碰2.0。因为中间件的核心难点从来不是配置语法而是路由规则设计、数据分布规划、跨节点事务一致性这些底层逻辑。这些逻辑在1.6和2.0里是相通的。至于为什么越来越多人拿MyCat和ShardingSphere对比——ShardingSphere-JDBC以jar包形态嵌入应用不走独立中间件性能更好但侵入性更强ShardingSphere-Proxy形态类似MyCat也是独立部署。我的选择标准很简单改造难度优先选MyCat因为业务代码零改动DBA友好性能敏感、团队有Java能力可以考虑ShardingSphere-JDBC。没有绝对的好坏只有适不适合。最后分享一个我自己的体会中间件永远只是工具真正决定系统上限的是你对数据分布的理解。MyCat能帮你把请求路由到正确的节点但它不会替你思考哪里该分、哪里不该分、分了之后查询怎么写。把这些问题想明白你用什么中间件都不会太差想不明白换再新的框架也照样是灾难。本文还有配套的精品资源点击获取
返回列表