客户端代码:
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~ |