31

全局唯一ID - snowflake

 4 years ago
source link: https://studygolang.com/articles/24736
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

为什么需要全局唯一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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK