### 關于雪花
雪花(snowflake)在自然界中,是極具獨特美麗,又變幻莫測的東西:
+ 1.雪花屬于六方晶系,它具有四個結晶軸,其中三個輔軸在一個基面上,互相以60度的角度相交,第四軸(主晶軸)與三個輔軸所形成的基面垂直;
+ 2.雪花的基本形狀是六角形,但是大自然中卻幾乎找不出兩朵完全相同的雪花,每一個雪花都擁有自己的獨有圖案,就象地球上找不出兩個完全相同的人一樣。許多學者用顯微鏡觀測過成千上萬朵雪花,這些研究最后表明,形狀、大小完全一樣和各部分完全對稱的雪花,在自然界中是無法形成的。
### 雪花算法
雪花算法的原始版本是scala版,用于生成分布式ID(純數字,時間順序),訂單編號等。
> 自增ID:對于數據敏感場景不宜使用,且不適合于分布式場景。
> GUID:采用無意義字符串,數據量增大時造成訪問過慢,且不宜排序。

### 算法描述
+ 最高位是符號位,始終為0,不可用。
+ 41位的時間序列,精確到毫秒級,41位的長度可以使用69年。時間位還有一個很重要的作用是可以根據時間進行排序。
+ 10位的機器標識,10位的長度最多支持部署1024個節點。
+ 12位的計數序列號,序列號即一系列的自增id,可以支持同一節點同一毫秒生成多個ID序號,12位的計數序列號支持每個節點每毫秒產生4096個ID序號。
代碼:
```go
package main
import (
"errors"
"fmt"
"sync"
"time"
)
const (
workerBits uint8 = 10
numberBits uint8 = 12
workerMax int64 = -1 ^ (-1 << workerBits)
numberMax int64 = -1 ^ (-1 << numberBits)
timeShift uint8 = workerBits + numberBits
workerShift uint8 = numberBits
startTime int64 = 1525705533000 // 如果在程序跑了一段時間修改了epoch這個值 可能會導致生成相同的ID
)
type Worker struct {
mu sync.Mutex
timestamp int64
workerId int64
number int64
}
func NewWorker(workerId int64) (*Worker, error) {
if workerId < 0 || workerId > workerMax {
return nil, errors.New("Worker ID excess of quantity")
}
// 生成一個新節點
return &Worker{
timestamp: 0,
workerId: workerId,
number: 0,
}, nil
}
func (w *Worker) GetId() int64 {
w.mu.Lock()
defer w.mu.Unlock()
now := time.Now().UnixNano() / 1e6
if w.timestamp == now {
w.number++
if w.number > numberMax {
for now <= w.timestamp {
now = time.Now().UnixNano() / 1e6
}
}
} else {
w.number = 0
w.timestamp = now
}
ID := int64((now-startTime)<<timeShift | (w.workerId << workerShift) | (w.number))
return ID
}
func main() {
// 生成節點實例
node, err := NewWorker(1)
if err != nil {
panic(err)
}
for {
fmt.Println(node.GetId())
}
}
```