前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、分布式 Id 问答

1.1、有了数据库自增Id,还不够吗?

⬤ 随着业务数据量的增长,存储在数据库中的数据越来越多,当索引占用的空间超出可用内存大小后,就会通过磁盘索引来查找数据,这样就会极大的降低数据查询速度;

⬤ 如何解决这样的问题呢? 一般我们首先通过分库分表来解决:分库分表后就无法使用数据库自增 ID 来作为数据的唯一编号,那么就需要使用分布式 ID 来做唯一编号了;

1.2、业务系统对ID号的要求

1、全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。

2、趋势递增:在MySQL InnoDB 引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能(我理解这里主要还是说的分库分表后的主键)

3、单调递增:保证下一个 ID 一定大于上一个 ID,例如事务版本号、IM 增量消息、排序等特殊需求。

4、信息安全:如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要ID无规则、不规则。

5、高性能:高可用低延时,ID生成响应要块,否则反倒会成为业务瓶颈

6、高可用: 5999.999%

2、分布式 Id 实现方案

2.1、UUID

public static void main(String[] args) { 
       String uuid = UUID.randomUUID().toString().replaceAll("-","");
       System.out.println(uuid);
 }

2.1.1、生成原理

通用唯一识别码(Universally Unique Identifier,缩写:UUID)是用于计算机体系中以识别信息数目的一个128位标识符,也就是可以通过16个字节来表示。

UUID可以根据标准方法生成,不依赖中央机构的注册和分配,UUID具有唯一性,这与其他大多数编号方案不同。重复UUID码概率接近零,可以忽略不计。

问题1:UUID 有显示几个字符?

答案:显示在由连字符分隔 ‘-‘ 的五个组中,以连字号分为五段,形式为8-4-4-4-12,总共 36 个字符(32 个字母数字字符和 4 个连字符)

123e4567-e89b-12d3-a456-426655440000
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

问题2:UUID占几个字节

答案:UUID的标准型式包含3216进位数字。那么UUID以连字号分为五段,形式为8-4-4-4-1232个字符,加上“-”一共是 36 位,所以咱们可以先取出 uuid,再把 - 去掉就是 16 个字节(一个十六进制数占4位,也就是半个字节,,那么UUID就是16个字节)

2.1.2、优点:

1、生成足够简单

2、ID 唯一(几乎不会产生重复id),但是理论上还是会有重复的

3、本地生成无网络消耗,基本不会有性能问题

2.1.3、缺点:

1、对 MySQL索引不利:无序的字符串,不具备趋势自增特性,如果作为数据库主键,在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能

2、不易于存储:UUID 太长,16 字节128位,通常以36长度的字符串表示,很多场景不适用。

3、信息不安全:基于MAC 地址生成 UUID 的算法可能会造成 MAC 地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置

2.2、SnowFlake 方案

Twitter 利用 zookeeper 实现了一个全局ID生成的服务 Snowflake

image-20210824212608302

2.2.1、生成原理

Snowflake 算法可以做到分配好机器号后就可以使用,不依赖任何第三方服务实现本地 ID 生成; 而依赖的第三方服务越少可用性越高;

ContactAuthor