为什么需要全局唯一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
有疑问加站长微信联系(非本文作者)