完整架构

基于前面的学习,让我们设计一个生产级的分布式 ID 系统完整架构。

架构设计

1. 整体架构

                    ┌─────────────────┐
                    │   负载均衡器     │
                    │  (Nginx / SLB)  │
                    └────────┬────────┘
                             │
         ┌───────────────────┼───────────────────┐
         │                   │                   │
    ┌────▼────┐         ┌────▼────┐         ┌────▼────┐
    │ 节点 A  │         │ 节点 B  │         │ 节点 C  │
    │号段模式 │         │号段模式 │         │号段模式 │
    └────┬────┘         └────┬────┘         └────┬────┘
         │                   │                   │
         └───────────────────┼───────────────────┘
                             │
         ┌───────────────────┼───────────────────┐
         │                   │                   │
    ┌────▼────┐         ┌────▼────┐         ┌────▼────┐
    │ DB 主库 │         │ DB 从库 │         │ Redis   │
    └─────────┘         └─────────┘         └─────────┘

2. 分层设计

接入层:

功能:
- 负载均衡
- 流量控制
- 服务发现
- 健康检查

服务层:

功能:
- ID 生成逻辑
- 号段管理
- 双 Buffer
- 降级策略

数据层:

功能:
- 数据库存储
- Redis 缓存
- 数据持久化

核心组件

1. 号段服务

职责:

  • 管理号段分配
  • 维护双 Buffer
  • 处理数据库交互

实现:


2. 双 Buffer

职责:

  • 维护两个号段 Buffer
  • 自动切换
  • 预加载

实现:


3. 降级服务

职责:

  • 主方案失败时降级
  • 提供多级降级
  • 监控降级状态

实现:


高可用设计

1. 多机房部署

北京机房:
├── 节点 A1、A2、A3
├── DB 主库
└── Redis Cluster

上海机房:
├── 节点 B1、B2、B3
├── DB 从库
└── Redis Cluster

深圳机房:
├── 节点 C1、C2、C3
├── DB 从库
└── Redis Cluster

2. 故障转移

流程:

1. 健康检查发现故障
2. 流量切换到健康节点
3. 故障节点自动重启
4. 重新加入集群

监控告警

1. 监控指标

QPS:每秒生成的 ID 数量
延迟:P50, P99, P999
错误率:生成 ID 失败的比例
可用性:服务可用时间比例
资源使用:CPU、内存、网络
号段使用率:Buffer 使用情况

2. 告警规则

QPS < 阈值 → P3 告警
延迟 P99 > 阈值 → P2 告警
错误率 > 阈值 → P1 告警
可用性 < 阈值 → P0 告警

性能优化

1. 本地缓存

服务层拿到一批号段之后,先缓存在本地内存里再逐个发放。业务线程只和内存打交道,号段不够了才去数据库取下一段。

业务线程 → 本地内存(原子自增)→ 发放 ID
                │ 剩余量见底
                ↓
           向号段服务申请下一段

本地缓存里要放三样东西:号段的左右端点、当前待发位置、续期阈值。缺一样就会出现「发空」或者「重复发号」。

观测指标含义处置建议
缓存剩余量当前号段还剩多少长期低于 10% 说明步长偏小或流量超出预期
续期耗时从发现不足到新号段就绪明显变长说明数据库压力上来了
续期失败次数后台预取失败的次数不为 0 就必须告警,它不会体现在业务错误率上

一个号段用完之后,下一段要提前取回来(这就是双 Buffer),否则切换时的等待会变成一次实实在在的接口卡顿。


2. 批量生成

批量生成是接口层的批量能力:一次请求要 100 个 ID 时,不该发 100 次请求,也不该查 100 次数据库。

一次请求 100 个 ID:
- 逐个生成:100 次业务调用 + 100 次号段服务调用
- 批量生成:1 次业务调用 + 1 次号段服务调用

实现:

/**
 * 批量取 ID 的接口实现。
 */
@RestController
@RequestMapping("/api/id")
public class IdController {

    private final SegmentIdGenerator idGenerator;

    public IdController(SegmentIdGenerator idGenerator) {
        this.idGenerator = idGenerator;
    }

    /**
     * 批量获取 ID。
     *
     * count 限制在 1 到 1000 之间,防止单个请求把整个号段领空。
     */
    @GetMapping("/batch")
    public List<Long> batchIds(@RequestParam(defaultValue = "1") int count) {
        if (count < 1 || count > 1000) {
            throw new IllegalArgumentException("count 必须在 1 到 1000 之间");
        }

        List<Long> ids = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            ids.add(idGenerator.nextId());
        }
        return ids;
    }
}

批量生成有三条纪律:

  • 批量大小要有上限。1000 是常见取值,再大就相当于让一个请求领走整个号段,一旦这个请求重试,浪费的号段会非常大。
  • 批量接口要限流。批量取号天然是「一次调用消耗多个 ID」,不做限流等于给了一个放大器。
  • 批量接口要能被降级。号段服务不可用时可以降级成雪花算法或者 UUID,但要接受有序性下降的代价。

部署方案

1. Docker 部署

部署要点

  • 镜像只负责提供稳定运行环境,业务可靠性仍然取决于状态、监控和回滚策略。

2. Kubernetes 部署

配置要点

  • 配置表达的是环境差异和运行参数,不是业务规则本身。

最佳实践

1. 选择合适方案

小型系统:Redis 自增
中型系统:雪花算法
大型系统:号段模式
超大系统:号段模式 + 双 Buffer

2. 多级降级

主方案:号段模式
降级方案1:雪花算法
降级方案2:UUID
降级方案3:时间戳 + 随机数

3. 完善监控

实时监控
告警机制
日志追踪
性能分析

总结

完整架构特点

特性说明
唯一性数据库保证
有序性严格递增
性能> 10,000,000 QPS
可用性99.99%
扩展性水平扩展
降级多级降级

课程总结

恭喜你完成了《系统设计 - 分布式 ID 生成器》课程!

你学到了: ✅ 分布式 ID 的多种方案 ✅ 各方案的优缺点和适用场景 ✅ 生产级系统的设计原则 ✅ 完整的系统架构

下一步

建议继续学习:

  • 系统设计其他主题
  • 分布式系统设计
  • 微服务架构
  • 高可用系统设计

感谢学习!🎉

发现内容有问题?

告诉我们哪里需要改进。