1. 程式人生 > 其它 >golang 分散式id生成器

golang 分散式id生成器

在高併發場景中,通常需要像mysql中那樣的自增主鍵一樣的不會重複且自增的id生成

twitter的snowflake就是一種典型的解法,id數值長64位,是一個int64型別,被分為四個部分:

  • 最高位不使用
  • 41位表示收到請求的時間戳,單位為毫秒
  • 5位表示資料中心的id
  • 5位表示機器例項的id
  • 12位迴圈自增id,1111,1111,1111後歸零

這樣的機制可以保證一臺機器在一毫秒內產生4096條訊息,一秒總共409.6萬條訊息

資料中心id配合例項id一共有10位,每個資料中心可以部署32臺例項,搭建32個數據中心,所以一共存在1024個例項

41位時間戳可以使用69年

 

1. github.com/bwmarrin/snowflake

github.com/bwmarrin/snowflake是一個輕量級的snowflake實現

首先需要引入依賴

go get github.com/bwmarrin/snowflake

 

這個庫使用起來也非常簡單

func main(){
	node,err:=snowflak.NewNode(1)
	if err!=nil{
		println(err.Error())
		os.Exit(1)
	}

	for i:=0;i<20;i++{
		id:=node.Generate()

		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())
		fmt.Printf("ID time: %d\n",id.Time())
		fmt.Printf("ID node: %d\n",id.Node())
		fmt.Printf("ID step: %d\n",id.Step())
		fmt.Println("--------------------------------")
	}
}

 

這個庫是一個單檔案,其中提供了我們可以定製的引數

其中Epoch是起始時間、NodeBits是例項id的長度,預設10位、StepBits是自增id的長度,預設12位

 

2. github.com/sony/sonyflake

snoyflake側重於多主機多例項的生命週期和效能,所以與snowflake使用了不同的位分配:

  • 比snowflake更長的生命週期,174年
  • 能執行在更多的例項上,216個
  • 生成id的速度比snowflake慢,10ms內最多生成28個

 

snoyflake在啟動階段需要配置引數,主要是一個Setting結構體

type Settings struct {
	StartTime      time.Time              // 起始時間,預設2014-09-01 00:00:00 +0000 UTC
	MachineID      func() (uint16, error) // 返回例項ID的函式,如果不定義此函外,預設用本機ip的低16位
	CheckMachineID func(uint16) bool      // 驗證例項ID/計算機ID的唯一性,返回true時才建立
}

 

我們需要自己實現這兩個函式:

func getMachineID() (uint16, error) {
	var machineID uint16 = 6
	return machineID, nil
}

func checkMachineID(machineID uint16) bool {
	existsMachines := []uint16{1, 2, 3, 4, 5}
	for _, v := range existsMachines {
		if v == machineID {
			return false
		}
	}
	return true
}

 

func main() {
	t, _ := time.Parse("2006-01-02", "2021-01-01")
	settings := sonyflake.Settings{
		StartTime:      t,
		MachineID:      getMachineID,
		CheckMachineID: checkMachineID,
	}

	sf := sonyflake.NewSonyflake(settings)

	for i := 0; i < 10; i++ {
		id, err := sf.NextID()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		fmt.Println(id)
	}
}