编辑
2024-07-12
Golang
0
请注意,本文编写于 83 天前,最后修改于 83 天前,其中某些信息可能已经过时。

目录

1.定义配置对象
2.定义接口
3.ID生成
4.自定义配置
5.调用案例

Golang 1.22.2

在项目中对应数据库的唯一id,我们通常会选择使用数据库自增id,uuid,雪花算法等,每种模式的id都有各自的优缺点,这里将通过Redis来实现一种自定义分布式的id生成模式。

当然这种实现方式也有一定的缺点,那就是过于依赖redis,一旦出现redis不可用,会导致id生成失败,从而影响整个业务的不可用,所以在设计的时候需要考虑,如果redis不可用如何自动启用其他唯一id生成模式。

首先看redis实现部分:

lua
// 获取第一个Key local id_key = KEYS[1] // 获取形参的第一个数,这里是初始化值 local initial = ARGV[1] // 获取形参的第二数据,这里每次增长的量 local step = ARGV[2] // 检查key当前是否存在值 local current = redis.call('get', id_key) // 如果不存在则返回初始值,并在redis中设置初始值 if current == false then redis.call('set', id_key, initial) return initial end --redis.log(redis.LOG_NOTICE,' current:'..current..':') // 如果存在值则在当前值上面加入每次的增量,设置到redis后并返回 local result = tonumber(current)+ tonumber(step) --redis.log(redis.LOG_NOTICE,' result:'..result..':') redis.call('set', id_key, result) return tostring(result)

实现完lua脚本后,我们知道一共需要传递三个参数,有个是业务key,用来标识每个表的,第二参数是id的初始值,比如从1开始或者从1000开始,就是通过第二个参数来设置的,最后一个是每次的增长量:比如我们需要每次在原来的基础+1,那么就传递1,如果需要+10,对应的传递10即可。

脚本有了之后我们开始在golang中实现具体的功能。

1.定义配置对象

go
type Config struct { Prefix string `json:"prefix"` // 编号前缀 Initial int64 `json:"initial"` // 初始值 Step int `json:"step"` // 每次递增数量 Remark string `json:"remark"` // 备注 Key string `json:"key"` // key名称 }

2.定义接口

这里需要定义一个接口来满足不同的id需求。

go
// Sequence 序列接口 type Sequence interface { // GetConfig 获取序列配置 GetConfig() Config // NextCode 获取下一个序列化 NextCode() string }

3.ID生成

go
// 执行lua脚本获取id func execute(conf Config) string { luaId := redis.NewScript(` local id_key = KEYS[1] local initial = ARGV[1] local step = ARGV[2] local current = redis.call('get', id_key) if current == false then redis.call('set', id_key, initial) return initial end --redis.log(redis.LOG_NOTICE,' current:'..current..':') local result = tonumber(current)+ tonumber(step) --redis.log(redis.LOG_NOTICE,' result:'..result..':') redis.call('set', id_key, result) return tostring(result) `) var ctx = context.Background() n, err := luaId.Run(ctx, cache.RedisClient, []string{conf.Key}, conf.Initial, conf.Step).Int64() if err != nil { log.Log.Errorf("生成序列id错误:%s", err.Error()) return "" } return fmt.Sprintf("%s%d", conf.Prefix, n) }

4.自定义配置

go
type GoodsSeq struct { } func (u GoodsSeq) GetConfig() Config { return Config{ Prefix: "SP", Initial: 300, Step: 1, Remark: "商品配置ID生成器", Key: "goods-id-seq", } } func (u GoodsSeq) NextCode() string { conf := u.GetConfig() return execute(conf) }

5.调用案例

go
// 生成商品ID id := sequence.GoodsSeq{}.NextCode() // 输出值:SP300

到这里,一个分布式自定义的id生成器已经实现,给出的样例中,针对redis不可用的情况并没有做处理,在生产环境中需要考虑。

本文作者:南月星河

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!