这是 Beta 探索课程,内容结构、实验步骤和示例可能会继续调整。
有序性
有序性是分布式 ID 的重要特性之一。不同的有序性级别对系统性能和业务逻辑都有重要影响。
有序性的级别
1. 严格递增(Strictly Increasing)
定义:每个新生成的 ID 都严格大于前一个 ID。
示例:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10特点:
- ✅ 最理想的有序性
- ✅ 便于范围查询
- ❌ 需要全局协调
- ❌ 性能开销大
实现方式:
- 单机计数器
- 全局分布式锁
- 中心化 ID 服务
2. 趋势递增(Monotonically Increasing)
定义:ID 大致按时间递增,允许短暂的无序。
示例:
1001, 1002, 1003, 1005, 1004, 1006, 1007
← 短暂无序特点:
- ✅ 满足大部分业务需求
- ✅ 性能较好
- ✅ 实现相对简单
- ❌ 非严格有序
实现方式:
- 雪花算法
- 号段模式
- 基于时间戳的方案
3. 大致有序(Roughly Ordered)
定义:ID 按时间大致排序,但允许较大的无序范围。
示例:
20240410001, 20240410005, 20240410003, 20240410008
范围内无序特点:
- ✅ 实现简单
- ✅ 性能好
- ❌ 无序范围可能较大
- ❌ 对范围查询不友好
实现方式:
- 带时间戳的随机 ID
- 各节点独立生成
4. 无序(Unordered)
定义:ID 完全随机,没有任何顺序。
示例:
f47ac10b-58cc-4372-a567-0e02b2c3d479
550e8400-e29b-41d4-a716-446655440000
6ba7b810-9dad-11d1-80b4-00c04fd430c8特点:
- ✅ 实现最简单
- ✅ 性能最好
- ✅ 分布式友好
- ❌ 完全无序
- ❌ 对索引不友好
实现方式:
- UUID v4
- 完全随机的 ID
为什么需要有序性
1. 数据库索引性能
B+ 树索引:
MySQL InnoDB 使用 B+ 树索引
有序 ID 有利于:
- 减少页分裂
- 减少页合并
- 提高缓存命中率
- 降低磁盘 I/O性能对比:
有序 ID:
- 插入性能:50000 TPS
- 页分裂次数:少
- 缓存命中率:高
无序 ID:
- 插入性能:10000 TPS
- 页分裂次数:多
- 缓存命中率:低2. 范围查询效率
查询场景:
数据设计要点
- 查询目标是快速定位状态、任务或资源,避免在关键路径上做大范围扫描。
有序性优势:
- ✅ 可以利用索引
- ✅ 可以使用 ORDER BY
- ✅ 可以使用 LIMIT
- ✅ 可以做分页查询
3. 分页查询友好
分页场景:
数据设计要点
- 查询目标是快速定位状态、任务或资源,避免在关键路径上做大范围扫描。
有序性优势:
- ✅ 排序速度快
- ✅ OFFSET 性能好
- ✅ 分页稳定
4. 数据恢复和回溯
恢复场景:
系统故障后需要恢复数据:
1. 按订单 ID 范围恢复
2. 按时间戳范围恢复
3. 有序 ID 便于定位5. 数据分析和统计
分析场景:
数据设计要点
- 查询目标是快速定位状态、任务或资源,避免在关键路径上做大范围扫描。
- 关键字段包括
SELECT,它们决定后续查询和管理能力。
无序性的应用场景
虽然有序性很有用,但有些场景更适合无序 ID:
1. 安全性要求
场景:不希望泄露业务信息
✅ 随机 ID:用户无法推测用户量
❌ 递增 ID:用户ID = 10000001,泄露用户量2. 防止遍历攻击
场景:防止恶意遍历所有用户
✅ 随机 ID:无法枚举
❌ 递增 ID:可以从 1 遍历到 N3. 分布式友好
场景:多节点独立生成,无需协调
✅ 随机 ID:各节点独立生成
❌ 递增 ID:需要协调保证递增有序性 vs 性能的权衡
权衡表格
| 有序性级别 | 性能 | 实现复杂度 | 适用场景 |
|---|---|---|---|
| 严格递增 | ⭐⭐ | ⭐⭐⭐⭐⭐ | 小规模系统 |
| 趋势递增 | ⭐⭐⭐⭐ | ⭐⭐⭐ | 大部分场景 |
| 大致有序 | ⭐⭐⭐⭐⭐ | ⭐⭐ | 日志系统 |
| 无序 | ⭐⭐⭐⭐⭐ | ⭐ | 消息系统 |
推荐选择
严格递增:
- 订单号(需要可读)
- 单据号(需要连续)
- 小规模系统
趋势递增:
- 用户 ID
- 商品 ID
- 评论 ID
- 大部分业务 ID
大致有序:
- 日志 ID
- 消息 ID
- 追踪 ID
无序:
- Token
- 会话 ID
- 临时 ID
有序性实现技巧
1. 时间戳作为前缀
实现:
ID = timestamp(毫秒) + 序列号
示例:
20240410123456789
↑ ↑
时间戳 序列号优点:
- ✅ 天然有序
- ✅ 包含时间信息
- ✅ 实现简单
2. 雪花算法
实现:
ID = 时间戳(41位) + 节点ID(10位) + 序列号(12位)
特点:
- 同一毫秒内递增
- 跨毫秒也趋势递增
- 分布式友好3. 号段模式
实现:
从数据库获取号段:[1000, 2000]
本地递增使用:1001, 1002, 1003, ...
特点:
- 号段内严格递增
- 跨号段大致有序
- 性能高常见错误
错误1:过度追求严格递增
❌ 错误做法:
为了严格递增,使用全局锁,牺牲性能
✅ 正确做法:
追求趋势递增,满足大部分需求错误2:忽视有序性对性能的影响
❌ 错误做法:
使用 UUID,无序 ID 导致数据库性能差
✅ 正确做法:
使用趋势递增 ID,优化数据库性能错误3:混用不同有序性的 ID
❌ 错误做法:
同一个表混用严格递增和无序 ID
✅ 正确做法:
保持一致的有序性级别有序性检查清单
在实现分布式 ID 生成器时,确保:
- 明确有序性需求级别
- 理解有序性对数据库性能的影响
- 权衡有序性和性能
- 选择合适的有序性级别
- 验证 ID 的有序性
- 考虑分布式环境下的有序性
- 处理时钟回拨对有序性的影响
- 测试大规模数据下的性能
下一步
了解了有序性后,我们继续学习 ID 的性能要求。
👉 下一节:性能要求