Sharding-JDBC 深度实战与面试全攻略

一、Sharding-JDBC 不支持的查询类型

Sharding-JDBC 作为客户端分库分表方案,存在以下查询限制:

1.1 跨分片复杂查询

  • JOIN 操作限制

    • 不支持跨库 JOIN(除非使用绑定表或广播表)

    • 不支持跨表 JOIN(非绑定表关系)

  • 子查询限制

    • 子查询中包含分片表且分片键不一致时

    • 相关子查询(Correlated Subquery)跨分片

  • 聚合函数限制

    • DISTINCT 跨分片使用可能结果不准确

    • AVG 函数需要特殊处理(先 SUM+COUNT 再计算)

    • GROUP_CONCAT 等特定数据库函数

1.2 分页查询限制

  • 大偏移量分页问题

    SELECT * FROM orders LIMIT 100000, 10

    需要从所有分片获取前 100010 条数据再归并

  • 跨分片 ORDER BY + LIMIT
    当排序字段非分片键时,结果可能不准确

1.3 其他限制

  • 不支持存储过程/函数调用

  • 不支持 SAVEPOINT 相关操作

  • 不支持 CASE WHEN 等复杂表达式跨分片

  • 不支持 UNION / UNION ALL 跨分片查询

二、Sharding-JDBC 扩展机制与难点

2.1 扩展方式

  1. 自定义分片算法

    public class CustomShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
        @Override
        public String doSharding(Collection<String> availableTargetNames, 
                                PreciseShardingValue<Long> shardingValue) {
            // 实现自定义分片逻辑
            long value = shardingValue.getValue();
            return "ds_" + (value % 2);
        }
    }
  2. 自定义分布式ID生成器

    public class CustomIdGenerator implements KeyGenerator {
        @Override
        public Comparable<?> generateKey() {
            // 实现自定义ID生成逻辑
            return SnowflakeIdGenerator.nextId();
        }
    }
  3. 自定义SQL改写

    public class CustomSQLRewriter implements SQLRewriteContextDecorator {
        @Override
        public void decorate(SQLRewriteContext context) {
            // 修改SQL执行计划
        }
    }

2.2 扩展难点

  1. SQL兼容性

    • 需要深入理解 SQL 解析引擎(ANTLR)

    • 处理不同数据库方言的差异

  2. 分布式一致性

    • 扩展功能时需考虑数据一致性

    • 跨分片事务处理复杂

  3. 性能优化

    • 避免全路由导致性能下降

    • 流式归并的内存控制

  4. 事务管理

    • 整合分布式事务框架(如 Seata)

    • 柔性事务状态恢复

三、跨分表范围查询实现

3.1 解决方案

  1. 绑定表策略

    shardingRule:
      bindingTables:
        - t_order, t_order_item
  2. Hint 强制路由

    try (HintManager hintManager = HintManager.getInstance()) {
        hintManager.addTableShardingValue("t_order", 1);
        hintManager.addTableShardingValue("t_order", 2);
        // 执行跨分片查询
    }
  3. 范围分片算法

    public class RangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
        @Override
        public Collection<String> doSharding(Collection<String> availableTargetNames,
                                            RangeShardingValue<Long> shardingValue) {
            // 根据范围值返回目标分片
        }
    }

3.2 跨天数据查询

  1. 按时间分片配置

    tables:
      log_table:
        actualDataNodes: ds$->{0..1}.log_$->{202301..202312}
        tableStrategy:
          standard:
            shardingColumn: create_time
            preciseAlgorithmClassName: com.example.MonthShardingAlgorithm
  2. 多天数据合并

    // 自动路由到多个分片
    List<Log> logs = logRepository.findByCreateTimeBetween(
        LocalDate.of(2023, 1, 1), 
        LocalDate.of(2023, 1, 7)
    );
    
    

四、不停服扩容方案

4.1 扩容流程

4.2 关键步骤

  1. 双写阶段

    • 同时写入新旧分片

    • 使用消息队列保证双写一致性

  2. 数据迁移

    • 存量数据:使用 DataX 等工具迁移

    • 增量数据:通过 Binlog 同步(如 Canal)

  3. 数据校验

    // 数据校验伪代码
    List<Data> oldData = queryOldShard(shardKey);
    List<Data> newData = queryNewShard(shardKey);
    assert oldData.equals(newData);
  4. 流量切换

    • 逐步切流(10% → 50% → 100%)

    • 基于配置中心的动态规则更新

4.3 兜底方案

  1. 快速回滚

    • 配置版本化管理

    • 一键回滚机制

  2. 数据补偿

    • 消息队列存储同步差异

    • 定时补偿任务修复数据

  3. 熔断机制

    # 配置熔断规则
    circuitBreaker:
      enable: true
      maxConsecutiveErrors: 5

五、多库多表数据聚合

5.1 归并引擎原理

5.2 聚合类型

  1. 遍历归并:普通查询结果合并

  2. 排序归并ORDER BY 查询

  3. 分组归并GROUP BY 查询

    • 先在分片本地分组

    • 再在内存中合并分组

  4. 聚合归并SUM/COUNT/MAX/MIN

    • 分片本地聚合

    • 结果二次聚合

5.3 分组归并示例

SELECT user_id, SUM(amount) 
FROM orders 
GROUP BY user_id

执行流程:

  1. 各分片执行:SELECT user_id, SUM(amount) FROM orders GROUP BY user_id

  2. 归并引擎按 user_id 合并结果

  3. 对相同 user_id 的 SUM(amount) 再次求和

六、Sharding-JDBC 内部流程

6.1 核心执行流程

6.2 关键组件

  1. 解析引擎:ANTLR 实现的 SQL 解析

  2. 路由引擎:根据分片策略计算目标分片

  3. 改写引擎:逻辑 SQL → 真实 SQL

  4. 执行引擎:并发执行分片查询

  5. 归并引擎:合并分片结果集

七、Sharding-JDBC vs MyCAT

7.1 架构对比

维度Sharding-JDBCMyCAT
架构模式客户端分片(无中心化)服务端代理(中心化)
性能更高(无网络跳转)有网络开销
部署应用集成,无需额外部署需独立中间件服务器
语言支持Java 生态多语言(MySQL 协议兼容)
功能专注分库分表支持读写分离、分库分表等
运维成本需维护中间件集群

7.2 选择 Sharding-JDBC 的原因

  1. 性能优势:减少网络跳转,降低延迟

  2. 架构轻量:无单点故障,符合云原生趋势

  3. 灵活集成:与 Spring 生态无缝整合

  4. 扩展性强:易于定制分片策略

  5. 社区活跃:Apache 顶级项目,持续更新

八、分库分表规则设计实践

8.1 分片键选择原则

  1. 高基数:字段值分布均匀(如 user_id)

  2. 业务相关性:常作为查询条件的字段

  3. 低修改频率:避免分片键频繁更新

  4. 业务增长模式

    • 用户维度:按 user_id 分片

    • 时间维度:按 create_time 分片

8.2 常用分片策略

  1. 哈希分片

    tableStrategy:
      standard:
        shardingColumn: user_id
        preciseAlgorithmClassName: HashModShardingAlgorithm
  2. 范围分片

    // 范围分片算法实现
    public Collection<String> doSharding(RangeShardingValue<Long> shardingValue) {
        Long lower = shardingValue.getValueRange().lowerEndpoint();
        Long upper = shardingValue.getValueRange().upperEndpoint();
        // 计算包含的分片范围
    }
  3. 复合分片

    complex:
      shardingColumns: user_id,order_id
      algorithmClassName: CompositeShardingAlgorithm
    
    

8.3 分片策略配置示例

sharding:
  tables:
    t_order:
      actualDataNodes: ds${0..1}.t_order${0..15}
      databaseStrategy:
        standard:
          shardingColumn: user_id
          preciseAlgorithmClassName: HashDatabaseShardingAlgorithm
      tableStrategy:
        standard:
          shardingColumn: order_id
          preciseAlgorithmClassName: HashTableShardingAlgorithm

九、面试常见问题深度解析

9.1 如何解决跨分片分页问题?

  1. 业务优化

    • 使用连续分页(基于上次最大ID)

    SELECT * FROM orders 
    WHERE id > ? 
    ORDER BY id LIMIT 10
  2. 内存归并

    • 设置最大归并行数限制

    props:
      max.connections.size.per.query: 5
      max.rows: 100000

9.2 如何实现全局唯一ID?

  1. Snowflake 算法

    public class SnowflakeIdGenerator implements KeyGenerator {
        public Comparable<?> generateKey() {
            return Snowflake.generateId();
        }
    }
  2. 数据库分段分配

    • 使用单独的 ID 分配服务

9.3 如何保证数据一致性?

  1. 分布式事务

    • 集成 Seata 的 AT 模式

    • 使用 XA 事务

  2. 最终一致性

    • 基于消息队列的补偿机制

    • 对账系统定时校验

十、最佳实践总结

  1. 分片设计原则

    • 单分片不超过 5000 万行

    • 预留 30% 容量用于扩容

  2. 性能优化

    props:
      sql.show: true # 开启SQL日志
      executor.size: 20 # 并发执行线程数
  3. 监控指标

    • 分片查询延迟

    • 归并结果集大小

    • 分布式事务成功率

  4. 灾备方案

    • 同城双活部署

    • 分片级数据备份 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值