浅析分布式ID生成方案

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

高并发情况下的数据库自增ID会出现重复情况,导致新增失败。
解决办法就是使用分布式ID

分布式ID的生成方式有以下几种

  • UUID
  • 数据库不同步长自增
  • 雪花算法
  • redis
  • 滴滴出品(TinyID)
  • 百度 (Uidgenerator)
  • 美团(Leaf)

常用.png

UUID

生成唯一ID,最简单的就是UUID,具有唯一性,但是结果太长了,保存在数据库中,会导致索引太大,消耗太大。

数据库不同步长自增ID

设置起始值和自增步长,就可以保证唯一ID是自增有序,而且还不会重复,缺点就是不利于扩容,增加维护成本。

  • mysql 1 配置:
1
2
sql复制代码set @@auto_increment_offset = 1;     -- 起始值
set @@auto_increment_increment = 2; -- 步长
  • mysql 2 配置:
1
2
sql复制代码set @@auto_increment_offset = 2;     -- 起始值
set @@auto_increment_increment = 2; -- 步长

雪花算法(Snowflake)

雪花算法(Snowflake)是twitter公司内部分布式项目采用的ID生成算法,理论上单机每秒400W+,最多每秒可以生成41亿+的ID

snow.png

分段 作用 说明
1bit 保留
41bit 时间戳,精确到毫秒 可以支持69年的跨度
5bit DatacenterId 可以最多支持32个节点
5bit WorkerId 可以最多支持32个节点
12bit 毫秒内的计数 支持每个节点每毫秒产生4096个ID
  • 优点
    • ID趋势递增
    • 生成效率高,单机每秒400W+
    • 支持线性扩充
    • 稳定性高,不依赖DB等服务
  • 缺点
    • 依赖服务器时间,如果服务器时间发生回拨,可能导致生成重复ID
    • 在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,也许有时候也会出现不是全局递增的情况

Redis生成ID

Redis可以作为集中式ID生成器,数据库的表记录最后分配的ID也是集中式ID生成器。
目前使用的ID生成器结合了这两种,实现如下:

  • redis累加器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码public int getId() {
// 获取redis累加器,累加获得id
int id = 1;
// 判断key是否存在
if (stringRedisLettuceTemplate.hasKey("message:id")) {
// 如果存在key则直接获取后进行累加
id = Integer.valueOf(stringRedisLettuceTemplate.boundValueOps("message:id").get());
stringRedisLettuceTemplate.opsForValue().increment("message:id", 1);
} else {
// 如果不存在,查询数据库最后一条,获取后+1
id = userDao.getLastId() + 1;
// 再次+1后存入redis
stringRedisLettuceTemplate.opsForValue().set("message:id", String.valueOf(id + 1));
}
return id;
}
  • 数据库
1
2
3
4
5
6
xml复制代码<select id="getLastId" resultType="java.lang.Integer">
SELECT IFNULL(id, 0) AS id
FROM user
ORDER BY id desc
limit 1
</select>

参考

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%