架构-数据库层面--分库分表--为什么需要分库分表

这篇文章的核心,就是讲,springboot在操作数据库的时候

为什么要去进行分库分表

如何在技术栈配置的时候,实现分库分表

一主多从何多主多从,其实本质上是在架构,机器层面实现三高

而分库分表是在数据层面实现三高

高可用,不太适用,但是高性能,高并发就好了

你的理解非常到位,而且一针见血地指出了分库分表与主从复制的本质区别。我们来把这篇文章的核心逻辑彻底捋顺,并补全**技术栈配置(以ShardingSphere-JDBC为例)**的具体实现细节。

1. 核心本质:架构分层与"三高"分工

你总结得极对:

  • 主从复制(一主多从/多主多从) 是**"机器/架构层"的横向扩展。它解决的是 高可用(HA) 读高并发**(读写分离)。但它的痛点是写性能依然受限于单主节点,且无法解决单表数据量过大的问题。
  • 分库分表(Sharding) 是**"数据层"的横向扩展。它解决的是 海量数据存储写高并发**(将写压力打散)。

关于"高可用"的细化: 你说"高可用不太适用"非常精准。分库分表本身不提供高可用 ,反而会引入分布式故障风险。真正的生产环境,一定是**"分库分表 + 主从复制"结合**:即每个分片(库)内部再搭建主从集群,用主从保高可用 ,用分片保高性能/高并发


2. 为什么要分库分表?(触发阈值)

在Spring Boot中,当出现以下硬性指标时,就必须考虑:

  • 单表数据量 :MySQL单表建议不超过 500万~1000万 行(或磁盘容量达20GB)。超过后,B+树索引层级加深,磁盘IO剧增,即使命中索引,查询延迟也会从毫秒级恶化到秒级。
  • 单库连接数:Spring Boot的HikariCP连接池通常设为核心数*2+1。单库最大连接数约1000个,若微服务实例过多,连接池会成为瓶颈。
  • 写入TPS :单库写入TPS受限于Redo Log和Binlog的刷盘,通常上限在 2000~3000 TPS 左右。

3. 如何在Spring Boot技术栈中实现?(以ShardingSphere-JDBC为例)

目前最主流的实现是 Apache ShardingSphere-JDBC(Sphere-JDBC),它以轻量级Jar包形式注入Spring Boot,无需额外部署Proxy。

核心配置逻辑(YAML / Properties):

第一步:引入依赖 (Maven)
xml 复制代码
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.3.2</version>
</dependency>
第二步:配置数据源(分库分表规则)

这里以**订单表(order)**按 user_id 取模分4个库,按 order_id 取模分4张表为例。

yaml 复制代码
spring:
  shardingsphere:
    datasource:
      names: ds0, ds1, ds2, ds3  # 逻辑数据源名
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_order_0
        username: root
        password: 123456
      # ds1, ds2, ds3 配置类似,指向不同的库 ...
      
    rules:
      sharding:
        tables:
          t_order:  # 逻辑表名(Spring Boot Mapper里操作这个名)
            actual-data-nodes: ds$->{0..3}.t_order_$->{0..3} # 实际节点映射
            # 分库策略
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: mod-db
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: mod-table
        
        sharding-algorithms:
          mod-db:
            type: MOD
            props:
              sharding-count: 4  # 分库数量
          mod-table:
            type: MOD
            props:
              sharding-count: 4  # 分表数量
        
        # 分布式主键生成(避免雪花算法ID冲突)
        key-generators:
          snowflake:
            type: SNOWFLAKE
            props:
              worker-id: 1
第三步:Spring Boot 业务代码零侵入

配置完成后,你的 Mapper 完全不需要改动,依然像操作单表一样注入和使用:

java 复制代码
@Mapper
public interface OrderMapper {
    // 插入时,ShardingSphere会根据user_id自动路由到对应库,根据order_id自动路由到对应表
    @Insert("INSERT INTO t_order (user_id, order_id, amount) VALUES (#{userId}, #{orderId}, #{amount})")
    int insert(Order order);
}

4. 配置时的"三大致命陷阱"(文章必提的重点)

在技术选型和配置时,必须解决这三个核心问题:

  1. 分片键(Sharding Key)必须携带 :增删改查的SQL的WHERE条件中必须包含 分片键(如user_id)。如果不带,ShardingSphere会执行全路由(广播),遍历所有库表,性能直接崩溃。
  2. 跨库事务(分布式事务) :分库后,本地事务失效。若业务强一致性要求(如订单扣库存),需引入 Seata(XA/TCC) ;若弱一致性,可使用ShardingSphere自带的 柔性事务(BASE)
  3. 分布式ID唯一性 :不能依赖数据库自增ID(不同库会重复)。必须使用 雪花算法(Snowflake)美团Leaf 生成全局唯一ID,且该ID常作为分表键,保证数据均匀落盘。

5. 总结:你们的架构演进路线图

文章中最后可以给出一个标准的演进结论:

  • 初期:单库单表 + 主从(读写分离)。
  • 中期(数据量<500万,写QPS<2000)只分表不分库,解决单表锁和索引性能问题。
  • 后期(数据量破亿,写QPS飙升)分库分表 + 主从副本 (每个分片库都配备一主一从)。此时,分库分表扛写流量和存储量主从复制扛读流量和容灾高可用

你需要特别注意:Spring Boot配置的核心,其实就是在application.yml中定义好**"逻辑表" "真实数据节点"的映射规则,以及分片算法**。一旦配好,代码层面完全无感------这也是Spring Boot生态推崇的"配置即服务"的精髓。