ARTICLE DETAIL

资讯详情

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

MyCat实战:从读写分离到分库分表的数据库中间件配置指南

MyCat实战:从读写分离到分库分表的数据库中间件配置指南 简介这是一份面向后端开发与数据库运维人员的 Mycat 入门到精通教程资源包。内容从 Mycat 基础概念与架构设计入手系统讲解 Server、DataNode、Schema、Rule 等核心组件并覆盖哈希、范围、列表、取模等数据分片策略以及基于 XA 两阶段提交的分布式事务处理、多节点心跳检测与故障切换的高可用方案。同时涵盖 SQL 优化、连接池参数调整、负载均衡、监控与日志分析等实战要点并给出常见故障排查思路适合希望解决高并发、大数据量下分库分表问题的读者从零起步。资源包共 2 个文件包含 1 个 HTML 教程页面和 1 个 TXT 配套说明页面结构清晰、重点突出整体仅 6KB轻量便携可直接在浏览器中阅读学习目前已有 445 人学习浏览。借助这份教程读者可以快速建立整体认知掌握从安装配置到分片规则设计、再到性能调优与监控排错的完整链路为该中间件在真实业务中的落地提供清晰参考。 做后端开发这些年MySQL单库被业务流量追着打的阶段我经历过不止一次。连接数被打满、慢查询越积越多、主从架构下还得自己写读写分离的路由逻辑维护成本实在不低。所以第一次接触MyCat时我心里很清楚这类数据库中间件的价值——它把读写分离、分库分表这些事从“手写一堆代码”变成了“改几个配置文件”。这篇教程就从实际落地出发把MyCat从架构原理到读写分离、分库分表配置再到排查问题完整过一遍。适合正在做MySQL性能优化、准备引入中间件或者已经被单库瓶颈卡住的后端同学照着配置就能在自己环境里跑起来。1. 先搞明白MyCat的定位和核心逻辑1.1 MyCat是什么为什么要用它MyCat是一个开源的分布式数据库中间件部署在业务应用和物理数据库之间。应用连MyCat就像连一个普通的MySQL所有SQL交给MyCat由它决定去哪个物理库执行再把结果汇总返回。你可以把它理解为“数据库前台的接线员”。用户打电话进来只说“我要查订单”接线员知道订单数据在哪个库就把电话转过去不需要用户自己记一堆分机号。MyCat解决的就是这个“路由”问题。它最核心的两个能力一个是读写分离一个是分库分表。读写分离把写操作路由到主库读操作分摊到从库减轻单库压力。分库分表数据量太大时按规则把数据分散到多个库、多张表单表数据量降下来查询和维护都轻松。这两个能力正好卡在大多数业务从单库走向分布式的关键节点上。相比让应用层自己维护数据源切换逻辑MyCat把复杂度收拢到一层业务代码几乎不用改。1.2 核心概念schema、dataNode、dataHost、rule配置MyCat之前这几个词必须先吃透它们会贯穿所有配置文件。概念作用类比schema逻辑库应用看到的数据库对应server.xml里的逻辑库配置公司的前台总机号table逻辑表逻辑库中的表可以映射到多个物理表业务上的“订单表”dataNode数据节点一个具体的物理数据库实例存储某个分片某个具体的分机号dataHost数据主机一组物理MySQL实例包含主从关系配置一个具体部门的分机群rule分片规则决定数据写到哪张物理表的算法分机转接规则配置的时候核心思路是先定义dataHost告诉MyCat有哪些真实MySQL再定义dataNode把逻辑表的数据映射到指定MySQL最后在schema.xml里建立逻辑库和逻辑表与dataNode之间的对应关系。1.3 SQL是怎么被路由的一条SQL进入MyCat后大致走这样一条链连接管理应用通过MySQL协议连上MyCatMyCat复用后端连接池。语法解析MyCat解析SQL拿到表名、条件、操作类型读或写。路由匹配根据schema.xml中逻辑表对应的dataNode以及rule.xml中的分片规则决定把SQL发往哪个dataNode。执行与合并如果有跨分片查询MyCat会分发到多个dataNode执行再合并结果返回。这个过程中读请求和写请求会在路由阶段根据balance参数被区分开这是实现读写分离的关键。后面我会专门用一节来拆。2. 环境准备与安装部署2.1 安装前需要准备什么MyCat的运行环境很简单但版本选择上有几个坑要注意。JDKMyCat主要是Java写的建议JDK 1.8及以上当前大部分生产环境用1.8最稳。MySQL主库和从库都需要建议5.7或8.0。MyCat对MySQL协议兼容性做得不错但尽量保持主从版本一致。MyCat版本建议用1.6.x稳定版。2.x版本虽然架构更新但生产使用广度和社区资料远不如1.6丰富初学者直接从1.6开始更顺。下载方式可以直接从MyCat官网获取发行包解压后目录结构如下mycat/ ├── bin/ # 启动脚本 ├── conf/ # 配置文件目录修改的核心都在这 │ ├── schema.xml │ ├── server.xml │ └── rule.xml ├── lib/ # 依赖jar包 └── logs/ # 运行日志2.2 快速启动MyCat先把服务跑起来再慢慢调配置。# 解压 tar -zxvf Mycat-server-1.6.7.6-release-20190627191026-linux.tar.gz mv mycat /usr/local/ # 启动 cd /usr/local/mycat/bin ./mycat start # 查看状态 ./mycat status启动成功后MyCat默认监听8066端口管理端口是9066。如果启动失败优先去看logs目录下的wrapper.log和mycat.log绝大多数问题都能在日志里找到线索。2.3 server.xml基础配置server.xml里主要配置连接MyCat的账号、权限和系统参数。最小可用的配置长这样user nameroot defaultAccounttrue property namepassword123456/property property nameschemasTESTDB/property /user system property nameserverPort8066/property property namemanagerPort9066/property /system这里“TESTDB”是逻辑库名一会儿要在schema.xml里定义。应用连MyCat时用的就是root/123456而不是后端MySQL的真实账号。MyCat会把应用认证和后端MySQL认证解耦这样做的好处是就算后端MySQL账号变更应用侧连接串不用跟着改。3. 读写分离配置实战MyCat的看家本领“mycat读写分离”在很多讨论里都是热门话题因为这是绝大多数团队第一次引入MyCat的直接原因。相比分库分表读写分离的配置改动小、动风险低、见效快。3.1 前提MySQL主从复制要正常MyCat本身不负责数据同步。读写分离的底层依赖是MySQL主从复制MyCat只负责任务调度把写操作发给主库把读操作发给从库。如果主从复制没搭好后面的一切都白搭。搭建主从复制不是这篇文章的重点但有一个关键点要确认在从库上执行SHOW SLAVE STATUS确保Slave_IO_Running和Slave_SQL_Running都是Yes。只有主从同步正常MyCat的读写分离才有意义。3.2 配置writeHost和readHost读写分离的配置集中在schema.xml的dataHost节点里。一个标准的读写分离配置如下dataHost namelocalhost1 maxCon1000 minCon10 balance1 writeType0 dbTypemysql dbDriverjdbc switchType1 heartbeatselect user()/heartbeat writeHost hosthostM1 url192.168.1.10:3306 userroot passwordroot1234 readHost hosthostS1 url192.168.1.11:3306 userroot passwordroot1234/ /writeHost /dataHost这里的核心是两层关系writeHost主库连接写操作默认走这里。readHost从库连接挂在某个writeHost下面读操作按balance规则分发。配置里还有另外两个参数要理解writeType写操作的路由策略0表示只发给第一个writeHost1表示轮流发。生产环境推荐0。switchType主从切换策略1表示自动切换。主库挂了会自动把备用的writeHost提升为主避免写操作全部失败。3.3 balance参数读写分离的关键开关balance是读写分离的开关也是最多人配置错的地方。它控制MyCat对读请求的负载均衡策略balance值行为适用场景0不开启读写分离所有读操作都发到writeHost不准备做读写分离时1读请求在writeHost和readHost之间分发主库也承担部分读压力常见于双主场景2读请求只发到readHost标准读写分离主库只处理写3读请求发到readHost且所有readHost都参与1.6版本开始支持多个从库场景希望所有从库都分摊读压力我最常用的是balance1和balance2。如果从库配置了多个建议在1.6.x版本下用balance3确保所有readHost都能接到读流量。balance1时从库和主库都会分担读有时候主库读压力并没有理想中被减轻需要根据实际监控调整。3.4 验证读写分离是否生效配置改完后重启MyCat然后在应用里执行几条SQL对比一下-- 写操作 INSERT INTO user_order (id, amount) VALUES (1, 100); -- 读操作 SELECT * FROM user_order WHERE id 1;怎么确认读请求真的到了从库最直接的办法是在主库和从库上分别开启通用日志然后观察语句执行情况。SET GLOBAL general_log ON; SET GLOBAL log_output TABLE;执行完读操作后分别查SELECT * FROM mysql.general_log WHERE argument LIKE %select% ORDER BY event_time DESC LIMIT 10;如果看到读SQL出现在从库日志里说明读写分离已经生效。这个验证方式虽然简单却非常有效我第一次配置完就是这么确认的。3.5 读写分离的常见坑配置读写分离时最容易踩的坑是忘了做主从复制延迟补偿。MyCat只做路由读请求一旦发到从库而主从复制延迟还没追平就会读到旧数据。对一致性要求高的场景比如支付结果查询建议把这类关键读操作强制路由到主库。MyCat提供了注解方式/*!mycat:db_typemaster*/ SELECT * FROM order_info WHERE order_id 100;加了这行注释MyCat就会把这条读请求强制发到主库。这个技巧在业务里非常实用能精准控制哪些读必须走主库。4. 分库分表配置从入门到进阶读写分离解决的是并发压力分库分表解决的是单表数据量过大导致的性能瓶颈。当单表数据量超过千万级索引维护成本变高、写入变慢这时就该考虑分片了。4.1 什么时候需要分片我的判断标准有三条满足其一就可以开始规划单表数据量超过千万且持续高速增长。单表写入TPS明显下降索引维护时间过长。单库容量接近上限无法通过扩容磁盘解决。分片的核心思路是“把一张大表横向拆成多张小表”。比如订单表按月分片每张物理表存一个月的订单查询时路由到对应月份的表单表数据量就被控制住了。MyCat里的分片必须同时配置逻辑表、物理存储节点和分片规则。4.2 水平分片配置示例假设我要把user表按用户ID取模分成4片物理上落在两个MySQL实例上。schema.xml里的配置这样写schema nameTESTDB checkSQLschematrue sqlMaxLimit100 table nameuser primaryKeyid dataNodedn1,dn2,dn3,dn4 rulemod-long/ /schema dataNode namedn1 dataHosthost1 databasedb_user_0 / dataNode namedn2 dataHosthost1 databasedb_user_1 / dataNode namedn3 dataHosthost2 databasedb_user_0 / dataNode namedn4 dataHosthost2 databasedb_user_1 /注意这里的dataNode是“数据库”级别的映射每个dataNode对应一个具体的物理数据库。这就是为什么分片后物理库可能是db_user_0、db_user_1这类带编号的库。这么做的好处是数据分散到多实例多库多表单点磁盘和CPU压力都会被分摊。4.3 rule.xml分片规则配置rule.xml定义了分片的算法。取模分片是最常见也最好理解的规则tableRule namemod-long rule columnsid/columns algorithmmod-long/algorithm /rule /tableRule function namemod-long classio.mycat.route.function.PartitionByMod property namecount4/property /function意思是对user表的id字段取模模数4对应4个数据节点。id5的数据5%41会被路由到dn2。这个规则简单直接但扩展性一般——一旦数据量再涨要把4片扩容到8片历史数据全部要重分布。所以取模分片适合数据规模相对稳定的场景。如果预见到数据量会持续增长建议一开始就用range分片比如按用户ID区间划分扩容时只需要新增节点不需要动老数据。缺点是有可能热点集中在某些区间需要一定预判能力。4.4 全局表与ER分片分片之后最头疼的问题就是关联查询。两张分片表join如果数据不在同一个物理库MyCat要跨库查再合并性能非常差。MyCat提供了两个方案ER分片订单表和订单明细表按相同的字段分片比如都按订单ID取模这样同一个订单的数据就在同一个节点上join就不需要跨库。全局表像商品分类、省份这类数据量小、不常修改、但高频关联的表复制到每个节点上查询直接在本地完成。配置方式是在schema.xml里用childTable建立父子关系table nameorder primaryKeyid dataNodedn1,dn2 rulemod-long childTable nameorder_item primaryKeyid joinKeyorder_id parentKeyid / /table这个配置的意思是order_item表跟着order表分片order_id相同的父子记录必然落在同一个dataNode上。这是一个很关键的设计我在实际项目中遇到关联查询性能问题时优先就是检查分片是否对齐了关联字段。5. 常见问题与排查技巧实录5.1 连接8066失败报Access denied优先检查server.xml里配置的user和schema是否对得上。MyCat的逻辑库名跟在连接串里指定的库名必须一致。还有一个容易被忽略的细节连接MyCat时指定的库名必须是schema里已定义的名字否则即使账号密码正确也会被拒绝。5.2 读写分离配置了但读请求还是全打到主库这种问题90%出在balance参数上。检查dataHost里的balance是否是非0值以及配置修改后是否重启了MyCat。还有一种情况是全局表或使用了强制主库注解这类请求本来就应该走主库属于预期行为。5.3 分片查询结果不对数据写过去了但查不出来或者查到了别的分片的数据大概率是分片字段和规则不匹配。排查步骤确认SQL的where条件是否包含分片字段。MyCat只有拿到分片字段才能计算目标节点。确认多条数据的分片字段值是否均匀取模本来就要求字段分布均匀。查看MyCat日志里的route信息会打印每条SQL被路由到哪个dataNode。logs/mycat.log里能看到类似route result的日志这是排查分片路由问题最直接的手段比瞎猜高效得多。5.4 性能优化建议MyCat本身是代理层SQL性能的下限由SQL质量和索引决定。接入MyCat后有几个优化点需要额外关注关闭MyCat的SQL统计功能能减少一部分解析开销。合理设置连接池参数maxCon和minCon要根据应用并发数调建议maxCon在500到1000之间。减少跨分片查询。分片规则设计时就要尽量让常用查询条件包含分片字段。对大表的排序和分组尽量把计算下推到物理库MyCat的合并排序在数据量很大时内存消耗明显。6. 我的实际操作体会做MyCat落地这几个项目下来我最大的感受是别把MyCat当银弹。它是一个路由层把复杂的分布式数据访问收拢成统一的入口但它放大了设计上的问题而不会凭空解决性能问题。分片键的选择、读写分离的一致性策略、从库延迟的容忍度这些都要在业务设计阶段想清楚。如果你刚开始接触MyCat我建议不要一上来就搞复杂分片。先从最简单的读写分离开始把主从复制做扎实把balance和switchType调明白确认读流量真的按预期走。等业务量增长到确实有单表瓶颈了再考虑分库分表并且务必在设计阶段就确定好分片字段和分片规则。最后再分享一个小技巧MyCat的配置修改虽然支持热加载但生产环境我从来不用reload都是低峰期重启MyCat。配置文件写错导致的路由异常远比那几分钟重启时间更麻烦。配置改动前把schema.xml、server.xml、rule.xml三个文件备份好回滚时能省下很多时间。本文还有配套的精品资源点击获取
返回列表