客户端代码:
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 }
![]() | 1 lqs 2020-02-15 20:38:06 +08:00 每次都 Init 当然会一样了 |
2 OllyDebug 2020-02-15 22:20:18 +08:00 via iPhone 代码的锅 |
3 jingege 2020-02-15 22:36:15 +08:00 via Android 我知道有个 nug,但是其实很容易发现,我决定先不告诉你 |
4 stevenhawking 2020-02-15 23:05:03 +08:00 @jingege 我知道你这句话有个 nug,但是其实很容易发现,我决定先不告诉你 |
![]() | 5 swulling 2020-02-16 01:40:01 +08:00 via iPhone 用法有问题,时间 workerID 序列号都相同 |
![]() | 6 sunmoon1983 OP |
![]() | 7 sunmoon1983 OP @swulling 大老,指点一下?循环里面要怎么用? |
![]() | 8 sunmoon1983 OP 感谢大家, @lqs 谢谢,我把 INIT 拿出来就可以了 |
![]() | 9 beiping96 2020-02-17 13:19:02 +08:00 另外还有一个点,如果生成 snowflake ID 的节点 在小于几 ms 内完成重启的话,也是会发生重复的 |
![]() | 10 zunceng 2020-02-26 13:23:45 +08:00 |
11 yuechen323 2020-04-23 10:49:53 +08:00 基于 SnowFlake 简单是简单, 但是需要二次开发 在每个应用内, 多线程情况下, 且高并发是一定会出现重复的, 因此生成 id 的服务一定要做成独立的服务 且生成 id 的进程一定是单线程, 可以用池化技术进行预分配 id 来优化速度 如果 id 服务要做成集群, 那么 dataCenterId 一定设置成不一样的, 这就变成了有状态服务 有状态服务如何优化呢? 可以在启动 id 服务的时候, 从 redis 啊, zookeeper 里面原子的获取自增 id 来实现 这样就可以无脑的部署多个点了 Peace~ |