如果在一个分布式系统中生成类似于MySQL自增ID这样不断增大, 同时又不会重复的ID,使用传统的单机做法就存在问题了,因为 在分布式系统中,每秒产生10W+的ID,ID每次增1的方式就变得不可取了。 考虑到多节点的情况,分布式并发的情况下可能出现问题。
分布式系统中,对于ID的设计是在保证不重复的情况下又可以排序, 设计思路是在ID中带有一些时间信息,这样即使进行了分库分表,分节点 生成,也能以时间顺序对这些值进行排序。
通用的做法是使用twitter的snowflake算法。snowflake由以下部分组成:
未使用 41位时间戳 datacenter_id sequence_id
↓ ↓ ↓ ↓
| 0 | 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0 | 00000 | 00000| 0000 0000 0000|
↑
worker_id
整个数值的长度是64位,int64类型,被划分为四部分,不含开头的第一个bit,因为这个bit是符号位。用41位来表示收到请求时的时间戳,单位为毫秒,接着五位来表示数据中心的id,后边五位表示机器实例ID,最后的12位为循环自增id。达到111111111111后会归0。
这样的机制可以支持在同一台机器上,同一毫秒产生2^12=4096条消息。一秒产生409.6万个id。从值域的角度来讲是完全够用了。
数据中心加上节点id共有10位,可以支持每个数据中心32台机器,所有数据中心共1024个节点。表示timestamp的41位可以支持使用69年。如果使用1970年的计数方式,那么跑到2039年就不能用了,这里的timestamp是相对一个时间的增量,也就是偏移量。
timestamp
、datacenter_id
、worker_id
和sequence_id
这四个字段中,
timestamp
和sequence_id
是由程序生成的,
datacenter_id
和worker_id
可以真实的对应部署节点和集群的编号,
也可以由程序生成,不同点在于,一旦启动,值就不可更改了,从而解决冲突问题。
如果可以随意修改,可能被不慎修改成重复的值,造成生成的id有冲突。
一般情况下,既可以通过制定id也可以通过程序来给定。
在hubble中也是采用类似于snowflake的生成方法,总体思路就是时间戳+网卡,对于复杂的可能加入了DCE及命名空间等,如果有长短要求的情况下还会有生成短id等不同的处理方式。
github.com/bwmarrin/snowflake
是一个用go语言实现的snowflake包,对各位的定义为:
1位符号位,41位时间戳,10位nodeid,12位序列。和标准的snowflake完全一致。
该包的使用
package main
import (
"fmt"
"os"
"github.com/bwmarrin/snowflake"
)
func main() {
n, err := snowflake.NewNode(1)
if err != nil {
println(err)
os.Exit(1)
}
for i :=0; i < 3; i++ {
id := n.Generate()
fmt.Println("id", id)
fmt.Println(
"node: ", id.Node(),
"step: ", id.Step(),
"time: ", id.Time(),
"\n",
)
}
}
这个库的可定制部分主要是这些长度:
// Epoch is set to the twitter snowflake epoch of Nov 04 2010 01:42:54 UTC
// You may customize this to set a different epoch for your application.
Epoch int64 = 1288834974657
// Number of bits to use for Node
// Remember, you have a total 22 bits to share between Node/Step
NodeBits uint8 = 10
// Number of bits to use for Step
// Remember, you have a total 22 bits to share between Node/Step
StepBits uint8 = 12
Epoch
时间戳,起始时间。NodeBits
机器编号位,StepBits
自增序列长。
现在snowflake各类语言都有自己的实现,重要的是领会其中的逻辑,根据实际情况定制自己的id,同时还要考虑生成效率,多思考,例如,为什么传统的seq不行呢,在分布式系统中传统序列有什么缺陷。