Skip to content

十三、ShardingSphere(4 题)

13.1 ★★★★ShardingSphere 的核心组件有哪些?ShardingSphere-JDBC、ShardingSphere-Proxy、ShardingSphere-Sidecar 的区别和适用场景是什么?分片原理是什么?

📖 点击查看答案

核心组件

  • Sharding-JDBC:轻量级 Java 框架,增强版 JDBC 驱动,直连数据库
  • Sharding-Proxy:独立部署的数据库代理,屏蔽分库分表
  • Sharding-Sidecar:基于 Service Mesh 的sidecar 方案
  • 核心功能模块:分库分表、读写分离、数据加密、影子库、分布式事务、弹性伸缩

三种形态对比

维度Sharding-JDBCSharding-ProxySharding-Sidecar
部署方式嵌入应用独立部署与应用同 Pod
语言支持仅 Java多语言多语言
性能损耗低(直连)较高(多一跳)
运维复杂度
适用场景Java 单体/微服务异构语言、DBA 运维K8s 云原生

分片原理

  1. SQL 解析:词法解析 → 语法解析 → 生成抽象语法树(AST)
  2. SQL 路由:根据分片键和分片算法,定位目标库表(分片路由、广播路由、单播路由)
  3. SQL 改写:将逻辑 SQL 改写为真实库表 SQL(如 t_ordert_order_0
  4. SQL 执行:并行执行多库 SQL,通过 ExecutorEngine 线程池
  5. 结果归并:合并多库结果集(流式归并、内存归并、装饰者归并)
java
// Sharding-JDBC 配置示例
@Bean
public DataSource dataSource() throws SQLException {
    return ShardingSphereDataSourceFactory.createDataSource(
        createDataSourceMap(),
        "md",  // 模式
        createShardingRuleConfiguration(),
        new Properties()
    );
}

private ShardingRuleConfiguration createShardingRuleConfiguration() {
    ShardingRuleConfiguration config = new ShardingRuleConfiguration();
    config.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
    // 分库策略:按 user_id 取模
    config.setDefaultDatabaseShardingStrategy(
        new StandardShardingStrategyConfiguration("user_id", new ModShardingAlgorithm()));
    // 分表策略:按 order_id 取模
    config.setDefaultTableShardingStrategy(
        new StandardShardingStrategyConfiguration("order_id", new ModShardingAlgorithm()));
    return config;
}

13.2 ★★★★ShardingSphere 的分片策略和分片算法有哪些?如何配置分片规则?分片键如何选择以避免数据倾斜?

📖 点击查看答案

分片策略

  • 标准分片策略(Standard):支持 =INBETWEEN,需配置 PreciseShardingAlgorithm 和可选 RangeShardingAlgorithm
  • 复合分片策略(Complex):多分片键,实现 ComplexKeysShardingAlgorithm
  • 行表达式分片策略(Inline):使用 Groovy 表达式,如 ds${id % 2}
  • Hint 分片策略(Hint):基于程序 hints 路由,非 SQL 解析
  • 不分片策略(None):不进行分片

分片算法

  • 精确分片算法(PreciseShardingAlgorithm):处理 =IN
  • 范围分片算法(RangeShardingAlgorithm):处理 BETWEEN><
  • 复合分片算法(ComplexKeysShardingAlgorithm):多分片键
  • Hint 分片算法(HintShardingAlgorithm):编程式路由
java
// 自定义精确分片算法
public class ModShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    @Override
    public String doSharding(Collection<String> availableTargetNames,
                             PreciseShardingValue<Long> shardingValue) {
        for (String target : availableTargetNames) {
            if (target.endsWith(String.valueOf(shardingValue.getValue() % availableTargetNames.size()))) {
                return target;
            }
        }
        throw new UnsupportedOperationException("no target found");
    }
}

// 行表达式配置(YAML)
// actualDataNodes: ds${0..1}.t_order_${0..3}
// databaseStrategy:
//   inline:
//     shardingColumn: user_id
//     algorithmExpression: ds${user_id % 2}
// tableStrategy:
//   inline:
//     shardingColumn: order_id
//     algorithmExpression: t_order_${order_id % 4}

分片键选择避免数据倾斜的要点

  1. 高基数:分片键取值范围要足够大,避免某分片数据过多
  2. 均匀分布:分片键值分布均匀,避免热点(如按用户ID取模,而非按状态字段)
  3. 避免单调递增:自增ID作为分片键会导致写入热点(如时间戳),可用 Snowflake 或哈希打散
  4. 高频查询字段:选择查询条件中高频出现的字段,避免全路由扫描
  5. 避免热点值:某些用户ID特别活跃(如大V),可加随机后缀或一致性哈希
  6. 范围查询友好:若需要范围查询,考虑按范围分片或复合分片
  7. 数据量评估:根据单表容量(建议 1000 万内)和数据增长预估分片数

13.3 ★★★★ShardingSphere 如何处理分布式事务?它支持哪些分布式事务类型(XA 强一致、BASE 柔性事务)?

📖 点击查看答案

事务类型

类型一致性性能实现适用场景
LOCAL 本地事务最高不保证跨库一致跨库少的非核心业务
XA 两阶段提交强一致Atomikos/Narayana/Narayana数据强一致、并发不高
BASE 柔性事务最终一致Seata AT/TCC、Saga高并发业务

XA 事务流程

  1. 应用发起事务,ShardingSphere 创建 XATransactionManager
  2. SQL 执行时,各分片资源被 XAResource 包装
  3. 一阶段:各分片执行 SQL 并 prepare
  4. 二阶段:所有 prepare 成功则 commit,否则 rollback
  5. 需配合 XA 事务管理器(Atomikos、Narayana)

BASE 事务(Seata AT)

  1. 一阶段:拦截 SQL,生成 before/after image 存入 undo_log,本地事务提交
  2. 二阶段提交:异步删除 undo_log
  3. 二阶段回滚:根据 undo_log 反向生成补偿 SQL
java
// XA 事务配置
@Bean
public PlatformTransactionManager txManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

// 开启 XA 事务(注解方式,配合 ShardingSphere 的 XA 模式)
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
    // 跨库操作,ShardingSphere 自动协调 XA
    accountMapper.debit(fromId, amount);   // ds0
    accountMapper.credit(toId, amount);    // ds1
}

// YAML 配置
// transaction:
//   defaultType: XA
//   providerType: Atomikos

// BASE 事务配置(Seata)
// transaction:
//   defaultType: BASE
//   providerType: Seata

XA 缺陷

  • 同步阻塞,性能差
  • 单点故障(协调者)
  • 数据不一致风险(网络分区时部分 commit)

BASE 优势

  • 一阶段即释放资源,性能高
  • 最终一致性适合互联网高并发场景
  • 但存在脏读、不可重复读问题(需配合读隔离)

13.4 ★★★分库分表后的常见问题有哪些?如何解决跨库 JOIN、跨库分页、跨库排序、跨库聚合(归并排序、流式处理)?

📖 点击查看答案

分库分表常见问题

  1. 跨库 JOIN 困难
  2. 跨库分页性能差
  3. 跨库排序、聚合需要归并
  4. 分布式事务
  5. 全局唯一 ID 生成
  6. 数据迁移与扩容
  7. 跨库事务一致性

跨库 JOIN 解决方案

  • 绑定表:关联表按相同分片键分到同库,避免跨库 JOIN
  • 广播表:小表(如字典表)每个库都存一份
  • 应用层 JOIN:分别查询后在内存关联
  • 冗余字段:反范式,冗余关联字段
  • Elasticsearch/数据同步:通过 Canal 同步到 ES 做联合查询

跨库分页问题

  • LIMIT 1000000, 10 需各库都取 1000010 条归并,性能极差
  • 解决:禁止深分页、使用游标分页(WHERE id > last_id)、二次查询法、ES 辅助

跨库排序与归并

java
// ShardingSphere 归并策略
// 1. 流式归并(Stream Merge):各分片结果已排序,多路归并
//    - 适用于 ORDER BY + LIMIT,每次只取一条比较
// 2. 内存归并(Memory Merge):所有结果加载到内存排序
//    - 适用于 GROUP BY、无索引排序
// 3. 装饰者归并:在流式归并基础上做聚合(MAX/MIN/SUM/COUNT/AVG)

// 跨库聚合示例:SELECT COUNT(*), SUM(amount) FROM t_order
// 各库返回 count_i, sum_i
// 最终 count = sum(count_i), sum = sum(sum_i)
// AVG 需特殊处理:avg = sum(sum_i) / sum(count_i),不能直接求平均

// 跨库分页优化:二次查询法
// 第一查询:各库 LIMIT 0, 10 取出最小值
// 第二查询:根据最小值各库查询 LIMIT min_value, 10
// 合并后取最终结果,减少数据传输

分页性能优化要点

  1. 避免深分页(超过 1000 页限制)
  2. 使用游标分页(基于有序主键)
  3. 借助搜索引擎(ES)做分页
  4. 预计算热门分页结果
  5. 使用 ShardingSphere 的流式归并降低内存

基于 4 份主流面试题库整合精选,共 200 题