10.雪花算法用户ID
# 01.分布式ID成器
# 1.1 分布式ID的特点
全局唯⼀性:不能出现有重复的ID标识,这是基本要求。
递增性:确保⽣成ID对于⽤户或业务是递增的。
⾼可⽤性:确保任何时候都能⽣成正确的ID。
⾼性能性:在⾼并发的环境下依然表现良好。
# 1.2 分布式ID应用场景
- 不仅仅是⽤于⽤户ID,实际互联⽹中有很多场景需要能够⽣成类似MySQL⾃增ID这样不断增⼤,同时⼜不会重复的id。
- 以⽀持业务中的⾼并发场景。
- ⽐较典型的场景有:电商促销时短时间内会有⼤量的订单涌⼊到系统,⽐如每秒10w+;
- 明星出轨时微博短时间内会产⽣⼤量的相关微博转发和评论消息
- 在这些业务场景下将数据插⼊数据库之前,我们需要给这些订单和消息先分配⼀个唯⼀ID,然后再保存到数据库中。
- 对这个id的要求是希望其中能带有⼀些时间信息
- 这样即使我们后端的系统对消息进⾏了分库分表,也能够以时间顺序对这些消息进⾏排序。
# 02.雪花算法介绍
# 2.1 snowflake算法
- 雪花算法,它是Twitter开源的由64位整数组成分布式ID,性能较⾼,并且在单机上递增
# 2.2 四个站位说明
1.第一位 占1 bit,
其值始终是0,没有实际作用。2.时间戳 占41 bit,
单位为毫秒,总共可以容纳约69年的时间。- 当然,我们的时间毫秒计数不会真的从1970年开始记
- 那样我们的系统跑到 2039/9/7 23:47:35 就不能了,
- 所以这里的时间戳只是相对于某个时间的增量,比如我们的系统上线是2020-07-01,
3.工作机器id 占10 bit
,其中高位5bit是数据中心ID,低位5bit是工作节点ID最多可以容纳1024个节点。4.序列号 占12 bit
,用来记录同毫秒内产⽣的不同id。- 每个节点每毫秒0开始不断累加,最多可以累加到4095,同一毫秒一共可以产生4096个ID。
- SnowFlake算法在同一毫秒内最多可以生成多少个全局唯一ID呢?
- 同一毫秒的ID数量 = 1024 X 4096 = 4194304
# 03.snowflake的Go实现
package main
import (
"fmt"
"github.com/bwmarrin/snowflake"
"time"
)
var node *snowflake.Node
func Init(startTime string, machineID int64) (err error) {
var st time.Time
st, err = time.Parse("2006-01-02", startTime)
if err != nil {
return
}
snowflake.Epoch = st.UnixNano() / 1000000
node, err = snowflake.NewNode(machineID)
return
}
func GenID() int64 {
return node.Generate().Int64()
}
func main() {
if err := Init("2020-07-01", 1); err != nil {
fmt.Printf("init failed, err:%v\n", err)
return
}
id := GenID()
fmt.Println(id) // 125946957477711872
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 04.gin中使用snowflake
# 1.1 pkg/snowflake/snowflake.go
package snowflake
import (
sf "github.com/bwmarrin/snowflake"
"time"
)
var node *sf.Node
func Init(startTime string, machineID int64) (err error) {
var st time.Time
st, err = time.Parse("2006-01-02", startTime)
if err != nil {
return
}
sf.Epoch = st.UnixNano() / 1000000
node, err = sf.NewNode(machineID)
return
}
func GenID() int64 {
return node.Generate().Int64()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1.2 conf/config.yaml
start_time: "2020-07-01"
machine_id: 1
1
2
2
# 1.3 settings/settings.go
type AppConfig struct {
Name string `mapstructure:"name"`
Mode string `mapstructure:"mode"`
Version string `mapstructure:"version"`
Port int `mapstructure:"port"`
StartTime string `mapstructure:"start_time"`
MachineID int64 `mapstructure:"machine_id"`
*LogConfig `mapstructure:"log"`
*MySQLConfig `mapstructure:"mysql"`
*RedisConfig `mapstructure:"redis"`
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1.4 main.go
func main() {
// 初始化,雪花算法
if err := snowflake.Init(settings.Conf.StartTime, settings.Conf.MachineID); err != nil {
fmt.Printf("init snowflake failed, err:%v\n", err)
return
}
// fmt.Println("使用雪花算法获取用户ID:", snowflake.GenID())
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
上次更新: 2024/3/13 15:35:10