# sfid 设计文档
基于 Redis 自动分配机器号的雪花 ID 生成器。
## 架构
```
┌─────────────────────────────────────────────────────────────┐
│ sfid │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Snowflake │───▶│ machine_id │───▶│ MACHINE_ID │ │
│ │ Generator │ │ () │ │ (xboot::auto)│ │
│ └─────────────┘ └─────────────┘ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Redis HEXPIRE │ │
│ │ (机器号分配) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## 雪花 ID 结构 (64 bits)
```
┌───────┬──────────────────────────┬────────────┬──────────────┐
│ 1 bit │ 41 bits │ 10 bits │ 12 bits │
│ 符号 │ 时间戳(ms) │ 机器号 │ 序列号 │
│ (0) │ (相对 2020-01-01 偏移) │ (0-1023) │ (0-4095) │
└───────┴──────────────────────────┴────────────┴──────────────┘
```
- 时间戳: 41 bits,可用约 69 年 (2020-2089)
- 机器号: 10 bits,最多 1024 台机器
- 序列号: 12 bits,每毫秒最多 4096 个 ID
## 机器号分配
### Redis 存储结构
使用 Redis Hash 存储机器号分配:
```
Key: sfid
Field: 机器号 (0-1023)
Value: 机器唯一标识 (machine-uid 或 uuid)
TTL: 1 小时 (使用 HEXPIRE,Redis 7.4+)
```
### 分配流程
```
┌─────────────┐
│ 启动 │
└──────┬──────┘
▼
┌─────────────────────┐
│ 生成随机起始点 start │
└──────┬──────────────┘
▼
┌─────────────────────┐
│ id = (start + i) % │◀──────┐
│ 1024 │ │
└──────┬──────────────┘ │
▼ │
┌─────────────────────┐ │
│ HSETNX sfid id │ │
│ local_id │ │
└──────┬──────────────┘ │
▼ │
┌───────┐ │
│成功? │──否──▶ 检查是否 │
└───┬───┘ 已拥有 ────┘
│是 │是
▼ ▼
┌─────────────────────────────┐
│ HEXPIRE sfid 3600 FIELDS │
│ 1 id │
└──────┬──────────────────────┘
▼
┌─────────────────────┐
│ 启动心跳任务 │
│ (每 15 分钟续期) │
└─────────────────────┘
```
### 心跳机制
- 间隔: 15 分钟
- 过期: 1 小时
- 操作: HSET + HEXPIRE 刷新
超过 1 小时无心跳,机器号自动释放,可被其他实例认领。
## 时钟回拨处理
使用 `coarsetime` 获取时间,减少系统调用开销。
### 回拨策略
```
┌─────────────────────┐
│ 获取当前时间 ts │
└──────┬──────────────┘
▼
┌───────────┐
│ ts < last │
└─────┬─────┘
│是
▼
┌───────────────┐
│ diff > 100ms? │
└───────┬───────┘
是 │ 否
▼ ▼
┌─────┐ ┌──────────────┐
│错误 │ │ sleep(diff) │
└─────┘ │ 等待追上 │
└──────────────┘
```
- 小幅回拨 (≤100ms): 等待时间追上
- 大幅回拨 (>100ms): 返回错误,拒绝生成
## 并发安全
### Snowflake Generator
- `last_ts`: AtomicI64,CAS 更新
- `sequence`: AtomicU16,原子递增
- 无锁设计,高并发性能
### 序列号溢出
同一毫秒内序列号用尽 (>4095) 时,自旋等待下一毫秒。
## 依赖
| coarsetime | 高性能时间获取 |
| fred | Redis 客户端 |
| machine-uid | 机器唯一标识 |
| static_ | 异步静态初始化 |
| xkv | Redis 连接池 |
## 使用示例
```rust
use sfid::{Snowflake, MACHINE_ID};
static SF: Snowflake = Snowflake::new();
#[tokio::main]
async fn main() -> Result<()> {
// 初始化机器号
xboot::auto().await?;
println!("machine_id: {}", **MACHINE_ID);
// 生成 ID
let id = SF.next()?;
println!("id: {id}");
Ok(())
}
```