MySQL 分库分表常见方案与 ShardingSphere 实战思路

当单表数据量逼近千万级、单库连接数频繁触顶时,分库分表就不再是“要不要做”的问题,而是“怎么做、用什么做”的问题。面试中,这个话题几乎是大厂后端岗位的必考题,考察点从方案选型一直延伸到分布式事务与扩容。本文从面试视角梳理常见方案,并给出 ShardingSphere 的实战思路。

一、为什么要分库分表

先明确边界:分库分表解决的是单库单表容量与性能瓶颈,不是万能药。触发时机通常有三类信号:

  • 数据量:单表超过 500 万~1000 万行,B+ 树索引层数增加,查询明显变慢;
  • 连接数:单库连接数打满,应用侧频繁获取连接超时;
  • 磁盘与 IO:单机磁盘容量、IOPS 成为写入瓶颈。

面试时如果能主动说出“先优化索引、读写分离、缓存,再考虑分片”,会比直接背方案更加分。

二、常见分片方案对比

1. 垂直拆分

按业务维度把不同表拆到不同库,例如用户库、订单库、商品库。优点是业务解耦、专库专用;缺点是跨库 JOIN 消失,分布式事务变复杂。垂直拆分通常是第一步,成本低、收益直接。

2. 水平拆分

同一张表按规则拆到多个库/表。核心在于分片键的选择:

  • 范围分片:按 ID 区间或时间区间。优点是扩容方便、范围查询高效;缺点是热点集中,新数据总落在最后一个分片。
  • 哈希分片:如 user_id % 4。优点是数据分布均匀;缺点是扩容需要数据迁移,范围查询要广播到所有分片。
  • 一致性哈希:缓解扩容迁移量,但实现复杂度上升,且容易产生数据倾斜。
  • 基因法/复合分片:把分片基因嵌入 ID,使订单按 user_id 分片后,order_id 也能定位到分片,避免二次路由。

3. 中间件选型

方案 代表 特点
客户端分片 ShardingSphere-JDBC 无代理、性能好,侵入应用
代理分片 ShardingSphere-Proxy、MyCat 对应用透明,多一层网络开销
云原生 PolarDB-X、TiDB 运维托管,成本较高

面试常问“JDBC 和 Proxy 怎么选”:追求低延迟、团队能改代码选 JDBC;多语言栈、想对应用透明选 Proxy。

三、分库分表后的棘手问题

这是面试区分度最高的部分,能答出以下几点说明真正落地过:

  1. 分布式主键:不能再用自增 ID。常见方案有雪花算法(Snowflake)、号段模式(Leaf)、Redis INCR。雪花算法要注意时钟回拨。
  2. 跨分片查询:分页、排序、聚合需要归并。LIMIT 100 OFFSET 10000 在分片下要改写为各分片取 OFFSET+LIMIT 再内存归并,深分页性能极差,通常用“上次最大 ID”游标法优化。
  3. 分布式事务:跨库写入用 Seata AT/TCC 或本地消息表、最终一致性。强一致场景慎用分片。
  4. 扩容:哈希取模扩容要迁移大量数据。实践上常用成倍扩容 + 双写迁移,或预分片(如先分 1024 张逻辑表,物理机少放几张,扩容只搬逻辑表)。
  5. 全局唯一性与字典表:小表做广播表,每个库一份,避免跨库 JOIN。

四、ShardingSphere 实战思路

ShardingSphere 是当前国内落地最广的方案,分为 JDBC 和 Proxy 两个产品。以下以 Spring Boot + ShardingSphere-JDBC 为例。

1. 依赖与配置

spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        jdbc-url: jdbc:mysql://127.0.0.1:3306/order_db0
        username: root
        password: root
      ds1:
        jdbc-url: jdbc:mysql://127.0.0.1:3306/order_db1
        # 其余同上
    rules:
      sharding:
        tables:
          t_order:
            actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: db-inline
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: table-inline
        sharding-algorithms:
          db-inline:
            type: INLINE
            props:
              algorithm-expression: ds$->{user_id % 2}
          table-inline:
            type: INLINE
            props:
              algorithm-expression: t_order_$->{order_id % 2}

这段配置把 t_order 拆成 2 库 × 2 表。注意分库键用 user_id、分表键用 order_id,是为了让同一用户的订单落在同库、单号又能均匀打散。

2. 分片键与路由

ShardingSphere 的核心是 SQL 解析 → 路由 → 改写 → 执行 → 归并。写 SQL 时要尽量带上分片键,否则会全路由广播,性能急剧下降。面试可举例:WHERE user_id = ? 能精确定位到一个库,WHERE create_time > ? 则会广播到所有分片。

3. 分布式主键

@Bean
public KeyGenerator keyGenerator() {
    return new SnowflakeKeyGenerator();
}

配置 key-generator 后,插入时无需手动设置主键,ShardingSphere 自动生成。

4. 读写分离与广播表

  • 读写分离:通过 readwrite-splitting 规则配置主从,写走主库、读走从库,注意主从延迟下的“写后读”一致性。
  • 广播表:字典表配置 broadcast-tables,每个库都存一份,JOIN 时无需跨库。
  • 绑定表:分片规则一致的关联表(如 t_ordert_order_item)配置 binding-tables,避免笛卡尔积关联。

5. 扩容思路

ShardingSphere 提供 Scaling(原 ElasticJob 生态)做数据迁移,原理是双写 + 存量迁移 + 校验 + 切换。实践中更稳的做法是:

  1. 新老集群双写,读仍走老集群;
  2. 用迁移工具同步存量数据并校验;
  3. 灰度切读,观察无异常后切写;
  4. 下线老集群。

五、面试答题框架

如果被问“你们怎么做分库分表”,可以按这个结构回答:

  1. 判断必要性:数据量、QPS、连接数达到什么阈值才做;
  2. 选型:垂直还是水平、分片键怎么选、JDBC 还是 Proxy;
  3. 落地:ShardingSphere 配置、分布式主键、广播表、绑定表;
  4. 踩坑:深分页、跨库 JOIN、分布式事务、扩容迁移;
  5. 兜底:监控慢 SQL、热点分片、数据倾斜治理。

分库分表本质是用复杂度换扩展性。面试官想听的不是“我用了 ShardingSphere”,而是你理解每一次拆分带来的代价,以及如何用工程手段把代价控制在可接受范围内。

未经允许不得转载:任鹏个人博客 » MySQL 分库分表常见方案与 ShardingSphere 实战思路

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏