vlambda博客
学习文章列表

[精选]分库分表之后,id 主键如何处理?如何保持全局唯一


文章来自:https://baijiahao.baidu.com/s?id=1670209783636634933









精选文章正文

你知道为什么要分库分表?

随着业务的不断发展,数据量将越来越大,ID作为系统数据的重要标识,如果一个库中的表数据超过了一定的数量,比如说mysql中的表数据达到千万级别,那就要考虑进行分库分表了,

当数据库实例的吞吐量达到性能的瓶颈时,我们需要扩展数据库实例,让每个数据库实例承担其中一部分数据库的请求,分解总体的大请求量的压力;

在数据库进行扩容的时候对应用层的配置改变最少, 就需要在每个数据库实例中预留足够的数据库数量

以上的情况我们都可以使用分库分表,那么什么是分库分表呢?

就是数据拆分:将一个表数据分片后放入多个表中。这样会引发新的问题,比如,分库分表后每个表的数据都会根据自己表的ID进行自增,导致出现ID的冲突,那么有哪些方案可以觉得这种问题的出现呢?下面来看看!


1、数据库自增长ID

这个就是说你的系统里每次得到一个 id,都是往一个库的一个表里插入一条没什么业务含义的数据,然后获取一个数据库自增的一个 id。拿到这个 id 之后再往对应的分库分表里去写入。

这个方案的好处就是方便简单,谁都会用;

缺点就是单库生成自增 id,要是高并发的话,就会有瓶颈的;如果你硬是要改进一下,那么就专门开一个服务出来,这个服务每次就拿到当前 id 最大值,然后自己递增几个 id,一次性返回一批 id,然后再把当前最大 id 值修改成递增几个 id 之后的一个值;但是无论如何都是基于单个数据库。

适合的场景:你分库分表就俩原因,要不就是单库并发太高,要不就是单库数据量太大;除非是你并发不高,但是数据量太大导致的分库分表扩容,你可以用这个方案,因为可能每秒最高并发最多就几百,那么就走单独的一个库和表生成自增主键即可。


2、Redis生成ID

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

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

缺点:Redis实例或集群宕机后,找回最新的ID值比较麻烦。

优点:整体吞吐量比数据库要高。


3、UUID、GUID生成ID

适合的场景:如果你是要随机生成个什么文件名、编号之类的,你可以用 UUID,但是作为主键是不能用 UUID 的。

UUID.randomUUID().toString().replace("-", "")
e444d1431da3403698af9f5d86210527

优点就是本地生成,不要基于数据库来了;

缺点UUID 太长了,作为主键性能太差了,另外 UUID 不具有有序性,会造成 B+ 树索引在写的时候有过多的随机写操作,频繁修改树结构,从而导致性能下降。


4 snowflake(雪花)算法

snowflake 算法是 twitter 开源的分布式 id 生成算法,就是把一个 64 位的 long 型的 id,1 个 bit 是不用的,用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。

与指定日期的时间差(毫秒级),41位,够用69年集群ID + 机器ID, 10位,最多支持1024台机器序列,12位,每台机器每毫秒内最多产生4096个序列号

雪花算法核心思想是:分布式ID固定是一个long型的数字,一个long型占8个字节,也就是64个bit,原始snowflake算法中对于bit的分配

如下图:

  • 1 bit:不用,为啥呢?因为二进制里第一个 bit 为如果是 1,那么都是负数,但是我们生成的 id 都是正数,所以第一个 bit 统一都是 0。


  • 41 bit:表示的是时间戳,单位是毫秒。41 bit 可以表示的数字多达 2^41 - 1,也就是可以标识 2^41 - 1 个毫秒值,换算成年就是表示69年的时间。

  • 10 bit:记录工作机器 id,代表的是这个服务最多可以部署在 2^10台机器上哪,也就是1024台机器。但是 10 bit 里 5 个 bit 代表机房 id,5 个 bit 代表机器 id。意思就是最多代表 2^5个机房(32个机房),每个机房里可以代表 2^5 个机器(32台机器)。

  • 12 bit:这个是用来记录同一个毫秒内产生的不同 id,12 bit 可以代表的最大正整数是 2^12 - 1 = 4096,也就是说可以用这个 12 bit 代表的数字来区分同一个毫秒内的 4096 个不同的 id。


缺点:

强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。

优点:

毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。

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

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


总结:

snowflake 算法相对其他三个方法来说还是比较靠谱的,要是搞分布式 id 生成,如果是高并发的,那么建议采用这个应该性能比较好,一般每秒几万并发的场景,足够用了。

关于如何生成分布式ID,平时工作中要注意总结和积累,查漏补缺,不断完善自己的知识体系。



以上是本文的全部内容,希望对大家的学习有帮助,也希望大家多多支持php自学中心