目录
涉及到分库分表,就会引申出分布式系统中唯一主键的生成问题,因为在单表中我们可以用数据库主键来做唯一ID,但是如果做了分库分表,多张单表中的自增主键就一定会发生冲突。那就不具备全局唯一性了。
那么,如何生成一个全局唯一的ID呢?有以下几种方式:
一、UUID
很多人对UUID都不陌生,它是可以做到全局唯一的,而且生成方式也简单,但是我们通常不推荐使用他做唯一ID,首先UUID太长了,其次字符串的查询效率也比较慢,而且没有业务含义,根本看不懂。
二、基于某个单表做自增主键
多张单表生成的自增主键会发生冲突,但是如果所有的表中的主键都从同一张表生成是不是就可以了。
所有的表在需要主键的时候,都到这张表中获取一个自增的ID。
这样做是可以做到唯一,也能实现自增,但是问题是这个单表就变成整个系统的瓶颈,而且也存在单点问题,一旦他挂了,那整个数据库都无法写入了。
三、基于多个单表 + 步长做自增主键
为了缓解单个数据库做自增主键的瓶颈及单点故障问题,我们可以引入多个表一起来生成就行了。
但是如何保证多张表里面生成的Id不重复呢?如果我们能实现以下的生成方式就行了:
实例1生成的ID从1000开始,到1999结束。 实例2生成的ID从2000开始,到2999结束。 实例3生成的ID从3000开始,到3999结束。 实例4生成的ID从4000开始,到4999结束。
这样就能避免ID重复了,那如果第一个实例的ID已经用到1999了怎么办?那就生成一个新的起始值:
实例1生成的ID从5000开始,到5999结束。 实例2生成的ID从6000开始,到6999结束。 实例3生成的ID从7000开始,到7999结束。 实例4生成的ID从8000开始,到8999结束。
我们把步长设置为1000,确保每一个单表中的主键起始值都不一样,并且比当前的最大值相差1000就行了。
四、雪花算法
雪花算法也是比较常用的一种分布式ID的生成方式,它具有全局唯一、递增、高可用的特点。
雪花算法生成的主键主要由 4 部分组成,1bit符号位、41bit时间戳、10bit工作进程位以及 12bit 序列号位。
时间戳占用41bit,精确到毫秒,总共可以容纳约69年的时间。
工作进程位占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,最多可以容纳1024个节点。
序列号占用12bit,每个节点每毫秒0开始不断累加,最多可以累积到4095,一共可以产生4096个ID。
所以,一个雪花算法可以在同一毫秒内最多可以生成1024 X 4096 = 4194304个唯一的ID