概述
推荐阅读: 分布式ID方案总结
分布式 ID: 又叫全局 ID,负责生成唯一 ID
- 推荐阅读:美团点评分布式ID生成系统
一、UUID 生成
UUID 的标准组成:包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的36个字符
示例:550e8400-e29b-41d4-a716-446655440000
-
优点:性能非常高:本地生成,没有网络消耗
-
缺点:
- 不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用
- 信息不安全:基于 MAC 地址生成 UUID 的算法可能会造成 MAC 地址泄露
- ID 作为主键时在特定的环境会存在一些问题,比如:做DB主键的场景下,UUID就非常不适用:
- MySQL官方有明确的建议主键要尽量越短越好,36个字符长度的UUID不符合要求
- 对MySQL索引不利:若作为数据库主键,在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能
-
自增: ID 生成对数据库依赖严重,而且一旦数据库宕机,服务将变得不可用
-
UUID: 生成的 ID 无序,由于数据库采用 B+ 树,因此入库性能差
二、数据库生成
以 MySQL 举例:利用给字段设置 auto_increment_increment
和 auto_increment_offset
来保证 ID 自增,每次业务使用下列SQL读写 MySQL 得到 ID 号
- 主从模式集群下,当主库挂掉后,数据没有及时同步到从库,会出现 ID 重复现象
- 使用双主模式集群,即两个 Mysql 实例都能单独的生产自增 ID
需要单独给每个 Mysql 实例配置不同的起始值和自增步长,水平扩容困难
优缺点:
- 优点:实现简单,且 ID 自增
- 缺点:
- 强依赖DB,当DB异常时整个系统不可用
- 性能瓶颈限制在单台 MySQL 的读写性能
- 水平扩容困难
配置案例:
- 第一台 Mysql 实例配置:
set @@auto_increment_offset = 1; -- 起始值 set @@auto_increment_increment = 2; -- 步长
- 第二台 Mysql 实例配置:
set @@auto_increment_offset = 2; -- 起始值 set @@auto_increment_increment = 2; -- 步长
三、号段模式
- 号段: 可以理解成批量获取,比如: 从数据库获取 ID 时,批量获取多个 ID 并缓存在本地,大大提高业务应用获取 ID 的效率
比如: 每次从数据库获取 ID 时,就获取一个号段,比如(1,1000],这个范围表示了 1000 个 ID,业务应用在请求 DistributIdService 提供 ID 时,DistributIdService 只需要在本地从 1 开始自增并返回即可,而不需要每次都请求数据库,一直到本地自增到1000时,也就是当前号段已经被用完时,才去数据库重新获取下一号段
对数据库表进行改动:
# 用来记录自增步长以及当前自增ID的最大值
CREATE TABLE id_generator (
id int(10) NOT NULL,
current_max_id bigint(20) NOT NULL COMMENT '当前最大id',
increment_step int(10) NOT NULL COMMENT '号段的长度',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- 优势: 不再强依赖数据库,当数据库不可用,则 DistributIdService 也能继续支撑一段时间
- 缺陷: 如果 DistributIdService 重启,会丢失一段 ID,导致 ID 空洞
- 解决方案:
- 实现一个集群,业务在请求 DistributIdService 集群获取 ID 时,会随机的选择某一个 DistributIdService 节点进行获取
- 利用乐观锁来控制多个 DistributIdService 节点同时请求数据库获取号段
四、Snowflake(雪花算法)
- 漫画:什么是SnowFlake算法
1. Twitter-Snowflake
1bit
保留41bits
时间戳: 支持69.7年需要的 id10bits
work-id: 支持1024个work12bits
sequence-id: 支持每work每毫秒4096个id若当前毫秒超过4096,则sleep 1毫秒,获取下一毫秒的自增
代码推荐阅读: Twitter-Snowflake,64位自增ID算法详解
- 优点:
- 毫秒数在高位,自增序列在低位,整个ID都趋势递增
- 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的性能也非常高
- 可以根据自身业务特性分配 bit 位,非常灵活
- 缺点:强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或服务处于不可用状态
2. Instagram Snowflake
去中性化,基于 PGSQL 实现
64bits从左至右依次是:
41bits
时间戳13bits
logic-shard-id10bits
sequence-id
实现方式:
- 根据share-key获取对应的PGSQL实例-库
- id 使用 PGSQL 的存储过程
13bits = share-key对应值 % logic-share-id
10bits = 该Table的auto_increment_id % (2^10)
好处:
- 去中性化
- 根据 id 可以获得对应 PGSQL 实例-库
3. Simpleflake
64bits
- 去中性化
- 将work-id的12bits给sequence-id。完全随机,每毫秒有1/(2^22 )出现冲突的情况。数据量大时需要注意。
- 未来可以平滑迁移到Twitter SnowFlake
4. Boundary flake
去中性化,基于 erlang 实现
128bits从左到右依次是
64 bits
时间戳: 和毫秒时间戳等长48 bits work-id
: 和mac地址等长,使用时要避免相同mac多个进程14 bits sequence-id
五、Redis 分布式 ID
利用 Redis 中的 incr
命令来实现原子性的自增与返回
六、公司方案
1. 百度(uid-generator)
- uid-generator
2. 美团(Leaf)
- Leaf
最后
以上就是孤独巨人为你收集整理的分布式 ID的全部内容,希望文章能够帮你解决分布式 ID所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复