为什么需要分布式ID?
-
分布式ID需要满足哪些条件:
- 全局唯一
必须保证ID是全局性唯一的,基本要求 - 高性能
高可用低延时,ID生成响应要块,否则会成为业务瓶颈 - 高可用
- 好接入
要秉着拿来即用的设计原则,在系统设计和实现上要尽可能的简单 - 趋势递增(不严格要求)
最好趋势递增,这个要求就得看具体业务场景了,一般不严格要求
- 全局唯一
UUID
UUID 全称:Universally Unique Identifier,即通用唯一识别码
UUID 是有一组32位的16进制数字构成,总数为,也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。
UUID由以下几部分组成:
- 当前的日期和时间
- 时钟序列
- 全局唯一的机器识别号:比如网卡mac地址
Linux 下使用命令生成UUID:
# uuidgen
53dbaf1c-1996-4dcc-8517-f17155d7c54a
或者使用:
# cat /proc/sys/kernel/random/uuid
- 短UUID
雪花算法
雪花算法(Snowflake)是 twitter 公司内部分布式项目采用的ID生成算法。
Snowflake 生成的是long
类型的ID,一个long
类型占8个字节。
Snowflake ID组成结构:
正数位(占1比特)
一般生成ID都为正数,所以默认为0。时间戳(占41比特)
毫秒级的时间,不建议存当前时间戳,相对于某个时间的增量,比如我们的系统上线时间是 2018-08-01,那就把这个值相对于 2018-08-01 00:00:00 的偏移量。-
机器ID
可以灵活配置,比如 数据中心(占5比特)+ 机器(占5比特),这样可以支持每个数据中心部署32台机器,所有数据中心共1024台实例。数据中心和机器实例ID,需要我们在部署阶段就能够获取到,并且一旦程序启动之后,就不可再更改了。一般数据中心的机器,会提供相应的获取数据中心ID的API,所以我们可以很轻易获取数据中心ID,而 机器实例ID 是我们逻辑上给机器分配的ID,比较简单的想法是使用能够提供自增ID功能的工具来支持,例如MySQL。但是,使用了MySQL 相当于给简单的ID生成服务增加了一个外部依赖。依赖越多,服务的可运维性越差。
自增值(占12比特)
自增值支持同一毫秒内同一个节点可以生成4096个ID,1秒内共产生409.6万条消息。基本上,这个完全够用了。
开源实现: http://github.com/bwmarrin/snowflake,是一个标准的Go实现
import (
"fmt"
"github.com/bwmarrin/snowflake"
)
func main() {
n, err := snowflake.NewNode(1)
if err != nil {
}
for i := 0; i < 3; i++ {
id := n.Generate()
fmt.Println(
"node: ", id.Node(),
"step: ", id.step(),
"time: ", id.Time(),
"\n",
)
}
}
这个库也留下了好的定制的字段:
// 起始时间
Epoch int64 = 1288834974657
// 机器编号的位长
NodeBits uint8 = 10
// 自增序列的位长
StepBits uint8 = 12
参考资料:
1、https://zhuanlan.zhihu.com/p/107939861
2、https://zhuanlan.zhihu.com/p/62494795