看了雪花算法,服务需要配置标识位(数据中心 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 不会溢出。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.