分享一个 id 自增生成器,依赖于 redis,求大佬帮忙挑挑毛病
source link: https://www.v2ex.com/t/802473
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
看了雪花算法,服务需要配置标识位(数据中心 ID 、机器 ID ),多一项配置就多一份出错的风险,同时在不依赖其他基础服务的情况下也不太好解决时间回调的问题。然后自己实现了一个简化版的,依赖于 redis 。大佬们帮忙看看有啥问题没有,感谢。
func GlobalIncrId() (int64, error) {
script := redis.NewScript(`
local key = KEYS[1]
local stamp = ARGV[1]
local newValue = redis.call("incr", key)
if newValue then
if newValue > tonumber(stamp) then
return newValue
else
local flag = redis.call("set", key, stamp)
if flag then
return stamp
end
end
end
return nil
`)
stamp := (time.Now().Unix() - 50 * 365 * 86400) << 22
ret, err := script.Run(RedisIns, []string{sredis.KEY_GLOBAL_INCR_ID}, stamp).Int64()
return ret, err
}
自增 id 带上 stamp 信息, 是为了防止 redis 的 key 丢失, 或者值被清除。stamp 的计算回拨了 50 年, 因为 32bit 的时间戳到 2038 年就溢出了。只要机器的系统时间回调以及 key 失效这两件事不同时发生, 就能保持自增性。
低 22 位用于 redis incr 自增,高位是时间信息,即 1s 内最多支持 4194304 个 id,超出了也没关系,只是会提前占用高位的时间。
用 22 位来自增是因为某些业务可能会将 id 用在 zadd 中,zadd 的 score 范围是:-(2^53) 至 +(2^53), 即时间信息可以占用 31 位, 保证 score 不会溢出。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK