分佈式ID(唯一性)的生成方法

我們在開發分佈式系統的時候,我們對數據庫的中的ID要保證唯一性,在數據庫分庫分表的時候,我們可能利用id的唯一性。

今天介紹一種生成分佈式ID的方法

SnowFlake 算法,是 Twitter 開源的分佈式 id 生成算法。其核心思想就是:使用一個 64 bit 的 long 型的數字作爲全局唯一 id。這 64 個 bit 中,其中 1 個 bit 是不用的,然後用其中的 41 bit 作爲毫秒數,用 10 bit 作爲工作機器 id,12 bit 作爲序列號。

給大家舉個例子吧,比如下面那個 64 bit 的 long 型數字:

  • 第一個部分,是 1 個 bit:0,這個是無意義的。

  • 第二個部分是 41 個 bit:表示的是時間戳。

  • 第三個部分是 5 個 bit:表示的是機房 id,10001。

  • 第四個部分是 5 個 bit:表示的是機器 id,1 1001。

  • 第五個部分是 12 個 bit:表示的序號,就是某個機房某臺機器上這一毫秒內同時生成的 id 的序號,0000 00000000。

①1 bit:是不用的,爲啥呢?

因爲二進制裏第一個 bit 爲如果是 1,那麼都是負數,但是我們生成的 id 都是正數,所以第一個 bit 統一都是 0。

②41 bit:表示的是時間戳,單位是毫秒。

41 bit 可以表示的數字多達 2^41 - 1,也就是可以標識 2 ^ 41 - 1 個毫秒值,換算成年就是表示 69 年的時間。

③10 bit:記錄工作機器 id,代表的是這個服務最多可以部署在 2^10 臺機器上,也就是 1024 臺機器。

但是 10 bit 裏 5 個 bit 代表機房 id,5 個 bit 代表機器 id。意思就是最多代表 2 ^ 5 個機房(32 個機房),每個機房裏可以代表 2 ^ 5 個機器(32 臺機器)。

④12 bit:這個是用來記錄同一個毫秒內產生的不同 id。

12 bit 可以代表的最大正整數是 2 ^ 12 - 1 = 4096,也就是說可以用這個 12 bit 代表的數字來區分同一個毫秒內的 4096 個不同的 id。簡單來說,你的某個服務假設要生成一個全局唯一 id,那麼就可以發送一個請求給部署了 SnowFlake 算法的系統,由這個 SnowFlake 算法系統來生成唯一 id。

這個 SnowFlake 算法系統首先肯定是知道自己所在的機房和機器的,比如機房 id = 17,機器 id = 12。

接着 SnowFlake 算法系統接收到這個請求之後,首先就會用二進制位運算的方式生成一個 64 bit 的 long 型 id,64 個 bit 中的第一個 bit 是無意義的。

接着 41 個 bit,就可以用當前時間戳(單位到毫秒),然後接着 5 個 bit 設置上這個機房 id,還有 5 個 bit 設置上機器 id。

最後再判斷一下,當前這臺機房的這臺機器上這一毫秒內,這是第幾個請求,給這次生成 id 的請求累加一個序號,作爲最後的 12 個 bit。

最終一個 64 個 bit 的 id 就出來了,類似於:

這個算法可以保證說,一個機房的一臺機器上,在同一毫秒內,生成了一個唯一的 id。可能一個毫秒內會生成多個 id,但是有最後 12 個 bit 的序號來區分開來。

下面我們簡單看看這個 SnowFlake 算法的一個代碼實現,這就是個示例,大家如果理解了這個意思之後,以後可以自己嘗試改造這個算法。

snowflake的go語言源代碼:https://github.com/bwmarrin/snowflake

參考案例:

package main

import (
	"fmt"

	"github.com/bwmarrin/snowflake"
)

func main() {

	// Create a new Node with a Node number of 1
	node, err := snowflake.NewNode(1)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Generate a snowflake ID.
	id := node.Generate()

	// Print out the ID in a few different ways.
	fmt.Printf("Int64  ID: %d\n", id)
	fmt.Printf("String ID: %s\n", id)
	fmt.Printf("Base2  ID: %s\n", id.Base2())
	fmt.Printf("Base64 ID: %s\n", id.Base64())

	// Print out the ID's timestamp
	fmt.Printf("ID Time  : %d\n", id.Time())

	// Print out the ID's node number
	fmt.Printf("ID Node  : %d\n", id.Node())

	// Print out the ID's sequence number
	fmt.Printf("ID Step  : %d\n", id.Step())

  // Generate and print, all in one.
  fmt.Printf("ID       : %d\n", node.Generate().Int64())
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章