我是靠谱客的博主 孤独巨人,最近开发中收集的这篇文章主要介绍分布式 ID,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

推荐阅读: 分布式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_incrementauto_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年需要的 id
  • 10bits work-id: 支持1024个work
  • 12bits sequence-id: 支持每work每毫秒4096个id

    若当前毫秒超过4096,则sleep 1毫秒,获取下一毫秒的自增

代码推荐阅读: Twitter-Snowflake,64位自增ID算法详解

  • 优点:
    • 毫秒数在高位,自增序列在低位,整个ID都趋势递增
    • 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的性能也非常高
    • 可以根据自身业务特性分配 bit 位,非常灵活
  • 缺点:强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或服务处于不可用状态

2. Instagram Snowflake

去中性化,基于 PGSQL 实现

64bits从左至右依次是:

  • 41bits 时间戳
  • 13bits logic-shard-id
  • 10bits 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所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部