摘要
摘要:分布式id;全局唯一性;Leaf-segment 算法;美团——Leaf;BTree;B+Tree
1 分布式id相关概念
1.1 为什么需要分布式id
为什么需要分布式id?
- ①
全局唯一性问题
:在分布式环境中,存在多节点共同完成一个功能,这些节点会被放在不同物理机上,每个节点都运行一个或多个进程,当某一时刻出现,多个进程同时请求生成id情况,会出现id重复问题。- ②
性能问题
:解决全局唯一性问题关键,就是让id唯一,然而,在分布式系统中,每个节点都需要单独维护自己id,这时候有两种解决方案,第一种,全局使用序列号生成器生成id
(虽然可以保证全局唯一性),但若只有一个节点运行,那么序列号生成器势必会成为性能瓶颈;第二种,使用分布式id思想,让多个节点在同一id空间内生成唯一id,且id唯一,从而保证整个系统的正确与可靠。- ③
趋势递增
:在MySQL InnoDB引擎中使用聚集索引,由于多数RDBMS使用B-tree的数据结构(每个节点都会索引节点和数据节点)存储索引数据,因此,在主键选择上应当选择有序(B-tree是有顺序的,Tree是有顺序的
)主键保证写入性能。- ④
单调递增
:保证下一个id > 上一个id,例如:事务版本号(乐观锁)、排序等特殊要求。- ⑤
信息安全
:若id连续,会造成恶意用户爬取数据工作简单,例如:按照指定URL顺序下载网站数据;若id为订单号,则竞对只需间隔一天时间下单,便可知道平台一天单量,因而,在特定场景下,需要id无规则。
1.1.1 BTree
针对数据节点:
- 在BTree中,每个节点即可是索引节点又可是数据节点,即索引节点与数据节点是一体,节点既存索引,又存储数据。
针对索引节点:
- 在BTree中,索引节点中存储的是索引关键字和指向子节点的指针,每个节点存储的子节点数是固定的,且与键值的个数相同。
1.1.2 B+Tree
针对数据节点:
- 只有叶子节点存储数据,且同一层叶子节点间形成一个有序链表,便于区间查找,而非叶子节点只存储索引关键字和指向孩子节点的指针,不存储数据。
针对索引节点:
- 索引节点中存储的是索引关键字和指向子节点的指针,每个节点可以存储多个子节点的索引关键字和指针,这样可以减少索引节点的数量,提高树的高度和查询效率。
1.1.3 B+Tree相比于BTree优势
- 基于上述对于B+Tree和BTree的论述,B+Tree有更好的磁盘读写性能、更快的查询速度和更高的查询效率,在MySQL和Oracle中都采用B+Tree索引结构优化查询效率。
1.2 什么是分布式id
分布式id:指在分布式环境下,为保证
id全局唯一性
而设计的一种分布式id生成方式。
- 全局唯一:不同机器在不同时间生成id必须唯一,确保整个分布式系统内id唯一性。
- 有序递增:生成id需要具有有序性,便于排序和查询,也方便数据库索引,提高效率。
1.3 常见分布式id生成策略
1.3.1 基于数据库自增id
基于数据库自增id:使用数据库自增id主键生成全局唯一id,适用于单机场景和数据量较小的分布式场景。
1.3.2 基于UUID
基于UUID:使用UUID生成全局唯一id,这种方法适用于分布式环境,但是,有以下缺点
- ① UUID生成id较长,占用存储空间较大,索引不够高效。
1.3.3 Twitter的Snowflake算法
Snowflake算法:Twitter开发的算法,使用64位二进制生成全局唯一id,该算法的核心是将64位的整数分成多个区域,分别代表时间戳、机器id、序列号等信息,具体用位运算实现,在保证全局唯一性同时,保证id的排序和高效索引。
1.3.4 美团的Leaf-segment算法
Leaf-segment算法:美团开发的算法,使用一个一个数据库记录保存当前的id区间,然后将id的生成请求发送给多个服务节点,每个服务节点拿到id区间后,可以在本地生成一定量的id,然后以缓存的方式使用,使用该算法将高并发下的单点性能问题分散到多个节点,通过id生成效率。
1.3.5 ZooKeeper发号器
ZooKeeper发号器:使用ZooKeeper实现分布式锁,使得在多个服务节点同时生成id时,只有一个节点可以进行生成,确保id的唯一性。(但是会造成线程阻塞,影响性能)
1.3.6 Redisson分布式锁
Redisson分布式锁:使用Redisson实现分布式锁,使得在多个服务节点同时生成id时,只有一个节点可以进行生成,确保id唯一性。(但是会造成线程阻塞,影响性能;依赖其他库,为我们带来许多额外工作量)