需求场景: 总部采集分支的数据,由于分支的 id 是子增的主键 id,所以会出现重复的 id,但是这个 id 需要作为标识,没有实际作用,这里选择的是分布式 id 雪花算法生成 id 存储用来标识,这个项目基于 gva 进行开发的,可以使用 sonyflake
和 snowflake
两个实现方式都可以解决这个问题,这里选择 snowflake
进行设计
雪花算法,由Twitter开源,是一种分布式唯一ID生成算法。这种算法的主要特点是简单、高效,生成的64位整数ID全局唯一,且趋势递增。在单机上,雪花算法生成的ID也能保持递增特性,但在不同的机器上,由于各自有不同的时间戳,因此生成的ID不会冲突。
这种算法的性能相当高,每秒中能生成数百万的自增ID。因此,雪花算法被广泛应用于分布式系统中需要唯一ID的场景。例如,美团开源的分布式ID生成器Leaf也采用了雪花算法来保证全局唯一和趋势递增。
我这边演示是通过插件注入的方式进行对 gva 进行二开,在 gva 后端模块的 server/plugin
中创建一个新的业务目录,里面创建一个 utils 工具文件夹,然后创建一个名字为 snowflake.go 文件,并且在 server 的全局 config.yaml
文件配置一个 snowflake,在 main.go
主函数进行初始化以后就可以生成对应的雪花 id 了
拉取 snowflake
go get github.com/bwmarrin/snowflake
config.yaml 添加下面内容
snowflake:
start-time: "2024-01-01" # string
machineID: 1 # int64
plugin/工程目录添加config
// Snowflake 雪花机器结构体
type Snowflake struct {
StartTime string `mapstructure:"start-time" json:"start-time" yaml:"start-time"`
MachineID int64 `mapstructure:"machineID" json:"machineID" yaml:"machineID"`
}
全局config/config.go 中绑定注入这个 Snowflake 结构体
type Server struct {
..........
// 雪花
Snowflake config.Snowflake `mapstructure:"snowflake" json:"snowflake" yaml:"snowflake"`
}
plugin/项目目录 创建 utils/snowflake.go
package utils
import (
"errors"
sf "github.com/bwmarrin/snowflake"
"time"
)
var node *sf.Node
// SnowflakeInit 初始化
func SnowflakeInit(startTime string, machineID int64) (err error) {
var start_time time.Time
start_time, err = time.Parse("2006-01-02", startTime)
if err != nil {
return errors.New("生成 id 失败")
}
sf.Epoch = start_time.UnixNano() / 1000000
node, err = sf.NewNode(machineID)
return
}
// GenID 生成雪花 id
func GenID() int64 {
return node.Generate().Int64()
}
主函数
main.go
初始化这个值
func main() {
.....
// 初始化雪花算法方法 SnowflakeInit
if err := utils.SnowflakeInit(global.GVA_CONFIG.Snowflake.StartTime, global.GVA_CONFIG.Snowflake.MachineID); err != nil {
fmt.Println("初始化雪花算法失败", err)
return
}
fmt.Println("测试 id", utils.GenID())
}
结果