ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

分布式唯一ID设计方案

2021-07-31 21:30:30  阅读:180  来源: 互联网

标签:leaf 数据库 ID 设计方案 时间 时钟 节点 分布式


方案汇总:

  1.  UUID:
    结合机器的网卡(基于名字空间/名字的散列值MD5/SHA1)、当地时间(基于时间戳&时钟序列)、一个随记数来生成UUID。结构: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
    优点:结合机器的网卡(基于名字空间/名字的散列值MD5/SHA1)、当地时间(基于时间戳&时钟序列)、一个随记数来生成UUID。结构: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
    缺点:

    ① UUID太长。

    ② 信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露。

    ③ 无序查询效率低:由于生成的UUID是无序不可读的字符串,所以其查询效率低
  2. 数据库自增
    使用数据库的id自增策略,数据库进行水平拆分,每个数据库设置不同的初始值和相同的自增步长
    优点:
    使用数据库的id自增策略,数据库进行水平拆分,每个数据库设置不同的初始值和相同的自增步长
    缺点:

    ① 方案实现复杂

    ②扩容复杂

    ③高可用问题,数据库故障后不可使用。

    ④ 存在数据泄露风险
  3. 号段模式
    每次获取一个segment(step决定大小)号段的值。用完之后再去数据库获取新的号段,可以大大的减轻数据库的压力
    优点:
    每次获取一个segment(step决定大小)号段的值。用完之后再去数据库获取新的号段,可以大大的减轻数据库的压力
    缺点:

    ID号码不够随机,能够泄露发号数量的信息,不太安全

    TP999数据波动大

    DB宕机会造成整个系统不可用

  4. Redis
    Redis的所有命令操作都是单线程的,本身提供像 incr 和 increby 这样的自增原子命令,所以能保证生成的 ID 肯定是唯一有序的
    优点:

    ① 不依赖于数据库,灵活方便,且性能优于数据库。

    ② 数字ID天然排序,对分页或者需要排序的结果很有帮助。

    缺点:

    ① 如果系统中没有Redis,还需要引入新的组件,增加系统复杂度。

    ② 需要编码和配置的工作量比较大。

  5. 雪花算法

    优点:

    ①整体上按照时间按时间趋势递增。

    ②全局唯一(由数据中心标识ID、机器标识ID作区分) ③本地生成,不依赖db,中间件,高性能。

    缺点:

    ①强依赖于时间,发生时钟回拨,可能会引起ID重复。

    ② 天然并发限制。
    Snowflake 实现的难点?

  6. 百度UidGenerator

1. 实例启动的时候,往这个表中插入一行数据,得到的 id 值就是 workerId 的值 2. 扩展: 实现 WorkerIdAssigner.java 接口 ,自定义 workerID 的生成

 默认实现DefaultUidGenerator

• 时钟回拨抛异常 • • 天然的并发限制没有解决,同一秒内超出最大序列,等待下一秒

 

    时钟回拨问题及并发限制问题解决

CachedUidGenerator-buffer初始化

CachedUidGenerator-buffer填充uid 

 

  

 •workerId:UidGenerator的workerId在实例每次重启时初始化,且就是数据库的自增ID,从而完美的实现每个实例获取到的workerId不会有任何冲突。解决了服务重启大步长时钟回拨引发的问题。

天然并发限制:UidGenerator不再在每次取ID时都实时计算分布式ID,而是利用RingBuffer数据结构预先生成若干个分布式ID并保存。QPS可达600万。

• • 时间递增 : 传统的雪花算法实现都是通过 System.currentTimeMillis () 来获取时间并与上一次时间进行比较,这样的实现严重依赖服务器的时间。而 UidGenerator 的时间类型是 AtomicLong , 且通过 incrementAndGet () 方法获取下一次的时间,从而脱离了对服务器时间的依赖,也就不会有时钟回拨的问题。解决了程序运行时的时钟回拨问题。

 
7. 美团leaf-snowflake

• 完全沿用 snowflake 方案的 bit 位设计 • • 使用 Zookeeper 持久顺序节点的特性自动对 snowflake 节点配置 wokerID • • zk 持久顺序 节点: ip:port-000000001 value: {"ip":"192.168.1.1","port":"80","timestamp":1624428405410}

       Leaf-snowflake启动步骤 

• 启动 Leaf-snowflake 服务,连接 Zookeeper , 在 leaf_forever 父节点下检查自己是否已经注册过(是否有该顺序子节点)。 • 如果有注册过直接取回自己的 workerID ( zk 顺序节点生成的 int 类型 ID 号),启动服务。 • 如果没有注册过,就在该父节点下面创建一个持久顺序节点,创建成功后取回顺序号当做自己的 workerID 号,启动服务。
弱依赖 ZooKeeper
除了每次会去ZK 拿数据以外,也会在本机文件系统上缓存一个 workerID 文件。当 ZooKeeper 出现问题,恰好机器出现问题需要重启时,能保证服务能够正常启动。这样做到了对三方组件的弱依赖

 
        时钟回拨
     

1. 若写过,则用自身系统时间与 leaf_forever /${self} 节点记录时间做比较,若小于 leaf_forever /${self} 时间则认为机器时间发生了大步长回拨,服务启动失败并报警。 ● 2. 若未写过,证明是新服务节点,直接创建持久节点 leaf_forever /${self} 并写入自身系统时间,接下来综合对比其余 Leaf 节点的系统时间来判断自身系统时间是否准确,具体做法是取 leaf_temporary 下的所有临时节点 ( 所有运行中的 Leaf-snowflake 节点 ) 的服务 IP : Port , 然后通过 RPC 请求得到所有节点的系统时间,计算 sum(time)/ nodeSize 。 ● 3. 若 abs( 系统时间 - sum(time)/ nodeSize ) < 阈值,认为当前系统时间准确,正常启动服务,同时写临时节点 leaf_temporary /${self} 维持租约。 ● 4. 否则认为本机系统时间发生大步长偏移,启动失败并报警。 ● 5. 每隔一段时间 (3 s) 上报自身系统时间写入 leaf_forever/${self}。

优点:
缺点: 

  • workerId不能重复使用,可能会超过1024
  • 时钟回拨问题只是提供了方案,代码层面并未提供
    zk,成本较高
  • 存在天然并发限制
  • 需要独立部署,依赖zk,成本较高
    ​​​​​​​

    8、其他
    ​​​​​​​思路: • ip 累加、 workerId 重复后、获取随机 workerId • 依赖jimdb

    bit 位设计
  • 沿用snowflake方案bit位设计
    1+41+10+12

     

    参考文献:

    https://tech.meituan.com/2017/04/21/mt-leaf.html

    https://github.com/Meituan-Dianping/Leaf

    https://github.com/Meituan-Dianping/Leaf/pull/94

    https://github.com/baidu/uid-generator

 

标签:leaf,数据库,ID,设计方案,时间,时钟,节点,分布式
来源: https://blog.csdn.net/qq_30757161/article/details/119281357

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有