git.zd.zone/hrpc/hrpc@v0.0.12/utils/uniqueid/uniqueid.go (about) 1 package uniqueid 2 3 import ( 4 "errors" 5 "strconv" 6 "sync" 7 "time" 8 ) 9 10 // 因为snowFlake目的是解决分布式下生成唯一id 所以ID中是包含集群和节点编号在内的 11 const ( 12 workerBits uint8 = 10 // 每台机器(节点)的ID位数 10位最大可以有2^10=1024个节点 13 numberBits uint8 = 12 // 表示每个集群下的每个节点,1毫秒内可生成的id序号的二进制位数 即每毫秒可生成 2^12-1=4096个唯一ID 14 // 这里求最大值使用了位运算,-1 的二进制表示为 1 的补码,感兴趣的同学可以自己算算试试 -1 ^ (-1 << nodeBits) 这里是不是等于 1023 15 nodeMax int64 = -1 ^ (-1 << workerBits) // 节点ID的最大值,用于防止溢出 16 numberMax int64 = -1 ^ (-1 << numberBits) // 同上,用来表示生成id序号的最大值 17 timeShift uint8 = workerBits + numberBits // 时间戳向左的偏移量 18 workerShift uint8 = numberBits // 节点ID向左的偏移量 19 // 41位字节作为时间戳数值的话 大约68年就会用完 20 // 假如你2010年1月1日开始开发系统 如果不减去2010年1月1日的时间戳 那么白白浪费40年的时间戳啊! 21 // 这个一旦定义且开始生成ID后千万不要改了 不然可能会生成相同的ID 22 epoch int64 = 1597472019000 // 这个是我在写epoch这个变量时的时间戳(毫秒) 23 ) 24 25 // serviceNode should be used for global 26 var ( 27 serviceNode *Node 28 nodeID int64 29 myIP string 30 ) 31 32 // Node 定义一个Node工作节点所需要的基本参数 33 type Node struct { 34 mu sync.Mutex // 添加互斥锁 确保并发安全 35 timestamp int64 // 记录时间戳 36 nodeID int64 // 该节点的ID 37 number int64 // 当前毫秒已经生成的id序列号(从0开始累加) 1毫秒内最多生成4096个ID 38 uniqueID int64 39 } 40 41 type Option struct { 42 NodeID int64 43 } 44 45 func init() { 46 var err error 47 nodeID, err = createNodeID() 48 if err != nil { 49 panic(err) 50 } 51 serviceNode = &Node{nodeID: nodeID} 52 } 53 54 // NewNode 实例化一个工作节点 55 // 优先级是: 传入参数 > 已存在的NodeID > createNodeID 56 func New(options ...Option) *Node { 57 options = append(options, Option{NodeID: nodeID}) 58 59 // Check the nodeID is valid or not 60 // 此时options 61 for _, v := range options { 62 if err := v.validate(); err == nil { 63 // 一旦有校验通过的,则赋值 return 64 serviceNode = &Node{nodeID: nodeID} 65 return serviceNode 66 } 67 } 68 return serviceNode 69 } 70 71 func (n *Node) Load() error { 72 return nil 73 } 74 75 func (n *Node) Name() string { 76 return "hrpc-uniqueid" 77 } 78 79 func (n *Node) DependsOn() []string { 80 return nil 81 } 82 83 func (o Option) validate() error { 84 if o.NodeID < 0 || o.NodeID > nodeMax { 85 return errors.New("Node ID excess of quantity") 86 } 87 return nil 88 } 89 90 // newNode will return an unique ID for different uses 91 func newNode() *Node { 92 // 获取生成时的时间戳 93 now := time.Now().UnixNano() / 1e6 // 纳秒转毫秒 94 if serviceNode.timestamp == now { 95 serviceNode.number++ 96 // 这里要判断,当前工作节点是否在1毫秒内已经生成numberMax个ID 97 if serviceNode.number > numberMax { 98 // 如果当前工作节点在1毫秒内生成的ID已经超过上限 需要等待1毫秒再继续生成 99 for now <= serviceNode.timestamp { 100 now = time.Now().UnixNano() / 1e6 101 } 102 } 103 } else { 104 // 如果当前时间与工作节点上一次生成ID的时间不一致 则需要重置工作节点生成ID的序号 105 serviceNode.number = 0 106 serviceNode.timestamp = now // 将机器上一次生成ID的时间更新为当前时间 107 } 108 // 第一段 now - epoch 为该算法目前已经奔跑了xxx毫秒 109 // 如果在程序跑了一段时间修改了epoch这个值 可能会导致生成相同的ID 110 serviceNode.uniqueID = int64((now-epoch)<<timeShift | (serviceNode.nodeID << workerShift) | (serviceNode.number)) 111 return serviceNode 112 } 113 114 func String() string { 115 serviceNode.mu.Lock() 116 defer serviceNode.mu.Unlock() 117 118 return strconv.FormatInt(newNode().uniqueID, 10) 119 } 120 121 func Number() int64 { 122 serviceNode.mu.Lock() 123 defer serviceNode.mu.Unlock() 124 125 return newNode().uniqueID 126 } 127 128 func NodeID() int64 { 129 return nodeID 130 } 131 132 func IP() string { 133 return myIP 134 }