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