在分布式系统中,为了标识资源的唯一性,需要生成一个全局唯一的ID,插入数据库时好做区分。
常见的生成唯一ID的方式有:
- uuid
- 数据库自增ID
- 号段模式
- Redis
- 类mongodbID
那么作为分布式系统中的ID,有哪些要求呢?
- 全局唯一
- 高性能&&高可用
- 趋势递增,有意义
其中uuid生成的虽然是唯一ID,但没有可读意义,也不适合放到数据库里作主键,不利于检索。
数据库自增ID
需要维护一张表来创建自增ID,当需要获取分布式ID时,往数据库里插入一条数据返回主键ID即可。
优点是实现简单,ID单调递增,数值类型查询快
缺点是DB单点存在宕机风险,也无法应对高并发场景
所有就有了升级版的数据库自增ID
在分布式数据库集群里,如果每个实例的自增ID都从1开始,还是会有重复ID,怎么办呢?
可以设置每个实例的起始ID不同,然后每个实例都次自增的步长一样:1
2
3
4
5
6
7// mysql实例1
set @@auto_increment_offset = 1; -- 起始值
set @@auto_increment_increment = 2; -- 步长
// mysql实例2
set @@auto_increment_offset = 2; -- 起始值
set @@auto_increment_increment = 2; -- 步长
以此类推即可,值得注意的是,如果发生了扩容,需要注意自增ID重复的情况
号段模式
号段模式是当下分布式ID生成器的主流实现方式之一,号段模式可以理解为从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,具体的业务服务将本号段,生成1~1000的自增ID并加载到内存。表结构如下:
1 | CREATE TABLE id_generator ( |
由于多业务端可能同时操作,所以采用版本号version乐观锁方式更新,这种分布式ID生成方式不强依赖于数据库,不会频繁的访问数据库,对数据库的压力小很多。
Redis
利用Redis的inc命令实现ID的原子性自增
关注两点:
- 数据持久化(AOF && RDB)
- 高可用
类mongodbID
mongodb从一开始就设计用来做分布式数据库,为了生成文档的唯一性,objectID至关重要。
ObjectId是一个12字节的 BSON 类型字符串, 5f2cbaecc4cae51411eea431 。按照字节顺序,依次代表:
4字节:UNIX时间戳
3字节:表示运行MongoDB的机器
2字节:表示生成此_id的进程
3字节:由一个随机数开始的计数器生成的值
这样保证了分布式ID的唯一性。
类似的算法有:雪花算法