全局唯一ID – snowflake

为什么需要全局唯一ID

比如以下

分布式下唯一ID

  • 如果数据库分了库/表, 那么表的自增主键就不再唯一, 这时候就需要一个全局唯一的ID生成器才能保证唯一.
  • 可以用来作为事务ID等需要保证唯一的业务 (事务ID可以用来确保幂)

预生成ID

有些业务下需要提前生成唯一ID, 这也是表的自增主键不能满足的需求.

snowflake

生成全局唯一ID有多种方法(可以搜到), 比如使用额外的数据库或者UUID, 但笔者认为性能更好 适用性更广的是snowflake算法.

snowflake是witter开源的分布式ID生成算法, GITHUB在此
.
我们如果要在代码中使用还需要根据语言实现它的算法, 笔者使用编程语言是golang, 幸运的是GITHUB上已经有了实现好的库, 如

  • github.com/bwmarrin/snowflake

用法也十分简单, 这里贴上readme-usage看一眼, 更多使用方法请参看官方库- 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())
}

时钟回拨问题

如果你使用了golang1.9+ 并且使用了最新的bwmarrin/snowflake库, 那么这个问题已经不存在了, 详情看这个issue:
https://github.com/bwmarrin/snowflake/issues/20

这是Golang的提案: Proposal: Monotonic Elapsed Time Measurements in Go