AI图像生成网站
目录
一、项目介绍
二、雪花算法
三、JWT认证与令牌桶算法
四、项目架构
五、图床上传与图像生成API搭建
六、项目测试与调试(等待更新)
雪花算法
雪花算法 (Snowflake) 是一种高效、可扩展的分布式唯一ID生成算法,最早由 Twitter 开发,并被广泛应用于各种系统中。本文将结合 Sonyflake 的实现代码,讲解雪花算法的原理与实现。
雪花算法之所以能够作为一种分布式 ID 生成策略,是因为它能够保证:
- 全局唯一性:无重复 ID。
- 高效性:生成速度快。
- 有序性:ID 基于时间戳,有趋势递增的特性。
它生成的 64 位二进制 ID 通常由以下几部分组成:
- 符号位 (1 bit):始终为 0。
- 时间戳 (41 bits):记录自某个时间起始点的毫秒数。
- 机器ID (10 bits):标识生成 ID 的机器节点。
- 序列号 (12 bits):用于每毫秒内生成多个 ID。
其中,符号位为0是因为 Snowflake ID 被设计为无符号整数(uint64),没有负数的场景,符号位只是为了占位,以保持位数的一致性。
假设生成的 ID 为 145038507964891137
,转化为二进制:
0000001000001000011001000101010011111101000000000000000000000001
这串二进制可以分解为 64 位:
位数范围(从左到右) | 部分 | 二进制值 | 十进制值 | 说明 |
---|---|---|---|---|
1 | 符号位 | 0 | 0 | 固定为 0,表示正数 |
2 - 40 | 时间戳 | 000000100000100001100100010101001111110 | 13829335678 | 自起始时间以来的毫秒数 |
41 - 56 | 机器 ID | 1000000000000000 | 32768 | 当前机器编号 |
57 - 64 | 序列号 | 00000001 | 1 | 当前毫秒内生成的第 1 个 ID |
Sonyflake 简介
Sonyflake 是 Go 语言实现的雪花算法改进版本,相比 Twitter 的实现,它:
- 使用更精准的时间单位。
- 提供了自定义机器 ID 的能力。
- 支持长时间运行,且避免了时钟回拨问题。
具体的改进有:
改进点 | Snowflake 的问题 | Sonyflake 的优化 |
---|---|---|
符号位 | 固定占用 1 位,没有实际用途 | 去掉符号位,增加实际可用位数。 |
机器 ID 长度 | 10 位,只支持最多 1024 个节点 | 16 位,支持最多 65536 个节点。 |
时间戳处理 | 依赖系统时间,易受时钟回拨影响 | 提供时钟回拨检测,支持自定义起始时间戳,增强容错能力。 |
序列号长度 | 12 位,支持每毫秒最多生成 4096 个 ID | 8 位,支持每毫秒最多生成 256 个 ID,节省位数并满足一般业务需求。 |
中央协调器依赖 | 需要依赖 ZooKeeper 或其他工具分配机器 ID | 通过回调函数动态获取机器 ID,减少依赖,降低运维复杂度。 |
并发和适用场景优化 | 针对大规模分布式系统设计 | 更适合中小规模分布式系统,尤其是局部部署场景,如小型服务集群或边缘计算。 |
本项目使用 Sonyflake 来生成用户、分组和作品的唯一 ID:
package snowflake
import (
"fmt"
"github.com/sony/sonyflake"
"time"
)
var (
sonyFlake *sonyflake.Sonyflake // 实例
sonyMachineID uint16 // 机器ID
)
// 获取机器 ID
func getMachineID() (uint16, error) {
return sonyMachineID, nil
}
// 初始化 Sonyflake
func Init(machineId uint16) (err error) {
sonyMachineID = machineId
t, _ := time.Parse("2006-01-02", "2024-11-16") // 设置起始时间
settings := sonyflake.Settings{
StartTime: t, // 起始时间
MachineID: getMachineID, // 获取机器 ID
}
sonyFlake = sonyflake.NewSonyflake(settings) // 生成节点实例
return
}
// 获取唯一 ID
func GetID() (id uint64, err error) {
if sonyFlake == nil {
err = fmt.Errorf("sonyflake not inited")
return
}
id, err = sonyFlake.NextID()
return
}
步骤解析
(1) 初始化实例
通过 Init(machineId uint16)
初始化 Sonyflake 实例,设置了:
- 开始时间:2024-11-16。
- 机器 ID:通过 getMachineID 获取。
settings := sonyflake.Settings{
StartTime: t, // 起始时间
MachineID: getMachineID, // 获取机器 ID
}
sonyFlake = sonyflake.NewSonyflake(settings) // 创建实例
(2) 生成唯一 ID
使用 sonyFlake.NextID() 获取唯一 ID,每次调用都会根据时间戳和机器 ID 自动生成新的 ID。
id, err = sonyFlake.NextID()
(3) 机器 ID 获取
getMachineID
函数为每个实例分配唯一的 uint16
值,用于区分生成 ID 的节点。
func getMachineID() (uint16, error) {
return sonyMachineID, nil
}
Sonyflake 的 ID 生成
以下是调用代码生成示例 ID的步骤:
package main
import (
"fmt"
"snowflake"
)
func main() {
err := snowflake.Init(1) // 初始化机器 ID 为 1
if err != nil {
panic(err)
}
id, err := snowflake.GetID() // 获取唯一 ID
if err != nil {
panic(err)
}
fmt.Printf("生成的ID: %d\n", id)
}