golang项目中实现的全局唯一id生成器

在应用程序中,经常需要全局唯一的ID作为数据库主键。在一台节点容易全局唯一,那在多台节点呢?

有两个思路:

  • 1使用散列函数,如sha256,加上时间戳、mac地址、cpu负荷、随机数等组成,id足够长,引入多个不确定因素,以至于碰撞几率非常小,可以认为是全局唯一。例如uuid就是这种。但是uuid是字符串的形式,对于DB来说,占用的空间至少大一倍,DB的索引是需要存储和对比的,因此在存储空间和查询时间上面都比整形要低,这种情况在DB的数据条数越多时越明显。
  • 2使用分割法。每个节点都保证自己生成的所有id在本机唯一,每个节点都有一个人为分配的不重复节点编号,插入id中,这样所有节点的id都是全局唯一的。
  • 3利用DB自带的主键唯一性来确保id唯一。但是db的自增id是需要等到事务提交后,ID才算是有效的。有些双向引用的数据,不得不插入后再做一次更新,比较麻烦。

第二种方式是类似Twitter的Snowflake算法,它给每台机器分配一个唯一标识,然后通过时间戳+标识+自增实现全局唯一ID。这种方式好处在于ID生成算法完全是一个无状态机,无网络调用,高效可靠。缺点是如果唯一标识有重复,会造成ID冲突。
Snowflake算法采用41bit毫秒时间戳,加上10bit机器ID(最多支持1024台id服务器),加上12bit序列号,理论上最多支持1024台机器每秒生成4096000个序列号。409万个id每秒,在任何交易平台目前都是够用的。

推特的id构成(从最高位往最低位方向):

  • 1位 ,不用。固定是0
  • 41位 ,毫秒时间戳
  • 5位 ,数据中心ID (用于对数据中心进行编码)
  • 5位 ,WORKERID (用于对工作进程进行编码)
  • 12位 ,序列号。用于同一毫秒产生ID的序列 (自增id)

下面是用golang实现的uuid方法(uuid类型为整形):

package main

import (
	"fmt"

	idworker "github.com/gitstliu/go-id-worker"
)

func main() {
	currWoker := &idworker.IdWorker{}
	currWoker.InitIdWorker(1000, 1)
	newID, err := currWoker.NextId()
	if err == nil {
		fmt.Println(newID)
	}
}

下载库

go get github.com/gitstliu/go-id-worker

下面是在vscode中的调试结果

API server listening at: 127.0.0.1:4442
4917572028174794752
Process exiting with code: 0

用mysql自带的自增id生成全局唯一id


发布了89 篇原创文章 · 获赞 72 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/jacky128256/article/details/104687772