MySQL数据库读写分离 以及 实现方式

MySQL 读写分离是提升数据库性能和可用性的核心架构设计,通过将写操作(INSERT/UPDATE/DELETE)路由到主库(Master)、读操作(SELECT)路由到从库(Slave)实现负载均衡。以下是详细实现方案:


一、为什么需要读写分离?

场景读写分离的价值
读多写少(如电商、内容平台)80%+ 读请求分散到从库,减轻主库压力
高并发场景水平扩展读能力,避免单点性能瓶颈
数据分析/报表复杂查询不影响主库业务
灾备恢复从库作为备份,主库故障时可切换

二、MySQL 读写分离架构图

写操作
读操作
读操作
主从同步
主从同步
应用程序
读写分离中间件
Master 主库
Slave1 从库
Slave2 从库

三、四大实现方式详解

1. 应用层代码实现(直连数据库)
  • 原理:在业务代码中硬编码或配置读写路由规则
  • 示例(Spring Boot + MyBatis):
    @Configuration
    public class DataSourceConfig {
        
        @Bean(name = "masterDataSource")
        public DataSource masterDataSource() {
            // 配置主库
            return DataSourceBuilder.create()...build();
        }
    
        @Bean(name = "slaveDataSource")
        public DataSource slaveDataSource() {
            // 配置从库
            return DataSourceBuilder.create()...build();
        }
    
        @Bean
        public AbstractRoutingDataSource routingDataSource() {
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put("master", masterDataSource());
            targetDataSources.put("slave", slaveDataSource());
            
            AbstractRoutingDataSource ds = new AbstractRoutingDataSource() {
                @Override
                protected Object determineCurrentLookupKey() {
                    // 根据事务/注解决定数据源
                    return TransactionSynchronizationManager.isCurrentTransactionReadOnly() 
                           ? "slave" : "master";
                }
            };
            ds.setTargetDataSources(targetDataSources);
            return ds;
        }
    }
    
  • 优点:简单直接,无额外组件依赖
  • 缺点
    • 侵入业务代码,维护成本高
    • 无法自动感知从库故障
    • 负载均衡能力弱

2. 数据库中间件代理(推荐方案)

在应用与数据库之间部署代理层,自动路由请求

中间件开发方特点
MySQL RouterMySQL官方轻量级,集成于MySQL生态,支持自动故障转移
ProxySQL开源社区高性能(毫秒级延迟),支持动态配置加载
MyCAT阿里开源支持分库分表+读写分离,适合复杂场景
ShardingSphere-ProxyApache生态强大,兼容多种数据库,支持分布式事务

ProxySQL 典型配置

-- 定义主库
INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (10, 'master', 3306);

-- 定义从库
INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (20, 'slave1', 3306);
INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (20, 'slave2', 3306);

-- 配置读写路由规则
INSERT INTO mysql_query_rules(active, match_pattern, destination_hostgroup) 
VALUES 
(1, '^SELECT.*', 20),   -- 读操作路由到从库组
(1, '.*', 10);          -- 其他操作路由到主库

-- 保存配置
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

3. 驱动层实现(透明化方案)
  • 原理:JDBC 驱动层自动分离读写(如:ShardingSphere-JDBC)
  • 示例配置
    # ShardingSphere-JDBC 配置
    spring:
      shardingsphere:
        datasource:
          names: master,slave0,slave1
          master:
            type: com.zaxxer.hikari.HikariDataSource
            jdbc-url: jdbc:mysql://master:3306/db
          slave0:
            type: com.zaxxer.hikari.HikariDataSource
            jdbc-url: jdbc:mysql://slave0:3306/db
          slave1:
            type: com.zaxxer.hikari.HikariDataSource
            jdbc-url: jdbc:mysql://slave1:3306/db
        rules:
          replica-query:
            data-sources:
              pr_ds:
                primary-data-source-name: master
                replica-data-source-names: slave0,slave1
                load-balancer-name: round_robin
            load-balancers:
              round_robin:
                type: ROUND_ROBIN
    
  • 优点
    • 对应用透明(无需改代码)
    • 支持负载均衡算法(轮询、权重等)
  • 缺点:需引入特定驱动

4. 基于DNS的读写分离
  • 原理:为读/写分别配置不同DNS域名
    • write.example.com → 主库IP
    • read.example.com → 从库SLB(负载均衡器)
  • 优点:实现简单
  • 缺点
    • DNS缓存导致故障切换延迟
    • 无法根据SQL类型精细路由
    • 已逐渐被中间件方案取代

四、关键问题与解决方案

1. 主从延迟导致数据不一致
  • 场景:用户下单后立即查询订单,从库尚未同步
  • 解决方案
    • 强制读主库:对一致性要求高的操作添加注解(如 @Master
    • GTID 等待:执行读操作前等待指定GTID同步(需业务改造)
    • 半同步复制:确保至少一个从库收到binlog才返回成功(rpl_semi_sync_master_wait_for_slave_count=1
2. 事务中的读写分离
  • 问题:事务内混合读写操作时强制路由到主库
  • 方案
    • 开启事务时自动使用主库连接
    • 通过注解标记只读事务(Spring @Transactional(readOnly = true)
3. 从库故障处理
  • 健康检查:中间件定期探测从库状态
  • 自动摘除:故障从库被移出连接池(如ProxySQL的 mysql-monitor

五、方案选型建议

场景推荐方案理由
中小项目,快速落地应用层代码实现简单,无需部署额外组件
高并发生产环境ProxySQL/MySQL Router高性能,自动故障转移
微服务+分库分表ShardingSphere-JDBC一体化解决方案,生态完善
云数据库(如RDS)云厂商代理服务免运维,深度集成(如阿里云Proxy)

六、最佳实践

  1. 从库读负载均衡
    • 轮询(Round Robin):默认均分流量
    • 权重分配:高性能从库承担更多流量
  2. 连接池配置
    # HikariCP 示例
    maximumPoolSize=20  # 避免连接数超过数据库限制
    connectionTimeout=3000
    
  3. 监控告警
    • 主从延迟监控(SHOW SLAVE STATUSSeconds_Behind_Master
    • 代理层性能指标(QPS、连接数、延迟)
  4. 灰度发布
    • 先切部分读流量到新从库观察
    • 使用中间件的权重调整功能逐步迁移

💡 终极建议
对于核心业务,ProxySQL + 多从库是最稳健的方案;对于云环境,直接使用云数据库的读写分离功能(如AWS RDS Proxy)可大幅降低运维复杂度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值