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

View File

@@ -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