常见生成唯一资源ID的方式
字数 1509 2025-08-22 12:23:36
唯一资源ID生成方式详解
一、唯一ID的特征要求
在业务开发中,唯一ID需要满足以下关键特征:
- 唯一性:生成的ID全局唯一,在特定范围内冲突概率极小
- 可用性:可保证高并发下的可用性
- 安全性:对生成的ID不能进行预测,不会暴露系统和业务的信息
二、常见生成方式对比
| 方案 | 唯一性 | 有序性 | 可用性 | 安全性 |
|---|---|---|---|---|
| 雪花算法 | 较强唯一性 | 大致有序 | 高可用 | 可部分预测 |
| UUID | 强唯一性 | 无序 | 高可用 | 不可预测 |
| 数据库自增ID | 强唯一性 | 有序 | 较高可用 | 可预测 |
| 哈希算法 | 较强唯一性 | 无序 | 较高可用 | 取决于算法 |
三、雪花算法详解
1. 算法组成
雪花算法生成的ID由以下几部分组成:
- 符号位:始终为0,表示正数
- 时间戳:占用41位,表示从固定时间点(如2010年1月1日)开始的时间差
- 机器标识:包括数据中心ID(5位)和机器ID(5位),用于区分不同服务器节点
- 序列号:占用12位,用于同一毫秒内生成的不同ID
2. 安全性分析
理论上可以预测,但实际操作困难:
- 时间戳采用毫秒级精度
- 假设5台机器,每毫秒生成1个ID,则每小时可生成1800万个ID(60601000*5)
- 爆破方式获取信息成本高,容易被发现
3. Python实现示例
import time
import threading
class SnowflakeGenerator:
def __init__(self, datacenter_id, worker_id):
self.datacenter_id = datacenter_id
self.worker_id = worker_id
self.sequence = 0
self.last_timestamp = -1
# Bit lengths
self.datacenter_id_bits = 5
self.worker_id_bits = 5
self.sequence_bits = 12
# Maximum values
self.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits)
self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)
self.max_sequence = -1 ^ (-1 << self.sequence_bits)
# Shift amounts
self.worker_id_shift = self.sequence_bits
self.datacenter_id_shift = self.sequence_bits + self.worker_id_bits
self.timestamp_shift = self.sequence_bits + self.worker_id_bits + self.datacenter_id_bits
self.lock = threading.Lock()
def _current_milliseconds(self):
return int(time.time() * 1000)
def _til_next_millis(self, last_timestamp):
timestamp = self._current_milliseconds()
while timestamp <= last_timestamp:
timestamp = self._current_milliseconds()
return timestamp
def generate_id(self):
with self.lock:
timestamp = self._current_milliseconds()
if timestamp < self.last_timestamp:
raise ValueError("Clock moved backwards. Refusing to generate id.")
if timestamp == self.last_timestamp:
self.sequence = (self.sequence + 1) & self.max_sequence
if self.sequence == 0:
timestamp = self._til_next_millis(self.last_timestamp)
else:
self.sequence = 0
self.last_timestamp = timestamp
return ((timestamp - 1288834974657) << self.timestamp_shift) | \
(self.datacenter_id << self.datacenter_id_shift) | \
(self.worker_id << self.worker_id_shift) | \
self.sequence
def generate_unique_id(prefix: str, datacenter_id: int, worker_id: int) -> str:
generator = SnowflakeGenerator(datacenter_id, worker_id)
snowflake_id = generator.generate_id()
return f"{prefix}{snowflake_id}"
# 使用示例
datacenter_id = 0
worker_id = 1
user_id = generate_unique_id("USER_", datacenter_id, worker_id)
print(f"生成的用户ID: {user_id}")
四、数据库自增ID
1. 基本特性
优点:
- 使用简单,满足基本需求
- 天然有序
缺点:
- 并发性不好
- 数据库写压力大
- 数据库故障后不可使用
- 存在数量泄露风险
2. 优化方案
方案一:数据库水平拆分
- 设置不同的初始值和相同的步长
- 保证每台数据库生成的ID不冲突
- 扩容问题:
- 根据扩容考虑决定步长
- 增加其他位标记区分扩容
方案二:批量生成ID
- 每次批量生成一批ID给不同机器消费
- 减小数据库压力到N分之一
- 缺点:服务器重启、单点故障会造成ID不连续
五、UUID
1. 基本格式
标准形式为32个十六进制数组成的字符串,分隔为五个部分:
467e8542-2275-4163-95d6-7adc205580a9
实际使用中常去掉分隔符:
467e85422275416395d67adc205580a9
2. 特性
- 唯一性:基于随机数和时间戳组合,生成全局唯一的ID
- 无序性:随机生成,不具有时间排序性
- 性能:生成速度快,适合高并发环境
- 安全性:完全无序,不可猜测,可防止水平越权攻击
六、哈希算法
1. 基本原理
- 将任意长度输入转化为固定长度哈希值
- 相同输入始终生成相同哈希值
- 单向性:无法从哈希值还原原始数据
2. 唯一性考虑
- 哈希冲突:不同输入可能生成相同哈希值
- 解决方案:
- 添加随机性减少冲突概率
- 使用唯一性索引验证ID是否已存在
3. 常见应用场景
- 密码学
- 数据完整性验证
- 数据检索
- 数字签名
- 哈希表等数据结构
- 信息安全领域
七、安全测试注意事项
在测试权限问题时,需充分了解资源ID的生成方式:
- 可预测性分析:判断ID是否可被猜测
- 越权测试:针对不同生成方式采取不同测试策略
- 有序ID(如自增ID)较易进行越权测试
- 无序ID(如UUID)较难进行越权测试
- 成本效益评估:爆破方式需考虑成本与收益比
八、方案选择建议
- 高并发+安全性:优先考虑UUID
- 需要有序性:考虑雪花算法
- 简单业务场景:可使用数据库自增ID(配合优化方案)
- 数据指纹需求:考虑哈希算法
没有绝对最好的方案,应根据具体业务需求选择最适合的ID生成方式。