优化全局 id 生成效率
This commit is contained in:
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
trade/create 性能问题,缩短事务时间,考虑其他方式实现可靠分布式事务
|
trade/create 性能问题,缩短事务时间,考虑其他方式实现可靠分布式事务
|
||||||
|
|
||||||
需要确认以下 ID.GenSerial 的分布式并发安全性
|
|
||||||
|
|
||||||
jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
|
||||||
|
|
||||||
端口资源池的 gc 实现
|
端口资源池的 gc 实现
|
||||||
|
|||||||
@@ -44,48 +44,28 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *IdService) GenSerial() (string, error) {
|
func (s *IdService) GenSerial() (string, error) {
|
||||||
var ctx = context.Background()
|
|
||||||
|
|
||||||
// 构造Redis键
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
key := idSerialKey(now)
|
|
||||||
|
|
||||||
// 使用Redis事务确保原子操作
|
// 脚本实现原子操作
|
||||||
var sequence int64
|
script := redis.NewScript(`
|
||||||
err := g.Redis.Watch(ctx, func(tx *redis.Tx) error {
|
local current = tonumber(redis.call('GET', KEYS[1])) or 0
|
||||||
|
if current >= tonumber(ARGV[1]) then
|
||||||
|
return redis.error_reply('sequence overflow')
|
||||||
|
end
|
||||||
|
|
||||||
// 获取当前序列号
|
local sequence = current + 1
|
||||||
currentVal, err := tx.Get(ctx, key).Int64()
|
redis.call('SET', KEYS[1], sequence, 'EX', ARGV[2])
|
||||||
if err != nil && !errors.Is(err, redis.Nil) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if errors.Is(err, redis.Nil) {
|
return sequence
|
||||||
currentVal = 0
|
`)
|
||||||
}
|
sequence, err := script.Run(context.Background(), g.Redis, []string{idSerialKey(now)}, maxSequence, redisTTL).Int64()
|
||||||
sequence = currentVal + 1
|
|
||||||
|
|
||||||
// 检查序列号是否溢出
|
|
||||||
if sequence > maxSequence {
|
|
||||||
return ErrSequenceOverflow
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将更新后的序列号保存回Redis,设置5秒过期时间
|
|
||||||
pipe := tx.Pipeline()
|
|
||||||
pipe.Set(ctx, key, sequence, redisTTL*time.Second)
|
|
||||||
_, err = pipe.Exec(ctx)
|
|
||||||
return err
|
|
||||||
}, key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 组装最终ID
|
// 组装最终ID
|
||||||
id := uint64((now << timestampShift) | sequence)
|
id := uint64((now << timestampShift) | sequence)
|
||||||
|
return strconv.FormatUint(id, 10), nil
|
||||||
idStr := strconv.FormatUint(id, 10)
|
|
||||||
|
|
||||||
return idStr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseSerial 解析ID,返回其组成部分
|
// ParseSerial 解析ID,返回其组成部分
|
||||||
@@ -98,7 +78,7 @@ func (s *IdService) ParseSerial(id uint64) (timestamp int64, sequence int64) {
|
|||||||
|
|
||||||
// idSerialKey 根据时间戳生成Redis键
|
// idSerialKey 根据时间戳生成Redis键
|
||||||
func idSerialKey(timestamp int64) string {
|
func idSerialKey(timestamp int64) string {
|
||||||
return fmt.Sprintf("global:id:serial:%d", timestamp)
|
return fmt.Sprintf("id:serial:%d", timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|||||||
Reference in New Issue
Block a user