优化全局 id 生成效率

This commit is contained in:
2025-12-05 17:30:18 +08:00
parent 3f24fba1ae
commit 4a2dcabf58
2 changed files with 13 additions and 35 deletions

View File

@@ -2,8 +2,6 @@
trade/create 性能问题,缩短事务时间,考虑其他方式实现可靠分布式事务
需要确认以下 ID.GenSerial 的分布式并发安全性
jsonb 类型转换问题,考虑一个高效的 any 到 struct 转换工具
端口资源池的 gc 实现

View File

@@ -44,48 +44,28 @@ var (
)
func (s *IdService) GenSerial() (string, error) {
var ctx = context.Background()
// 构造Redis键
now := time.Now().Unix()
key := idSerialKey(now)
// 使用Redis事务确保原子操作
var sequence int64
err := g.Redis.Watch(ctx, func(tx *redis.Tx) error {
// 脚本实现原子操作
script := redis.NewScript(`
local current = tonumber(redis.call('GET', KEYS[1])) or 0
if current >= tonumber(ARGV[1]) then
return redis.error_reply('sequence overflow')
end
// 获取当前序列号
currentVal, err := tx.Get(ctx, key).Int64()
if err != nil && !errors.Is(err, redis.Nil) {
return err
}
local sequence = current + 1
redis.call('SET', KEYS[1], sequence, 'EX', ARGV[2])
if errors.Is(err, redis.Nil) {
currentVal = 0
}
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)
return sequence
`)
sequence, err := script.Run(context.Background(), g.Redis, []string{idSerialKey(now)}, maxSequence, redisTTL).Int64()
if err != nil {
return "", err
}
// 组装最终ID
id := uint64((now << timestampShift) | sequence)
idStr := strconv.FormatUint(id, 10)
return idStr, nil
return strconv.FormatUint(id, 10), nil
}
// ParseSerial 解析ID返回其组成部分
@@ -98,7 +78,7 @@ func (s *IdService) ParseSerial(id uint64) (timestamp int64, sequence int64) {
// idSerialKey 根据时间戳生成Redis键
func idSerialKey(timestamp int64) string {
return fmt.Sprintf("global:id:serial:%d", timestamp)
return fmt.Sprintf("id:serial:%d", timestamp)
}
// endregion