面试官:你项目是如何实现读写分离的?

读写分离(Read-Write Splitting)是一种常见的数据库架构优化策略,通过将数据库的读操作(查询)和写操作(插入、更新、删除)分离到不同的数据库实例上,从而提高系统的性能、可扩展性和高可用性

在项目中实现读写分离目前主流的实现技术是通过 Apache ShardingSphere 来实现数据库的读写分离的。

从 Apache ShardingSphere 官网也可以看出读写分离是其提供的主要功能之一:

ShardingSphere 官网地址:shardingsphere.apache.org/document/cu...

通过 ShardingSphere 可以轻松实现 MySQL 数据库的读写分离,以下是基于最新 ShardingSphere 5.x 版本的实现步骤和关键代码:

1.核心实现原理

ShardingSphere 通过 JDBC 驱动层透明代理实现读写分离,其核心逻辑为:

  1. SQL 路由:根据 SQL 类型(SELECT/WRITE)自动路由到主库或从库。
  2. 负载均衡:支持轮询、随机权重等算法分配读请求到多个从库。
  3. 主从同步:依赖 MySQL 原生主从复制机制保障数据一致性。

2.具体实现步骤

步骤 1:搭建MySQL主从复制(前置条件)

sql 复制代码
-- 主库配置(my.cnf)
server-id=1
log-bin=mysql-bin
binlog-format=ROW

-- 从库配置(my.cnf)
server-id=2
relay-log=relay-bin
read-only=1

-- 主库创建复制账号
CREATE USER 'repl'@'%' IDENTIFIED BY 'P@ssw0rd';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

-- 从库配置主库连接
CHANGE MASTER TO 
  MASTER_HOST='master_ip',
  MASTER_USER='repl',
  MASTER_PASSWORD='P@ssw0rd',
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=592;
START SLAVE;

步骤 2:SpringBoot项目集成ShardingSphere-JDBC

1.添加 Maven 依赖

在 pom.xml 中添加 ShardingSphere 和数据库连接池的依赖:

xml 复制代码
<dependency>
  <groupId>org.apache.shardingsphere</groupId>
  <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
</dependency>
<dependency>
  <groupId>com.mysql</groupId>
  <artifactId>mysql-connector-j</artifactId>
</dependency>

2.配置 application.yml

在 application.yml 中配置数据源和读写分离规则:

yaml 复制代码
spring:
  shardingsphere:
    datasource:
      names: master,slave0
      # 主库配置
      master:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://master_ip:3306/db?useSSL=false
        username: root
        password: Master@123
      # 从库配置  
      slave0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://slave_ip:3306/db?useSSL=false
        username: root
        password: Slave@123
      # 从库2配置  
      slave1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://slave_ip:3306/db?useSSL=false
        username: root
        password: Slave@123
    rules:
      readwrite-splitting:
        data-sources:
          readwrite_ds:
            type: Static
            props:
              write-data-source-name: master
              read-data-source-names: 
                - slave0
                - slave1
            load-balancer-name: round_robin
        load-balancers:
          round_robin:
            type: ROUND_ROBIN # 轮询
    props:
      sql-show: true  # 显示实际路由的SQL

配置说明

  • 数据源配置
    • master:主库数据源,用于写操作。
    • slave0 和 slave1:从库数据源,用于读操作。
  • 读写分离规则
    • write-data-source-name:指定写操作的数据源。
    • read-data-source-names:指定读操作的数据源列表。
    • load-balancer-name:指定读操作的负载均衡算法。
  • 负载均衡算法
    • ROUND_ROBIN:轮询算法,读请求会在 slave0 和 slave1 之间轮询。
    • 其他可选算法:RANDOM(随机)、WEIGHT(权重)等。

3.验证读写分离

1.写操作测试

java 复制代码
public void createUser(User user) {
userMapper.insert(user); // INSERT 语句自动路由到master
}

2.读操作测试

java 复制代码
public List<User> listUsers() {
    return userMapper.selectList(null); // SELECT 语句路由到slave0
}

3.查看执行日志

控制台会输出类似日志:

plain 复制代码
Actual SQL: master ::: INSERT INTO user (...)
Actual SQL: slave0 ::: SELECT * FROM user

3.高级配置(可选)

  1. 强制主库读通过 Hint 强制路由到主库:
java 复制代码
HintManager.getInstance().setPrimaryRouteOnly();
  1. 故障转移配置心跳检测实现从库故障自动剔除:
yaml 复制代码
spring:
  shardingsphere:
    rules:
      readwrite-splitting:
        data-sources:
          readwrite_ds:
            type: Dynamic
            props:
              auto-aware-data-source-name: readwrite_ds
              health-check-enabled: true
              health-check-max-retry-count: 3
              health-check-retry-interval: 5000

注意事项

主从延迟问题:异步复制场景下,刚写入的数据可能无法立即从从库读取,可通过 HintManager 强制读主库临时解决。

4.优缺点分析

  1. 优点分析
    1. 提升性能:写操作通常对性能要求较高,而读操作可以通过从库分担压力,避免主库因高并发查询而过载。从库可以进行水平扩展(增加更多从库实例),进一步提升系统的读取能力。
    2. 提高可用性:主库和从库可以部署在不同的服务器或机房,增加系统的容错性。即使某个从库出现故障,其他从库仍然可以继续提供读服务。
    3. 优化资源利用:主库可以专注于处理写操作,从库可以优化查询性能(如添加更多的索引、缓存等)。
  2. 缺点分析
    1. 数据一致性延迟:由于从库的数据是通过主库同步而来,可能存在一定的延迟(秒级或更长),导致读操作可能读取到旧数据。
    2. 复杂性增加:需要管理主从复制的配置和同步机制。需要处理主从切换、故障转移等复杂情况。
    3. 成本增加:需要额外的硬件资源来部署从库。需要额外的运维成本来维护主从架构。

5.应用场景

读写分离适用于以下场景:

  • 读操作远多于写操作系统:如电商系统、社交平台等,读操作远多于写操作。
  • 需要高可用性:通过主从架构提高系统的容错能力。

小结

读写分离是一种常见的数据库架构优化策略,通过将数据库的读操作和写操作分离,提高了系统的性能、可扩展性和高可用性。读写分离主流的实现技术是 Apache ShardingSphere,通过添加依赖,配置读写分离规则的方式就可以轻松的实现读写分离。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:场景题、并发编程、MySQL、Redis、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、JVM、设计模式、消息队列等模块。

相关推荐
风象南4 小时前
我把大脑开源给了AI
人工智能·后端
哈里谢顿8 小时前
1000台裸金属并发创建中的重难点问题分析
面试
哈里谢顿8 小时前
20260303面试总结(全栈)
面试
橙序员小站9 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
怒放吧德德9 小时前
Netty 4.2 入门指南:从概念到第一个程序
java·后端·netty
雨中飘荡的记忆10 小时前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
开心就好202512 小时前
UniApp开发应用多平台上架全流程:H5小程序iOS和Android
后端·ios
悟空码字12 小时前
告别“屎山代码”:AI 代码整洁器让老项目重获新生
后端·aigc·ai编程
小码哥_常12 小时前
大厂不宠@Transactional,背后藏着啥秘密?
后端
奋斗小强12 小时前
内存危机突围战:从原理辨析到线上实战,彻底搞懂 OOM 与内存泄漏
后端