V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
sunmoon1983

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

  •  1
     
  •   sunmoon1983 · Feb 15, 2020 · 5921 views
    This topic created in 2263 days ago, the information mentioned may be changed or developed.

    客户端代码:

    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
    }
    
    11 replies    2020-04-23 10:49:53 +08:00
    lqs
        1
    lqs  
       Feb 15, 2020
    每次都 Init 当然会一样了
    OllyDebug
        2
    OllyDebug  
       Feb 15, 2020 via iPhone
    代码的锅
    jingege
        3
    jingege  
       Feb 15, 2020 via Android
    我知道有个 nug,但是其实很容易发现,我决定先不告诉你
    stevenhawking
        4
    stevenhawking  
       Feb 15, 2020
    @jingege 我知道你这句话有个 nug,但是其实很容易发现,我决定先不告诉你
    swulling
        5
    swulling  
       Feb 16, 2020 via iPhone
    用法有问题,时间 workerID 序列号都相同
    sunmoon1983
        6
    sunmoon1983  
    OP
       Feb 16, 2020
    @lqs init 里面有判断,如果已经初始化了
    if sfg.isHaveInit {
    return sfg, nil
    }
    sunmoon1983
        7
    sunmoon1983  
    OP
       Feb 16, 2020
    @swulling 大老,指点一下?循环里面要怎么用?
    sunmoon1983
        8
    sunmoon1983  
    OP
       Feb 16, 2020
    感谢大家,
    @lqs 谢谢,我把 INIT 拿出来就可以了
    beiping96
        9
    beiping96  
       Feb 17, 2020
    另外还有一个点,如果生成 snowflake ID 的节点 在小于几 ms 内完成重启的话,也是会发生重复的
    yuechen323
        11
    yuechen323  
       Apr 23, 2020
    基于 SnowFlake 简单是简单, 但是需要二次开发
    在每个应用内, 多线程情况下, 且高并发是一定会出现重复的, 因此生成 id 的服务一定要做成独立的服务
    且生成 id 的进程一定是单线程, 可以用池化技术进行预分配 id 来优化速度
    如果 id 服务要做成集群, 那么 dataCenterId 一定设置成不一样的, 这就变成了有状态服务
    有状态服务如何优化呢?
    可以在启动 id 服务的时候, 从 redis 啊, zookeeper 里面原子的获取自增 id 来实现
    这样就可以无脑的部署多个点了
    Peace~
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2997 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 51ms · UTC 15:22 · PVG 23:22 · LAX 08:22 · JFK 11:22
    ♥ Do have faith in what you're doing.