优秀是一种习惯!!!
Solo  当前访客:0 开始使用

AmethystFOB

记录精彩人生

表结构设计之主键的选择(1)——避坑UUID

2023-11-28 13:37:45 amethystfob
0  评论    0  浏览

表结构设计之分布式的主键生成策略的选择(1)——避坑UUID

UUID作为主键,再插入数据的时候对于系统的压力是非常大的。如在某个时间点时会出现磁盘的IO异常,导致应用经常出现高延迟。

UUID(全球唯一标识符 Universally Unique Identifier):00000000-0000-0000-0000-000000000000共8+4+4+4+12=32位,业界主要有5中UUID的生成机制:

UUID生成机制

5种UUID的生成机制

基于时间的UUID

  • 能保证不同设备UUID是唯一的

  • 在同一设备上生成UUID可能重复

    利用时间戳 和 设备的具体特性生成唯一编号。
    不同设备上因为其环境不同,可以保证UUID是唯一的。
    但是在极端环境下:同一设备同一毫秒时间下它生成的UUID就可能会出现重复。因此,如果是超高并发的系统,这种情况还不少。

    所以实际开发中不怎么使用基于时间的UUID

DCE安全的UUID

  • DCE(身份验证和安全服务)

  • 涉及侵犯用户隐私

  • 有损时间戳导致精度丢失

    DCE即使用用户的某些特征(用户名、邮箱等相关的身份标识)来生成,欧美广泛抵制。

    所以实际开发中不怎么使用DCE安全的UUID

基于命名空间的UUID(MD5、SH1)

  • 在相同的命名空间下可能会出现UUID冲突
命名空间:为某一组件赋予独特名字,MD5,SH1加密的过程不一样
所以实际开发中不怎么使用基于命名空间的UUID

基于随机数的UUID

  • 完全随机生成,会存在极小概率重复的情况
  • 与外部环境无关,不涉及环境信息
  • 生成内容无序无规律
  • 目前的主流做法

为什么UUID会引起IO异常

UUID模式:1、全局唯一(√) 2、信息安全(√) 3、趋势递增(×) 4、索引效率(×)

因为无序,因此 3 不支持;
如果数据库采用MySQL,尤其是InnoDB,会严重影响索引效率。因为:MySQL默认采用B+Tree索引,索引值和数据是紧密联系的,这种索引也被称为簇集索引。簇集索引最大好处是执行效率很高。

MySQL InnoDB引擎保存数据是以页为单位,一页默认16k。
UUID是无序的,当UUID可能在索引中间某一页插入数据时,新增记录所在的数据页已满,数据库要申请一个新的数据页存储数据,这种现象被称为“页分裂”
页分裂确保新产生的数据页中的所有的ID值一定要比数据页中的ID值大,因为ID在索引中保存是要有序的。
在大并发环境下增加了磁盘IO的压力,无序ID才是罪魁祸首。

当在高并发环境下,某一时间大量产生了“页分裂”,磁盘IO激增,所以应用程序会出现高延迟。

解决办法: 改为有序的数字主键生成策略就可以了

因此结合当前表设计,主要是数据的插入会大量进行,避免出现插入时UUID主键无序导致索引位置对比次数过多导致的高延迟问题。

分布式ID生成算法——雪花算法

读写分离:主表 从表 通过binlog确保两个表的数据是一致的

分库分表肯定不是一个单体应用了,请求 ——> 负载均衡 ——> 集群 ——> 路由 ——> DB1 DB2 ... DBn 这种情况为了防止唯一ID重复,加锁就不行了,做一个唯一的ID分配中心,但是会增加IO网络的传输,每生成一个ID都需要向ID分配中心来获取,高并发场景下,又加锁又网络IO传输效率是非常低的,因此不行。

集群自己内部生成唯一的一个ID,不需要和其他机器进行交互 —— 雪花算法

雪花算法——推特开源的一个分布式ID生成算法。0 00000000……0 0000……0 00000……0 (最高位表示正负 + 41bit时间戳 + 10bit机器ID + 12bit序列号)一个64位的整数。

0表示正数,1表示负数

使用时间由于41bit时间戳限制——69年

通常会把10bit拆分为两个部分——前5个代表哪个机房,后面5个代表在这个机房里的哪个机器id

12bit序列号——代表在同一毫秒内每个机器最多能产生的id的一个数量:2^12-1 即4095个

实现:

1、生成ID的时间戳
2、机器编号ID
3、序列号


标题:表结构设计之主键的选择(1)——避坑UUID
作者:amethystfob
地址:https://newmoon.top/articles/2023/11/27/1701065859371.html

欢迎各路大侠指点留痕:
, ,
TOP