分库分表后全局唯一ID的四种生成策略对比

分库分表之后,ID主键如何处理?

当业务量大的时候,数据库中数据量过大,就要进行分库分表了,那么分库分表之后,必然将面临一个问题,那就是ID怎么生成?因为要分成多个表之后,如果还是使用每个表的自增长ID,意味着每个表都是从1开始累加的,这样肯定是不对的。需要一个全局唯一的ID来支持。所以这也是你实际生产环境中必须考虑的一个问题。全局ID生成器,一般需要满足下列几个特性:

唯一性、高可用、递增性、安全性、高可用性

413f52c7a08ddc586135b60a2c1c3993.png

 

常用的主键ID生成策略有以下几种:

数据库自增ID

原理:

如果使用这种方式,那么这就意味着,你的系统里每次得到一个ID,都需要往一个库中的一个表中插入一条没有什么业务含义的数据,然后获取一个数据库自增的id.拿到这个ID之后,再往对应的分库分表里写。

c3a43d012cf90106d6d1a63eae8b8f62.png

 

这种方式的优缺点如下:

优点:非常简单,有序递增,方便分页和排序。

缺点:

a.分库分表之后,数据表的自增ID容易重复,无法直接使用(虽然可以设置步长,但是局限性明显);

b.性能吞吐量整个比较低。如果设计一个单独的数据库来实现分布式应用的数据唯一性,即使使用预先生成方案,也会因为事务问题,在高并发场景下容易出现单点的瓶颈问题。

使用场景:单数据库实例的表ID(包含主从同步场景);部分按天计数的流水号等

在分不分表场景、全局唯一性ID场景下不使用。

Redis生产全局ID

原理:

通过Redis的INCR/INCRBY自增原子操作命令,能保证生产的ID肯定是唯一的序列号,本质上实现方式与数据库一致的。

2ba2ef16c94fd5c1c78e127cf65642dc.png

使用Redis生产全局ID的优缺点:

本文由凯哥Java(公众号:kaigejava),个人博客:www.kaigejava.com 发布于博客园.

 

凯哥自己开发的,领取外卖、打车、咖啡、买菜、各大电商的优惠券的公¥众¥号。如下图:

527c8a82983e56a30f4299fc76e1956a.png

优点:整体吞吐量比数据库要高。因为Redis的吞吐量性能高于数据库

缺点:Redis实例或者集群宕机后,找回最新的ID值比较麻烦。但是可以在生产唯一ID的算法上进行优化,避免这种情况。

使用场景:比较适合计算场景。比如用户访问量、订单流水号(日期+流水号)等。

凯哥推荐文章:Redis实战9-全局唯一ID

UUID、GUID生成ID

 

优缺点:

优点:性能非常高。在本地生成,没有网络消耗;

缺点:UUID太长了,占用空间大,作为主键性能太差了;

由于UUI不具有有序性,会导致B+树索引在写的时候有过多的随机写操作。

使用场景:如果你要随机生成一个什么文件名称、编号之类的,可以考虑使用UUID,但是如果是作为数据库的主键,不建议使用UUID的。

雪花算法(snowflake)

雪花算法来源于Twitter,使用Scala语言实现,雪花算法的特性是有序、唯一且要求性能高,低延迟(每台集群每秒至少生成10K条数据,并且响应时间在2MS内),要在分布式环境(多集群、跨机房)下使用。因此雪花算法得到的ID是分段组成的。

a.与指定日期时间差(时间差到毫秒级)的,41位数字,可以使用69年;

b.机器ID+集群ID,10位,最多支持1024台机器;

c.序列号,12位。每台机器每毫秒内最多生产4096个序列号.

雪花算法的核心思想是:

分布式ID固定是一个long类型的数字,一个long类型占用8个字节,也就是8*8=64个bit位。所以,雪花算法的格式如下图:

42e2b28690ba0bf1dabb5bdf96898e62.png

雪花算法分段,每段含义:

第一段:也就是最高1位是符号位。固定值,就是0,标识全部ID都是正整数。

第二段:接下来的41位,标识的是时间戳。单位是毫秒。41bits标识的数字对应的是2^41次方-1.也就是可以标识2的41次方-1个毫秒值。换算成年就是标识69年的时间;

第三段:再接下来的10位标识的是机器ID。如果有异地部署,多集群的也可以配置,需要在线下提前规划好各地机房,各个集群,实例ID的编号。其中包括5位的机器id和5位的集群id.最多可以部署2^10台机器。也就是1024台。

第四段:最后12位是序列号。用于记录同一毫秒内产生的不同ID.12个比特位可以代表的最大正整数是2^12-1=4096.也就是说,可以用这12个bits代表数字来区分同一毫秒内4096个不同的ID.

此算法的优缺点如下:

雪花算法的优缺点:

优点:毫秒数在高位,自增序列在低位,所以整个ID都呈现出递增趋势;

不依赖数据库等三方系统,以服务部署方式,稳定性更高,生成ID的性能也是非常高的;

可以根据自身业务特性来分配bit位,非常灵活。

缺点:

太依赖集群的时钟,如果机器时钟回拨了,可能会导致重复或者服务处于不可用。

 

结束语

大家好,我是凯哥Java(kaigejava),乐于分享技术文章,欢迎大家关注“凯哥Java”,及时了解更多。让我们一起学Java。也欢迎大家有事没事就来和凯哥聊聊~~~

 



 

posted @ 2023-02-02 09:04  kaizi1992  阅读(174)  评论(0编辑  收藏  举报