snowflake 算法生成的 id 也能重复?

2020-02-15 20:23:20 +08:00
 sunmoon1983

客户端代码:

func GenerateID() (string, error) {
	c := connect.Instance() //连接 grpc
	cc, cancel := c.ServerClient()
	defer cancel()
    //生成 id
	r, err := cc.GenerateSnowflakeID(c.Ctx, &serv.GenerateSnowflakeRequest{WorkID:"1"})
	if err != nil {
		return "", err
	}
	return r.GetMessage(), err
}
func main() {
	data := ""
	for i:=0;i<=100;i++{
		id, err := GenerateID()
		str := gconv.String(id)
		fmt.Println("ID(运行到第"+gconv.String(i+1)+"条):"+str+",长度:"+gconv.String(len(str)))
		if strings.Contains(data,","+str+","){
			fmt.Println("ID 重复(运行到第"+gconv.String(i+1)+"条):"+str)
			break
		}else{
			if err != nil{
				fmt.Println(err.Error())
			}
			data = data+","+str+","
		}
	}
}

生成结果

sunmoondeMacBook-Pro:client_test sunmoon$ go run main.go 
ID(运行到第 1 条):1581769199913537536,长度:19
ID(运行到第 2 条):1581769199913537536,长度:19
ID 重复(运行到第 2 条):1581769199913537536

服务端代码

// GenerateSnowflakeID 生成 ID
func (s *Server) GenerateSnowflakeID(ctx context.Context, in *serv.GenerateSnowflakeRequest) (re *serv.GenerateReply, err error) {
	gen, err := snowflake.New().SetWorkerID(gconv.Int64(in.GetWorkID())).Init()
	if err != nil {
		glog.Line(true).Println(err.Error())
		return
	}
	id, err := gen.Generate()
	if err != nil {
		glog.Line(true).Println(err.Error())
		return
	}
	//id := s.GetWuid()
	re = &serv.GenerateReply{Message: gconv.String(id)}
	return
}
5124 次点击
所在节点    Go 编程语言
11 条回复
lqs
2020-02-15 20:38:06 +08:00
每次都 Init 当然会一样了
OllyDebug
2020-02-15 22:20:18 +08:00
代码的锅
jingege
2020-02-15 22:36:15 +08:00
我知道有个 nug,但是其实很容易发现,我决定先不告诉你
stevenhawking
2020-02-15 23:05:03 +08:00
@jingege 我知道你这句话有个 nug,但是其实很容易发现,我决定先不告诉你
swulling
2020-02-16 01:40:01 +08:00
用法有问题,时间 workerID 序列号都相同
sunmoon1983
2020-02-16 08:02:12 +08:00
@lqs init 里面有判断,如果已经初始化了
if sfg.isHaveInit {
return sfg, nil
}
sunmoon1983
2020-02-16 08:02:55 +08:00
@swulling 大老,指点一下?循环里面要怎么用?
sunmoon1983
2020-02-16 08:12:00 +08:00
感谢大家,
@lqs 谢谢,我把 INIT 拿出来就可以了
beiping96
2020-02-17 13:19:02 +08:00
另外还有一个点,如果生成 snowflake ID 的节点 在小于几 ms 内完成重启的话,也是会发生重复的
zunceng
2020-02-26 13:23:45 +08:00
yuechen323
2020-04-23 10:49:53 +08:00
基于 SnowFlake 简单是简单, 但是需要二次开发
在每个应用内, 多线程情况下, 且高并发是一定会出现重复的, 因此生成 id 的服务一定要做成独立的服务
且生成 id 的进程一定是单线程, 可以用池化技术进行预分配 id 来优化速度
如果 id 服务要做成集群, 那么 dataCenterId 一定设置成不一样的, 这就变成了有状态服务
有状态服务如何优化呢?
可以在启动 id 服务的时候, 从 redis 啊, zookeeper 里面原子的获取自增 id 来实现
这样就可以无脑的部署多个点了
Peace~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/644873

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX