Twitter snowflake ID 演算法之 golang 實現

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

是什嗎?

snowflake ID 演算法是 twitter 使用的唯一 ID 產生演算法,為了滿足 Twitter 每秒上萬條訊息的請求,使每條訊息有唯一、有一定順序的 ID ,且支援分布式產生。

主要解決了高並發時 ID 產生不重複的問題

結構

snowflake ID 的結構是一個 64 bit 的 int 型資料。

:

1 bit:不使用,可以是 1 或 0

41 bit:記錄時間戳記 (目前時間戳減去使用者佈建的初始時間,毫秒錶示),可記錄最多 69 年的時間戳記資料

10 bit:用來記錄分布式節點 ID,一般每台機器一個唯一 ID,也可以多進程每個進程一個唯一 ID,最大可部署 1024 個節點

12 bit:序號,用來記錄不同 ID 同一毫秒時的序號,最多可產生 4096 個序號

時間戳記、節點 ID 和序號的位元可以根據業務自由浮動調整

唯一 ID 原理

假設在一個節點 (機器) 上,節點 ID 唯一,並發時有多個線程去產生 ID。
滿足以上條件時,如果多個進程在同一毫秒內產生 ID,那麼序號步進 (加一),這裡要保證序號的操作並發安全,使同一毫秒內產生的 ID 擁有不同序號。如果序號達到上限,則等待這一毫秒結束,在新的毫秒繼續步進。

這樣保證了:
所有產生的 ID 按時間趨勢遞增
整個分布式系統內不會產生重複 ID

用 go 實現的思路

why go ?

go 有封裝好的協程 goroutine,可以很好的處理並發,可以加鎖保證資料的同步安全,有很好的效能。當然其它語言如 Java、Scala 也是完全可以的。

思路

1、確定唯一的節點 ID
2、設定一個初始時間戳記 (毫秒錶示)
3、處理並發時序號步進和並發安全問題
4、組裝各個 bits ,產生最終的 64 bit ID

編碼實現

首先我們要引入基礎的模組

import (    "fmt"        // 測試、列印    "time"      // 擷取時間    "errors"    // 建置錯誤    "sync"      // 使用互斥鎖)

基礎常量定義

這裡求最大值使用了位元運算,-1 的二進位表示為 1 的補碼,感興趣的同學可以自己算算試試 -1 ^ (-1 << nodeBits) 這裡是不是等於 1023
const (    nodeBits  uint8 = 10          // 節點 ID 的位元    stepBits  uint8 = 12            // 序號的位元    nodeMax   int64 = -1 ^ (-1 << nodeBits)   // 節點 ID 的最大值,用於檢測溢出    stepMax   int64 = -1 ^ (-1 << stepBits)    // 序號的最大值,用於檢測溢出    timeShift uint8 = nodeBits + stepBits    // 時間戳記向左的位移量    nodeShift uint8 = stepBits  // 節點 ID 向左的位移量)

設定初始時間的時間戳記 (毫秒錶示),我這裡使用 twitter 設定的一個時間,這個可以隨意設定 ,比現在的時間靠前即可。

var Epoch int64 = 1288834974657 // timestamp 2006-03-21:20:50:14 GMT

ID 結構和 Node 結構的實現
這裡我們申明一個 int64 的 ID 類型 (這樣可以為此類型定義方法,比直接使用 int64 變數更靈活)

type ID int64

Node 結構用來儲存一個節點 (機器) 上的基礎資料

type Node struct {    mu sync.Mutex         // 添加互斥鎖,保證並發安全    timestamp int64      // 時間戳記部分    node      int64      // 節點 ID 部分      step      int64      // 序號 ID 部分          }

擷取 Node 類型執行個體的函數,用於獲得當前節點的 Node 執行個體

func NewNode(node int64) (*Node, error) {    // 如果超出節點的最大範圍,產生一個 error    if node < 0 || node > nodeMax {        return nil, errors.New("Node number must be between 0 and 1023")    }    // 產生並返回節點執行個體的指標    return &Node{        timestamp: 0,        node:      node,        step:       0,    }, nil}

最後一步,產生 ID 的方法

func (n *Node) Generate() ID {        n.mu.Lock() // 保證並發安全, 加鎖    defer n.mu.Unlock() // 方法運行完畢後解鎖    // 擷取目前時間的時間戳記 (毫秒數顯示)    now := time.Now().UnixNano() / 1e6    if n.timestamp == now {        // step 步進 1         n.step ++        // 當前 step 用完        if n.step > stepMax {            // 等待本毫秒結束            for now <= n.timestamp {                now = time.Now().UnixNano() / 1e6            }        }    } else {        // 本毫秒內 step 用完        n.step = 0    }        n.timestamp = now    // 移位元運算,生產最終 ID    result := ID((now - Epoch) << timeShift | (n.node << nodeShift) | (n.step))    return result}

測試

我們使用迴圈去開啟多個 goroutine 去並發產生 ID,然後使用 map 以 ID 作為鍵儲存,來判斷是否產生了唯一的 ID

main 函數代碼

func main() {    // 測試指令碼    // 產生節點執行個體    node, err := NewNode(1)    if err != nil {        fmt.Println(err)        return    }    ch := make(chan ID)    count := 10000    // 並發 count 個 goroutine 進行 snowflake ID 產生    for i := 0; i < count; i++ {        go func() {            id := node.Generate()            ch <- id        }()    }                defer close(ch)    m := make(map[ID]int)    for i := 0; i < count; i++  {        id := <- ch        // 如果 map 中存在為 id 的 key, 說明產生的 snowflake ID 有重複        _, ok := m[id]        if ok {            fmt.Printf("ID is not unique!\n")            return        }        // 將 id 作為 key 存入 map        m[id] = i    }    // 成功產生 snowflake ID    fmt.Println("All ", count, " snowflake ID generate successed!\n")}

完整的程式執行個體 :點我查看

上線使用

你可以用 go 的 net/http 包處理並發請求,產生 ID 並且返回 http 響應結果。
Just do it

參考文章

【1】理解分布式id產生演算法SnowFlake
【2】bwmarrin/snowflake

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.