MyCat 读写分离详解
概述
MyCat 是一个开源的分布式数据库中间件,基于阿里巴巴的Cobar项目开发而来。它主要实现了数据库的读写分离、分库分表等功能。读写分离是指将数据库的读操作(查询)和写操作(增删改)分离到不同的数据库服务器上,从而提升数据库的并发处理能力和整体性能。
在实际应用中,MyCat 采用Java开发,支持MySQL、Oracle、SQL Server等多种数据库协议,能够有效地解决单机数据库的性能瓶颈问题。通过将读写操作分散到不同服务器,可以显著提高系统的吞吐量和响应速度。
读写分离基本原理
在完整的读写分离架构中,通常包含以下关键组件:
主库(Master)
- 负责处理所有写操作(INSERT、UPDATE、DELETE)
- 通常只有1个主库,但可以采用主-主复制架构实现双主
- 主库通过二进制日志(binlog)将数据变更同步到从库
- 在MySQL中,主库会记录所有数据变更到binlog文件,从库通过I/O线程读取这些变更
- 主库需要配置server-id和binlog格式(推荐ROW格式)
从库(Slave)
- 负责处理读操作(SELECT)
- 可以有多个从库实现负载均衡
- 从库通过主从复制机制保持与主库数据同步
- 从库需要配置server-id和指定主库位置
- 可以配置延时复制从库,用于数据恢复
- 从库可以配置不同的存储引擎,如InnoDB或TokuDB
中间件(MyCat)
- 作为数据库代理,负责SQL请求的路由分发
- 提供透明的读写分离功能,对应用层无感知
- 支持多种负载均衡策略
- 内置连接池管理,减轻数据库连接压力
- 提供SQL防火墙功能,防止SQL注入
- 支持分布式事务(XA协议)
详细工作流程
客户端请求阶段
- 应用程序通过JDBC或其他方式连接MyCat
- 使用标准数据库连接字符串,如:jdbc:mysql://mycat_host:8066/TESTDB
- 发送SQL请求到MyCat服务端
- 应用程序无需修改代码,保持原有数据库访问方式
SQL解析阶段
- MyCat解析SQL语句类型
- 使用Druid SQL解析器分析SQL语法
- 识别SQL类型:SELECT, INSERT, UPDATE, DELETE等
- 识别为写操作(INSERT/UPDATE/DELETE)或读操作(SELECT)
- 对于特殊SQL(如存储过程、事务等)做特殊处理
- 存储过程自动路由到主库
- 事务中的SELECT默认走主库
- 支持通过注释强制路由:
/*#mycat:db_type=master*/SELECT...
- 检查SQL权限和防火墙规则
路由转发阶段
- 写操作:路由到主库执行
- 自动选择可用的writeHost
- 支持事务一致性路由
- 读操作:根据负载均衡策略选择从库执行
- 随机选择(readBalance="1")
- 权重选择(readBalance="2")
- 主库优先(readBalance="3")
- 支持强制路由(如通过注释指定目标库)
- 使用
/*#mycat:node=dn1*/
指定数据节点 - 使用
/*#mycat:schema=TESTDB*/
指定逻辑库
- 使用
- 处理分片表的路由选择
结果返回阶段
- 接收数据库执行结果
- 处理结果集合并
- 处理错误和异常
- 将结果返回给客户端
- 保持原有JDBC接口
- 支持结果集流式返回
- 记录执行日志和性能指标
- 记录慢SQL日志
- 统计SQL执行时间
- 监控连接使用情况
完整配置示例与说明
schema.xml配置详解
<!-- 定义逻辑库 -->
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<!-- 定义逻辑表映射 -->
<table name="user" dataNode="dn1" primaryKey="id" type="global"/>
<table name="order" dataNode="dn1,dn2" rule="mod-long" />
<!-- 分片表配置示例 -->
<table name="log" dataNode="dn1,dn2,dn3" rule="sharding-by-date" />
</schema>
<!-- 定义数据节点 -->
<dataNode name="dn1" dataHost="localhost1" database="test" />
<dataNode name="dn2" dataHost="localhost2" database="test" />
<dataNode name="dn3" dataHost="localhost3" database="test" />
<!-- 定义数据主机 -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1"
slaveThreshold="100" tempReadHostAvailable="1">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 主库配置 -->
<writeHost host="hostM1" url="192.168.1.100:3306" user="root"
password="123456" weight="1">
<!-- 从库配置 -->
<readHost host="hostS1" url="192.168.1.101:3306" user="root"
password="123456" weight="10"/>
<readHost host="hostS2" url="192.168.1.102:3306" user="root"
password="123456" weight="20"/>
</writeHost>
<!-- 备用主库配置 -->
<writeHost host="hostM2" url="192.168.1.200:3306" user="root"
password="123456" weight="1">
<readHost host="hostS3" url="192.168.1.201:3306" user="root"
password="123456" weight="10"/>
</writeHost>
</dataHost>
关键配置参数详解
balance参数:
- 0:不开启读写分离,所有读请求都发到主库
- 适用于对数据实时性要求极高的场景
- 1:所有读操作随机发送到从库
- 适用于读多写少的业务场景
- 2:所有读操作按权重分配
- 适用于从库配置不同的硬件资源
- 3:读操作优先发送到主库,主库不可用时才发送到从库
- 适用于读写混合且对实时性要求高的场景
writeType参数:
- 0:所有写操作发送到第一个writeHost
- 默认配置,确保写操作一致性
- 1:写操作随机发送到writeHost
- 适用于双主架构
- 2:按权重分配写操作
- 适用于多主且负载均衡场景
switchType参数:
- -1:不自动切换
- 需要人工干预主从切换
- 1:自动切换(默认)
- 基于心跳检测结果自动切换
- 2:基于MySQL主从同步状态决定是否切换
- 检查Seconds_Behind_Master值
- 3:基于MySQL galera cluster状态切换
- 适用于集群环境
高级配置与管理
server.xml配置详解
<system>
<!-- 系统参数配置 -->
<property name="defaultSqlParser">druidparser</property>
<property name="sequnceHandlerType">1</property>
<property name="useCompression">1</property>
<!-- 连接池参数 -->
<property name="processorBufferPool">204800</property>
<property name="processorBufferLocalPercent">100</property>
<!-- 系统日志配置 -->
<property name="sqlInterceptor">com.mycat.route.interceptor.StatisticsInterceptor</property>
</system>
<user name="app_user">
<property name="password">app_password</property>
<property name="schemas">TESTDB</property>
<!-- 读写权限控制 -->
<property name="readOnly">false</property>
<!-- 最大连接数 -->
<property name="maxCon">100</property>
<!-- 权限表配置 -->
<privileges check="true">
<schema name="TESTDB" dml="0110">
<table name="user" dml="1111"/>
<table name="order" dml="1110"/>
</schema>
</privileges>
</user>
<user name="readonly_user">
<property name="password">readonly_pass</property>
<property name="schemas">TESTDB</property>
<property name="readOnly">true</property>
<property name="maxCon">50</property>
</user>
监控与管理
MyCat管理命令:
-
数据源状态监控:
show @@datasource; -- 查看数据源状态 show @@datasource where schema = 'TESTDB'; -- 按库查看
-
心跳状态监控:
show @@heartbeat; -- 查看心跳状态 show @@heartbeat where name='hostM1'; -- 指定主机查看
-
连接状态监控:
show @@connection; -- 查看连接状态 show @@connection where host='192.168.1.100'; -- 按IP查看
-
后端连接状态:
show @@backend; -- 查看后端连接状态 show @@backend where type=0; -- 查看活跃连接
-
其他常用命令:
show @@sql; -- 查看正在执行的SQL show @@slow; -- 查看慢SQL reload @@config; -- 重载配置
性能监控:
-
通过JMX接口获取性能指标:
- 连接数统计
- SQL执行次数
- 缓存命中率
- 网络流量统计
-
监控SQL执行时间、频率等:
- 记录超过阈值(如500ms)的SQL
- 统计高频SQL语句
- 分析SQL执行计划
-
设置慢SQL阈值并记录:
<property name="sqlSlowTime">500</property> <property name="sqlRecordCount">1000</property>
实际应用场景与最佳实践
电商系统应用:
-
商品浏览(SELECT)走从库
- 商品列表查询
- 商品详情查询
- 商品搜索查询
-
订单创建(INSERT)走主库
- 下单操作
- 支付记录
- 物流信息
-
库存扣减(UPDATE)走主库
- 预扣库存
- 实际扣减
- 库存回滚
社交平台应用:
-
动态浏览走从库
- 朋友圈读取
- 动态流加载
- 消息历史查询
-
发布动态走主库
- 发布新动态
- 编辑动态
- 删除动态
-
点赞/评论操作走主库
- 点赞记录
- 评论提交
- 互动统计
最佳实践建议:
-
主从延迟监控:
- 设置阈值告警(如超过5秒)
- 监控Seconds_Behind_Master
- 延迟过高时自动降级
-
读写分离粒度:
- 按表分离:核心表走主库
- 按SQL类型分离:复杂查询走从库
- 按业务分离:支付业务强制主库
-
事务处理:
- 事务中的读操作应强制走主库
- 使用
/*#mycat:db_type=master*/
注释 - 考虑分布式事务方案
-
重试机制:
- 主库不可用时的自动重试策略
- 设置合理的重试次数和间隔
- 失败后记录日志并告警
性能优化方向:
-
连接池配置优化:
- 合理设置maxCon和minCon
- 配置空闲连接回收策略
- 监控连接泄漏
-
缓存策略优化:
- 结果集缓存
- 路由缓存
- 热点数据缓存
-
SQL路由算法优化:
- 基于表分析的路由
- 基于SQL特征的路由
- 智能路由选择
-
批量操作处理优化:
- 批量插入优化
- 大批量查询分页
- 并行查询处理
通过合理配置MyCat的读写分离功能,可以显著提升数据库系统的整体性能和处理能力,但需要根据业务特点进行针对性调优和持续监控维护。建议在实施前充分测试不同场景下的性能表现,并制定完善的应急预案。