ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MySQL中间件MyCat实战:读写分离与分库分表配置指南

MySQL中间件MyCat实战:读写分离与分库分表配置指南 简介Mycat 入门到精通教程面向需要应对大数据量、高并发访问的数据库开发、运维及架构人员从零开始系统讲解 Mycat 这一分布式数据库中间件的原理与实战。内容按模块递进展开先介绍 Mycat 在 MySQL 生态中的定位以及 Server、DataNode、Schema、Table、Rule 等核心概念再讲解安装与配置文件、哈希分片、范围分片、列表分片等常用分片策略并深入分析 XA 两阶段提交分布式事务、高可用部署、SQL 优化与连接池等参数调优方法。此外还涉及监控日志解读、电商与社交等真实场景案例以及与 ShardingSphere、Cobar 等中间件的对比选型分析帮助读者建立完整的 Mycat 知识体系。压缩包内共 2 个文件以 html 教程文档和 txt 文字说明为主整包仅 6KB结构精简便于快速打开学习。目前已有 445 人学习下载适合希望用较短时间掌握 Mycat 核心要点、进行技术选型或准备面试的读者。1. 先想清楚MyCat到底解决什么问题1.1 一个被业务打到单库瓶颈的真实场景先别急着下载安装包。我见过太多人一上来就照着文档搭MyCat配完发现业务压根用不上最后整个中间件成了摆设。所以想聊清楚MyCat咱们先看一个场景。假设你手上有个电商系统用户表、订单表、商品表都在一台MySQL上。刚开始每天几千单数据库毫无压力。等到业务跑起来日订单量到了几十万你会发现几个明显症状主库CPU时不时飙到90%以上读写都压在同一个库上慢查询开始变多单表几千万条数据之后索引就算加了查询也肉眼可见地变慢。这时候你面前有两条路。一条是换更强的硬件把单机配置往死里堆但成本高、天花板明显。另一条就是引入MyCat这类数据库中间件把数据访问的压力从单库分摊出去。MyCat不是数据库本身它是你和MySQL之间的一个代理层应用连它就像连MySQL一样但背后它帮你把请求路由到不同的真实库上。这就是我第一次接触MyCat时的感受——这玩意就像高速公路上的智能分流闸口流量大了它帮你分车道车再多它还能给你分几个出口。什么人适合看这篇内容如果你正在做数据库相关的架构升级或者已经在用MyCat但只当了个透明代理、没发挥出它的能力再或者你是面试前临时想搞懂中间件原理这篇都可以给你省下不少瞎折腾的时间。我会按从零讲起但会直接切入能落地的部分不是那种抄一遍官方文档就完事的节奏。1.2 MyCat在架构里的真实身份理解MyCat最怕用错类比。很多人看官方介绍看到“数据库中间件”“分库分表工具”几个词就以为它是某种数据库客户端或者是个连接池——完全不对。MyCat的本质是一个MySQL协议层的代理服务。你的应用不需要改代码只需要把数据库连接地址从MySQL改成MyCat的地址端口默认是8066。应用发来的SQL语句MyCat会先解析一遍搞清楚这条SQL要操作哪个表、哪些数据然后根据你配置好的分片规则和读写策略决定把SQL转发给后端的哪一台MySQL。对于应用来说它感知不到后端有N台数据库它看到的只是一个逻辑上的“大数据库”。这里有个很关键的点得说透MyCat只做路由和转发不负责真正的数据存储数据还是落在后端的MySQL里。所以MyCat本身不需要多强的机器配置2核4G跑个小团队的业务都绰绰有余。你也不要指望MyCat帮你加速单条SQL——它不会像缓存层那样让你查询变快它的核心价值在于让集群里的每一台MySQL都干它最擅长的事把读压力分出去、把数据量拆小让每一台机器都活得轻松。我拿实际团队例子给你说。当年我们上线MyCat之前所有查询都打到主库DB的CPU没低过70%热备的那台从库整天闲着。上了读写分离之后主库CPU直接掉到30%左右耗时高峰从200ms降到了50ms出头。没有换一台硬件全靠把流量重新分配了——这就是中间件的意义。2. 核心机制读写分离和分库分表是怎么跑通的2.1 读写分离把“读”和“写”拆到不同机器上读写分离这个概念国内团队用到极多也是MyCat最受欢迎的功能。理论上它不复杂后端准备一台主库负责写一台或多台从库通过MySQL主从复制同步数据负责读。应用把SQL发到MyCatMyCat根据语句判断——如果是insert、update、delete丢给主库如果是select丢给从库。但实际落地时有几个细节很容易踩坑。第一主从复制有延迟。比如用户在订单支付成功后立刻刷新页面这时候数据可能还没同步到从库如果MyCat把这次查询路由到从库用户就会看到“订单还没支付成功”这种诡异现象。你有三个处理方向一是把实时性要求极高的业务路由到主库二是接受极短窗口内的不一致三是调整主从复制策略牺牲一些同步速度换一致性。我们当初对账、支付状态这类强一致查询都通过强制路由规则走主库剩下的列表查询、统计报表走从库体感上没有任何问题。第二事务内的读必须走主库。你在代码里开启了事务先插入一条数据然后在同一个事务里查询这条数据如果MyCat把这条查询发到从库从库大概率还没有这条数据你读出来就是空的这就是传说中的“读己之写”问题。好在MyCat对事务有处理机制一旦检测到事务开启后续所有SQL都会路由到主库这个行为要靠你配置好别把事务范围搞得过大否则主库压力还是下不来。第三balance参数决定了分流的比例和策略。这是读写分离配置里最核心的开关我后面会专门讲四个取值分别代表什么新手一般在这个配置上懵得最多。2.2 分库分表别把鸡蛋放在同一个篮子里读写分离解决的是“压力大”的问题但解决不了“数据太多”的问题。当你的单表数据到了亿级就算读请求分散到十台从库每台机器上的查询照样要扫上亿行数据。这时候就得靠分库分表把一个逻辑表拆成多份分散到不同的物理库、不同的物理表里。分库分表的核心设计是分片键。你选哪个字段做分片键决定了一条数据会被路由到哪台数据库。最常见的分片算法就是取模假设你有3个数据节点对应3台MySQL分片键是用户ID那么MyCat计算user_id % 3结果是0走第一个节点1走第二个节点2走第三个节点。这样一来同一个用户的订单始终落在同一台机器上查询单条订单时MyCat能准确定位到那一个节点不会全库扫描。但这个设计是有代价的。分片键一旦定下来后续想改等于重写一遍数据分布。而且跨分片的查询就很痛苦——比如你要查“最近一周所有用户的订单汇总”数据分散在3台机器上MyCat必须去每个节点都跑一遍然后把结果合并。MyCat里叫全局聚合表能做但性能要打折。还有跨分片的joinMyCat支持一部分深层场景还是力不从心。所以分片键的选择是架构决策级别的事情不是开发顺手决定的这个我在第五部分会展开讲。2.3 MyCat的核心概念三件套在配MyCat之前先把三个核心概念刻进脑子里因为所有配置文件都在围绕它们转。逻辑库schema。对应用来说它连上MyCat看到的数据库名。比如你后端有4台MySQL上面各有几十张表但在应用眼里只有一个叫“shop_db”的库它不需要知道底层分了几个节点。数据节点dataNode。一个数据节点对应后端的一台MySQL上的一个具体数据库比如第一台机器上的“shop_db_01”。分库分表后一个逻辑表的数据就分散在多个数据节点上。数据主机dataHost。数据节点里配置的连接地址指向真实MySQL的IP和端口也包含负载均衡、心跳检测等参数。这三个概念的嵌套关系可以这样记逻辑库是你站在应用视角看到的表象数据节点告诉你数据到底分散在哪几个位置数据主机则决定这些位置的真实连接方式。配置文件 schema.xml 里就是这三层结构理清它们配置就不再是一堆拼凑的标签。3. 从零搭一套环境部署和配置要点3.1 环境准备与安装MyCat是基于Java开发的所以第一步就是确认机器上有JDK版本建议JDK 8及以上。我在CentOS 7上跑得最多也试过在Ubuntu和Windows上装都没问题只是生产环境一定要部署在Linux上稳定性区别还是很明显。安装流程没什么难度去官方仓库下载对应tar.gz包解压到 /usr/local/mycat 就行。解压后目录结构是这样的bin/启动、停止脚本如 mycat start、mycat stopconf/所有配置文件所在地核心是 server.xml、schema.xml、rule.xmllogs/运行日志查问题主要看这里。启动命令就一句话mycat start然后mycat status看看状态。如果你看到启动失败90%是配置文件写错了或者8066端口被占用。首次跑通之前不建议急着改端口默认的8066数据端口和9066管理端口先留着。有个细节新手容易忽略MyCat启动后不是说你后端MySQL没准备好它就不启动它启动时不会立刻检查所有依赖的数据库经常会“先活着再说”你sql查询的时候才会报连不上后端库。所以启动成功只能说明配置能过解析不代表整条链路是通的务必用客户端连上去具体执行一条SQL验证。3.2 三个关键配置文件分别用来干什么配置文件作用核心内容server.xml定义MyCat自己的用户、逻辑库权限账号密码、可访问的逻辑库schema.xml定义逻辑库与后端MySQL的映射关系逻辑表、数据节点、真实连接rule.xml定义分片规则分片键、分片算法、参数新手最容易犯的错是把所有概念全部堆在schema.xml里然后server.xml的权限没配好导致连上了却看不到库。记住一个顺序先定用户再定schema最后定dataNode和dataHost。server.xml里配置的用户需要显式声明它能访问哪个逻辑库schema.xml里声明的逻辑库才能真正被这个用户看到。我第一次搭的时候在这上面卡了快两个小时。server.xml里我建了一个mycat用户密码写对了但没在schema标签里把逻辑库名指给这个用户客户端连接倒是成功show databases结果却是空白。后来一查文档才意识到MyCat的权限模型是“用户→逻辑库”绑定式不是MySQL那种全局授权后就完事的绑定了才能看得见。3.3 最简单节点配置先把链路跑通不管后面是读写分离还是分库分表建议你第一步先配一个最简配置一台MySQL一套逻辑库不搞任何花活先把MyCat这台“代理”跑通。这一步的目的不是炫技而是排除变量——先把基础链路打通再慢慢加功能出了问题也知道往哪个方向查。最简schema.xml大致长这样mycat:schema xmlns:mycathttp://io.mycat/ schema nametest_db checkSQLschematrue sqlMaxLimit100 table nameuser primaryKeyid dataNodedn1/ /schema dataNode namedn1 dataHosthost1 databasetest_db / dataHost namehost1 maxCon1000 minCon10 balance0 writeType0 dbTypemysql dbDriverjdbc heartbeatselect user()/heartbeat writeHost hosthostM1 urljdbc:mysql://192.168.1.101:3306 userroot password123456/ /dataHost /mycat:schema这里有个参数叫checkSQLschema我建议新手直接设成true。它的作用是你SQL里写了select * from test_db.user这种带库名的写法MyCat会自动把库名前缀去掉再路由到后端不然后端MySQL收到一个带了它不认识的前缀的语句直接报错。配置好之后用MySQL客户端连MyCat的8066端口执行select * from user如果能返回数据基础链路就算通了。这一步通过后再在上面叠加读写分离或分片规则出问题时你能快速定位是规则问题还是基础链接问题。4. 读写分离实战把流量从主库卸下来4.1 准备工作后端MySQL主从复制先跑通读写分离有个前提后端的主从复制必须先搞好否则MyCat这边配得再花哨也是白搭。这里不是讲MySQL主从搭建的完整教程但我要提醒几个直接影响MyCat使用体验的点。用GTID模式做主从复制比传统的binlog文件名位置点的方式省心得多因为MySQL会自动处理断点续传的逻辑不太容易出现主从不同步越差越远的情况。复制账号要单独建一个专用账号不要拿root账号给从库拉数据用权限收敛是数据库安全的基本素养。主从复制配置完成后一定要在从库上执行show slave status\G确认Slave_IO_Running和Slave_SQL_Running都是YES再往下走。这俩任何一个不是YES读写分离上线后你看到的查询结果就是缺数据的。另外从库上要有对应的库表结构MyCat不会自动帮你建表——这听起来像废话但真有人操作时忘了在从库建表结果读请求全部报错。4.2 在schema.xml里配置一主一从一主一从的运维成本最低绝大多数业务初期用这个组合就够了。主库只负责写从库分担读。你只需要在同一个dataHost下的writeHost标签里嵌套一个readHost子标签。dataHost namehost1 maxCon1000 minCon10 balance1 writeType0 dbTypemysql dbDriverjdbc heartbeatselect user()/heartbeat writeHost hosthostM1 urljdbc:mysql://192.168.1.101:3306 userroot password123456 readHost hosthostS1 urljdbc:mysql://192.168.1.102:3306 userroot password123456 weight1/ /writeHost /dataHost注意balance参数的取值这是读写分离的精华所在。4.3 balance参数四个取值别再记混了balance值行为适用场景0不开启读写分离所有请求都发给writeHost调试用或不需要读写分离时1读请求随机分发到所有readHost与备用的writeHost一主多从场景最常用2读请求随机分发到所有writeHost和readHost双主互备场景3读请求只发给readHostwriteHost不参与读严格区分读写推荐用于一主一从我线上用的就是balance3。这个参数最直观的理解balance1时每台可用的后端都可能承担读压力包括主库balance3时主库彻底脱离开读流量只保留写。很多人配完发现主库压力没降多少一查balance1默认为主库也参与了读分发所以压测数据看上去很奇怪。确认业务流程是纯一主一从后直接上balance3最省心。要说一下writeType这个参数。默认0就行它的含义是写请求只发给第一个writeHost万一第一台挂了才切换到第二台。别手贱去改成1writeType1让写请求随机分发到所有writeHost在非双主环境下会造成数据混乱。4.4 怎么验证读写分离真的生效配置写完重启MyCat然后执行mycat console在前台模式看日志这是调试阶段最直观的方式。用客户端连上MyCat执行一条查询然后立刻看日志。你会发现日志里有一行类似SQLRouteCache的记录能看到这条SQL被路由到了哪个dataNode和哪个host。我习惯的做法是分别执行select * from user where id 1;—— 应该看到走hostS1update user set name test where id 1;—— 应该看到走hostM1begin; select * from user where id 1; commit;—— 再执行查询应该走hostM1因为事务内强制走主库如果你发现update也走从库那就是balance配置有问题或者SQL类型里MyCat没识别出来是写语句需要检查是不是SQL写法有问题比如某些存储过程调用场景MyCat对动态SQL的解析能力是有限的这时候尽量别走中间件转发。5. 分库分表实战把一个表拆成多份5.1 分片键怎么选这是整个分库分表里最重要的决策我在第二部分说过分片键很重要这里得展开讲讲为什么。选分片键本质上是选“数据的访问模式”。假设你的业务里最频繁的查询是“查某个用户的所有订单”那么分片键选user_id就非常合适。select * from orders where user_id 888这条SQLMyCat计算888 % 2两个节点直接定位到对应节点单点查询毫秒级返回。但如果你的业务里DBA经常要跑“按订单状态查所有用户”的统计SQLSELECT会把所有节点扫一遍这时候分片键选user_id不是不行但性能会很难看。所以选分片键之前先把业务里最高频的查询列出来统计它们的where条件选那个在绝大多数查询里都出现、且分布足够均匀的字段。切忌选性别这种枚举值只有两三个的字段那会让数据分布极其不均一个节点爆掉另一个节点闲置。也切忌选自增主键这种插入时单调递增的字段因为新数据永远只落在最后一个分片上写压力还是集中。5.2 配置一个取模分片规则取模mod分片是最好理解、也最适合入门的算法。我们以一个订单表为例拆成两个数据节点。先在rule.xml里定义一个规则tableRule namemod-long rule columnsid/columns algorithmmod-long/algorithm /rule /tableRule function namemod-long classio.mycat.route.function.PartitionByMod property namecount2/property /function这段配置的意思是取id字段对2取模结果0走第一个数据节点结果1走第二个数据节点。然后在schema.xml里把逻辑表指向两个数据节点table nameorders primaryKeyid dataNodedn1,dn2 rulemod-long /这里要特别注意dataNode里的顺序是有讲究的取模结果为0对应第一个dn1为1对应第二个dn2。如果写成dn2,dn1那模0的数据反而去了第二台机器查询的时候路由就会对不上。这种问题非常隐蔽数据写入和数据读取是两套计算路径配置不一致时连日志都不太好排查只能靠对比配表顺序。5.3 建表和测试数据时注意什么分片后的建表不能像单库那样只在MyCat里执行。MyCat会把你发出的建表语句下发到所有dataNode上所以你要确认每个后端MySQL的账号都有建表权限。如果某些节点建表失败MyCat的报错信息往往不直观建议你在配置分片之后先手动到每个后端库里都把表建好再通过MyCat执行insert验证路由效果。实测中我习惯插入十条记录然后分别查每个节点确认数据分布是否符合预期。这里有个小技巧在订单表里加一个node_id字段业务插入时显式写入路由节点的编号比如手动标注“这条数据应该在dn1”后续排查数据分布时一眼就能看出来对不对不用反复用SQL去试探。这个做法不是必须的但数据量大的时候排查效率会高很多。5.4 全局表解决分片后JOIN的问题分库分表之后最头疼的问题之一就是JOIN。如果orders表分片了而users表没分片直接在MyCat里写select * from orders o join users u on o.user_id u.idMyCat会报错或者性能极差。MyCat的官方解法之一是全局表。把那些数据量不大、几乎不更新、又经常需要和其他表关联的表比如省市区字典表、商品分类表在每个数据节点上都放一份一模一样的完整拷贝。配置方式很简单在schema.xml里给这个表加一个typeglobal属性table nameregion primaryKeyid typeglobal dataNodedn1,dn2 /这样MyCat在写操作时会把数据同步到所有节点读操作时只在当前节点本地关联避免了跨节点JOIN。字典表、配置表用这个方案非常香。但注意全局表不适合数据量大或频繁修改的表因为每一次写都要同步到所有节点写放大很严重。6. 常见问题与排查技巧实录6.1 连不上MyCat从哪一步开始查连不上MyCat是新手最开始遇到的高频问题。我给你一个固定排查顺序。第一步确认进程在跑ps -ef | grep mycat。第二步确认端口在听netstat -tlnp | grep 8066。第三步从应用机器上telnet一下MyCat的IP和8066端口排除防火墙拦着。第四步确认server.xml里的用户配置正确包括密码和逻辑库名。第五步确认schema.xml里没有语法错误特别是标签闭合。我见过最离谱的一次线上故障是因为schema.xml中dataHost的url写成了jdbc:mysql://192.168.1.101少写了端口3306MyCat启动正常但每次查询都报后端连接失败。这种错误靠日志很容易定位但日志级别要开对。conf目录下有个log4j2.xml把com.mycat的日志级别调到DEBUG能看到完整的SQL路由和连接信息排查时效率翻倍。6.2 读写分离没生效四个最常见的原因读写分离配置完了压测一下发现主库压力没降这事我遇到太多次了。常见原因有四条现象原因解决方式查询也走主库balance参数设置为0改成1或3主库压力仍然很高balance1时主库也参与读分发改成balance3事务内的查询走主库这是正常行为不需要处理优化事务粒度开启事务后所有查询都走主库连接池持有连接事务未正确关闭检查代码确保事务及时提交或回滚最后一条值得展开说说。某些DBCP或HikariCP连接池配置下如果连接复用了之前开启过事务的连接MyCat会基于会话状态一直认为你还在事务里导致后续所有读都发往主库主库压力自然下不来。解决办法一是代码层确保事务边界清晰二是排查连接池是否在归还连接后把autoCommit重置为true。6.3 分片查询报错跨分片查询的现实困境分片后的查询报错很多人第一反应是MyCat出bug了。其实大部分时候是业务SQL触发了MyCat不支持的场景。如果你执行一条不带分片键的查询比如select * from orders where shop_id 5而分片键是idMyCat不知道去哪个分片它会广播到所有节点去执行然后合并结果。小数据量还好数据量大时这种“全表扫描式”的路由会非常慢甚至导致后端连接池被打满。解法是先通过分片键定位到单一分片或者单独建一张路由表把shop_id和id的对应关系维护起来。跨分片JOIN是另一个大坑。MyCat支持部分跨分片查询但代价是内存中做笛卡尔积或者逐节点拉数据拼接数据量一大就内存溢出。我团队的规范是所有分片表的关联查询尽量在设计层面规避实在规避不了要么冗余字段要么用全局表要么让应用层分多次查询然后合并而不是让MyCat硬扛。这比遇到问题再调优高效得多。6.4 主从复制延迟带来的脏读一个必须提前约定的方案上线读写分离之前业务方和DBA必须对“能接受多久的复制延迟”达成一致否则上线后天天扯皮。我们在实践中总结了一套经验对实时性要求极高的数据强制走主库大多数列表查询可以容忍一两秒延迟报表统计类查询除了走从库还可以加一个延迟阈值超过阈值报个警。MyCat里可以通过注释或路由规则强制某些表只走主库。我遇到不少团队在第一步就忽略了这一点导致用户支付完刷新页面看到待支付状态客服被用户骂了一周才发现是复制延迟。所以这块一定要在方案上线前就约定好并且写进团队的开发规范里。7. 把MyCat用稳的一些个人体会我接触MyCat这几年最大的感受是它不是那种“装上就万事大吉”的中间件它更像一个需要你持续经营的数据流调度中心。很多团队上了分库分表之后反而因为复杂度和规则维护成本把系统搞得更脆弱了。所以最后分享几条个人体会。第一能用读写分离解决的问题就别急着分库分表。分库分表带来的复杂度是指数级上升的跨分片查询、分布式事务、全局唯一ID每一个都需要额外的方案来兜底。我们先跑了半年读写分离确定单表数据量确实到了瓶颈才逐步引入分片平滑过渡。第二MyCat的配置一定放进版本管理。schema.xml、server.xml、rule.xml这些文件就是基础设施的一部分绝不能只在服务器上手工改。我见过团队在测试环境配置改了生产环境忘了同步然后查了一下午数据不对最后发现是规则不一致。第三监控比优化更重要。把MyCat的9066管理端口接上监控定时采集连接数、路由次数、后端库的响应时间。出现性能问题的时候这些指标能帮你快速判断是路由环节的瓶颈还是后端MySQL的瓶颈而不是靠猜。第四不要跳过心跳检测的配置。heartbeatselect user()/heartbeat这段不是摆设。MyCat靠它感知后端MySQL是否存活如果心跳失败MyCat会自动把流量切换到备机。有一次后端主库磁盘满了MySQL假死我没配心跳应用端直接全挂。配置好心跳并设短一点的时间间隔能大幅提升整个数据层的容灾能力。这个话题能聊的东西其实还有很多比如全局序列、多租户隔离、MyCat与其他中间件如ShardingSphere的对比每一个单独拿出来都能写一篇。但作为一篇从入门到实战的记录先把读写分离和分库分表这两条主线讲透跑通这条主线你已经能解决大部分业务压力问题了。剩下的等真正遇到了再说。本文还有配套的精品资源点击获取
返回列表