
分布式ID生成服务设计
分布式ID生成服务需要满足高可用、高性能、全局唯一、趋势递增等特性。以下是基于Java和MySQL的实现方案,支持横向扩展。
数据库设计
使用MySQL的InnoDB表存储ID段分配信息,避免单点故障。表结构如下:
CREATE TABLE `id_generator` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`biz_tag` varchar(64) NOT NULL COMMENT '业务标识',
`max_id` bigint(20) NOT NULL COMMENT '当前最大ID',
`step` int(11) NOT NULL COMMENT '号段步长',
`version` bigint(20) NOT NULL COMMENT '乐观锁版本号',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_biz_tag` (`biz_tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
号段模式实现
采用号段分配方式降低数据库压力。每个业务标识获取一个ID段,缓存到本地内存中。
public class SegmentIdGenerator {
private volatile Segment currentSegment;
private volatile Segment nextSegment;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
public synchronized Long getNextId(String bizTag) {
if (currentSegment == null || !currentSegment.hasRemaining()) {
if (nextSegment != null && nextSegment.hasRemaining()) {
currentSegment = nextSegment;
nextSegment = null;
} else {
currentSegment = loadSegmentFromDb(bizTag);
}
preloadNextSegment(bizTag);
}
return currentSegment.getNextId();
}
private void preloadNextSegment(String bizTag) {
executor.execute(() -> {
if (nextSegment == null || !nextSegment.hasRemaining()) {
nextSegment = loadSegmentFromDb(bizTag);
}
});
}
private Segment loadSegmentFromDb(String bizTag) {
// 数据库操作获取新号段
}
}
数据库更新策略
使用乐观锁保证并发安全,避免ID重复:
public boolean updateMaxId(String bizTag, long newMaxId, long oldVersion) {
String sql = "UPDATE id_generator SET max_id=max_id+step, version=version+1 "
+ "WHERE biz_tag=? AND version=?";
try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, bizTag);
stmt.setLong(2, oldVersion);
return stmt.executeUpdate() > 0;
}
}
服务层设计
构建Spring Boot服务提供RESTful API:
@RestController
@RequestMapping("/api/id")
public class IdController {
@GetMapping("/next")
public Response<Long> nextId(@RequestParam String bizTag) {
Long id = idGenerator.getNextId(bizTag);
return Response.success(id);
}
}
横向扩展方案
采用多实例部署时,可通过以下方式保证扩展性:
每个实例初始化时注册到Zookeeper或Redis,获取唯一实例标识 将实例标识作为ID高位部分,结合数据库生成的ID低位部分 例如:64位ID = 16位实例标识 + 48位数据库生成ID
public class DistributedIdGenerator {
private final int instanceIdBits = 16;
private final long instanceId;
public DistributedIdGenerator() {
this.instanceId = registerInstanceAndGetId();
}
public long generateId() {
long sequenceId = segmentIdGenerator.getNextId();
return (instanceId << (64 - instanceIdBits)) | sequenceId;
}
}
性能优化措施
适当增大号段步长,减少数据库访问频率 使用双缓冲机制预加载下一个号段 添加本地缓存应对突发流量 监控号段消耗速度,动态调整步长
public class DynamicStepAdjuster {
public int calculateNewStep(int currentStep, long usedTime) {
// 根据历史消耗时间动态计算新步长
return Math.min(currentStep * 2, MAX_STEP);
}
}
容灾方案
数据库主从部署,故障时自动切换 添加本地文件备份,数据库不可用时降级处理 定期检查ID使用情况,避免号段浪费 实现监控报警机制,及时发现异常
监控指标
实现以下监控项保证服务健康: ID生成速率 号段消耗时间 数据库更新成功率 服务响应时间 实例负载情况
这种设计结合了数据库的可靠性和内存的高性能,通过号段分配和实例标识支持横向扩展,适合中等规模分布式系统。对于超大规模系统,可考虑雪花算法等完全分布式方案。

被折叠的 条评论
为什么被折叠?



