分片键选择
分片键(Sharding Key)的选择直接决定了分片策略的效果。一个优秀的分片键需要满足以下特性:
1. 数据分布均匀性
• 基数要足够大,避免数据倾斜
• 增长趋势可预测,便于容量规划
• 避免热点,如使用时间戳作为分片键时要注意追加写入问题
2. 查询模式适配性
• 与业务最频繁的查询模式匹配
• 支持就近路由,提升查询效率
• 考虑批量操作场景的性能影响
实践要点:
-- 不推荐:使用自增ID作为分片键
CREATE TABLE orders (
id BIGINT PRIMARY KEY, -- 易造成写入热点
user_id BIGINT,
order_time TIMESTAMP
);
-- 推荐:使用user_id作为分片键
CREATE TABLE orders (
id BIGINT,
user_id BIGINT, -- 分片键
order_time TIMESTAMP,
PRIMARY KEY (user_id, id)
);
典型业务场景分析
案例1:电商订单分片
- 场景:大型电商平台日订单量千万级
- 挑战:历史订单查询与实时订单写入并存
- 解决方案:采用用户ID+时间范围的复合分片策略
订单表分片设计:
CREATE TABLE orders_${user_id % 256}_${yyyyMM} (
id BIGINT,
user_id BIGINT,
order_time TIMESTAMP,
status VARCHAR(32),
PRIMARY KEY (user_id, id)
) PARTITION BY RANGE (order_time);
跨分片事务
跨分片事务是分片系统的技术难点,需要在一致性和性能之间做出权衡。
1. 分布式事务协调
• 实现两阶段提交(2PC)协议
• 使用三阶段提交(3PC)提高可用性
• 采用SAGA模式处理长事务
2. 数据一致性保证
@Transactional
public void transferMoney(long userId1, long userId2, BigDecimal amount) {
// 重要:先对分片键排序,避免死锁
long firstId = Math.min(userId1, userId2);
long secondId = Math.max(userId1, userId2);
Account account1 = accountDao.lockAccount(firstId);
Account account2 = accountDao.lockAccount(secondId);
// 执行转账逻辑
account1.deduct(amount);
account2.add(amount);
}
注意事项:
• 避免大规模跨分片事务:可能导致性能急剧下降
• 合理设计分片策略:将相关联的数据放在同一分片
• 使用补偿机制:处理分布式事务失败场景
性能基准与监控
• 吞吐量基准:单分片写入QPS > 5000
• 跨分片查询延迟:P99 < 200ms
• 关键监控指标:
a.分片数据分布偏差率 < 15%
b.跨分片事务比例 < 5%
c.单分片存储容量利用率 < 75%
分片扩容方案
1. 在线扩容流程
准备新节点预热数据调整路由表数据同步切换流量清理旧数据
2. 数据迁移策略
• 双写方案:新写入同时写入新旧节点
• 快照+增量:先迁移基础数据,再同步增量
• 虚拟节点:使用一致性哈希实现平滑扩容
核心代码示例:
public class ConsistentHash<T> {
private final int numberOfReplicas; // 虚拟节点数
private final SortedMap<Integer, T> circle = new TreeMap<>();
public void addNode(T node) {
for (int i = 0; i < numberOfReplicas; i++) {
circle.put(hash(node.toString() + i), node);
}
}
public T getNode(Object key) {
if (circle.isEmpty()) {
return null;
}
int hash = hash(key);
if (!circle.containsKey(hash)) {
SortedMap<Integer, T> tailMap = circle.tailMap(hash);
hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
}
return circle.get(hash);
}
}
故障诊断与处理
数据倾斜
性能下降
节点故障
发现分片异常判断类型重平衡策略分析慢查询故障转移执行修复
常见故障处理流程:
1. 数据倾斜
• 触发条件:单分片负载超过平均值150%
• 处理方案:动态分片+数据重平衡
• 预防措施:实时监控分片数据分布
2. 热点分片
• 问题表现:特定分片QPS突增
• 解决方案:引入二级分片+本地缓存
• 代码示例:
@Cacheable(key = "#userId", condition = "#userId % 256 == hotShardId")
public UserOrder getOrder(long userId) {
// 热点分片走二级缓存
if (isHotShard(userId)) {
return localCache.get(userId);
}
return orderMapper.getOrder(userId);
}
架构扩展性设计
1. 多维度分片支持
public interface ShardingStrategy {
String getShardingKey(Object params);
// 支持自定义分片算法
int calculateShard(String shardingKey);
// 支持分片规则动态变更
void updateShardingRule(ShardingRule rule);
}
2. 分片管理面板
• 分片健康度可视化
• 自动化运维能力
• 分片扩缩容向导
技术选型参考
场景 | 推荐方案 | 特点 |
单元化部署 | ShardingSphere | 异构数据源整合能力强 |
海量数据 | TiDB | 强一致性,自动分片 |
全球化部署 | CockroachDB | 跨区域一致性好 |