文章目录

  • 背景
  • 常见实现方案
    • UUID
      • 优势
      • 缺点
      • 应用
    • 类SnowFlake方案
      • 优点
      • 缺点
      • 应用
    • 数据库生成
      • 优点
      • 缺点
    • MySQL 增强版
      • 优点
      • 缺点
    • Leaf -segment方案
      • 优点
      • 缺点
    • Leaf -segment方案-双Buffer优化
      • 优点
      • 缺点
    • Leaf -snowflake方案
      • 弱依赖ZK
      • 时钟同步问题
      • 优点
      • 缺点
    • 参考文档

背景

阅读了美团的ID生成器架构设计,记个笔记,同时强烈推荐阅读原文;
业务系统对ID号的要求有:

  1. 全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。
  2. 趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。
  3. 单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求。
  4. 信息安全:如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要ID无规则、不规则。

3和4需求还是互斥的,无法使用同一个方案满足。

业务还对ID号生成系统的可用性要求极高,由此总结下一个ID生成系统应该做到如下几点:

  1. 平均延迟和TP999延迟都要尽可能低;
  2. 可用性5个9;
  3. 高QPS。

常见实现方案

UUID

UUID(Universally Unique Identifier)的标准型式包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的36个字符;

优势

性能高,本地生成,没有网络消耗;

缺点

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

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

ID作为主键时在某些场景不适用;比如做DB主键的场景下,UUID就非常不适用;而且UUID的无序性会导致数据位置在MySQL索引中频繁变动;

应用

类SnowFlake方案

是一种以划分命名空间(UUID也算,由于比较常见,所以单独分析)来生成ID的一种算法,这种方案把64-bit分别划分成多段,分开来标示机器、时间等;理论上snowflake方案的QPS约为409.6w/s,这种分配方式可以保证在任何一个IDC的任何一台机器在任意毫秒内生成的ID都是不同的。

第一bit不用,41-bit的时间可以表示(1L<<41)/(1000L360024*365)=69年的时间,10-bit机器可以分别表示1024台机器【如果我们对IDC划分有需求,还可以将10-bit分5-bit给IDC,分5-bit给工作机器,这样就可以表示32个IDC,每个IDC下可以有32台机器,可以根据自身需求定义】,12个自增序列号可以表示2^12个ID;

优点

ID趋势递增,毫秒数在高位,自增序列在低位;

不依赖数据库等第三方系统,本地生成,稳定性高,性能也高;

分配灵活,根据自身业务特性分配bit位;

缺点

强依赖机器时钟,机器上的时钟回拨会导致ID重复或者服务不可用;

应用

MongoDB的objectID,通过“时间+机器码+pid+inc”共12个字节,通过4+3+2+3的方式最终标识成一个24长度的十六进制字符。

数据库生成

以MySQL举例;利用给字段设置auto_increment_incrementauto_increment_offset来保证ID自增,每次业务使用下列SQL读写MySQL得到ID号

begin;
REPLACE INTO Tickets64 (stub) VALUES (‘a’);
SELECT LAST_INSERT_ID();
commit;

replace into 跟 insert 功能类似,不同点在于:replace into 首先尝试插入数据到表中, 1. 如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据。 2. 否则,直接插入新数据。

要注意的是:插入数据的表必须有主键或者是唯一索引!否则的话,replace into 会直接插入数据,这将导致表中出现重复的数据。

优点

成本小,简单,通过MySQL就能实现;

ID号自增,在特殊场景下这也是优势;

缺点

强依赖DB,当DB异常时整个系统不可用;

DB主从切换时可能导致数据不一致,ID重复;

性能瓶颈在单台MySQL;

MySQL 增强版

N台机器,每台机器的步长需设置为N,每台的初始值依次为0,1,2…N-1;

优点

缺点

系统水平扩展很难;机器台数和步长确定后,扩容麻烦;

ID不能单调递增,只能趋势递增;

数据库压力依旧很大,每次获取ID都需要读写一次数据库;

或许可以通过预生成来减少数据库的压力;比如数据库预先生产千万级的数据到缓存中,业务先从缓存读取ID,缓存没有了再去数据库中读取;数据库中数据批量追加到缓存中;

Leaf -segment方案

Leaf分别在上述第二种和第三种方案上做了相应的优化,实现了Leaf-segment和Leaf-snowflake方案。

通过proxy server批量获取,每次获取一个segment(step决定大小)号段的值,用完后再去数据库中取;同时不同业务通过biz_tag字段区分,每个biz_tag的ID获取,互相隔离;

扩容通过biz_tag分库分表即可;

±------------±-------------±-----±----±------------------±----------------------------+
| Field | Type | Null | Key | Default | Extra |
±------------±-------------±-----±----±------------------±----------------------------+
| biz_tag | varchar(128) | NO | PRI | | |
| max_id | bigint(20) | NO | | 1 | |
| step | int(11) | NO | | NULL | |
| desc | varchar(256) | YES | | NULL | |
| update_time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
±------------±-------------±-----±----±------------------±----------------------------+

biz_tag用来区分业务,max_id表示biz_tag目前被分配的ID号段的最大值,step表示每次分配的号段长度;(比如step为1000,那么当1000取完了才去数据库中读取)

架构设计:

Begin
UPDATE table SET max_id=max_id+step WHERE biz_tag=xxx
SELECT tag, max_id, step FROM table WHERE biz_tag=xxx
Commit

优点

leaf服务扩容方便,性能能支撑大多数业务场景;

ID号码是趋势递增的8bytes的64位数字,用MySQL就能满足;

容灾性高,leaf内部有号段缓存,即使DB宕机段时间内服务仍然可用;

迁移性好,max_id可变,迁移方便;

缺点

ID号码不够随机,不太安全;

TP999数据波动大,当号段使用完之后还是会hang在更新数据库的I/O上,所以TP999会出现尖刺;

DB宕机会导致系统不可用;

Leaf -segment方案-双Buffer优化

leaf取号段的时机是在号段消耗完才进行的;也就是当前号段的上界点的ID下发时间是下一号段的取回号段时间,过程中新的拉取ID请求需要等待(线程阻塞),特别是取DB的时候网络的抖动或者DB的慢查询会导致整个系统的响应时间变慢;

本架构设计在号段消耗完前,提前预拉取下一号段的数据;

内存中同时存在2个号段数据,号段通过异步线程滚动前进;

优点

每个biz_tag都有消费进度监控,比如号段长度设置为高峰期QPS的600倍;

每次请求都会判断下一个号段的状态,从而更新下一个号段;

缺点

Leaf -snowflake方案

Leaf分别在上述第二种和第三种方案上做了相应的优化,实现了Leaf-segment和Leaf-snowflake方案。

snowflake方案适合订单类,不需要趋势递增的场景;

leaf-snowflake方案仍然使用snowflake方案的bit位设计,“1+42+10+12”;

通过zookeeper服务注册管理每个leaf服务,并且zk负责下发每个leaf服务的work id,作为标识启动后续ID生成程序;


弱依赖ZK

在本机缓存一个worker ID文件,当zk出现问题时,通过读取文件实现对zk的弱依赖;

时钟同步问题

如果机器时钟发生了回拨,那么就会发生重复ID号;启动顺序如下:

参见上图整个启动流程图,服务启动时首先检查自己是否写过ZooKeeper leaf_forever节点:

若写过,则用自身系统时间与leaf_forever/ s e l f 节点记录时间做比较,若小于 l e a f f o r e v e r / {self}节点记录时间做比较,若小于leaf_forever/ self节点记录时间做比较,若小于leaff​orever/{self}时间则认为机器时间发生了大步长回拨,服务启动失败并报警。

若未写过,证明是新服务节点,直接创建持久节点leaf_forever/${self}并写入自身系统时间,接下来综合对比其余Leaf节点的系统时间来判断自身系统时间是否准确,具体做法是取leaf_temporary下的所有临时节点(所有运行中的Leaf-snowflake节点)的服务IP:Port,然后通过RPC请求得到所有节点的系统时间,计算sum(time)/nodeSize。

若abs( 系统时间-sum(time)/nodeSize ) < 阈值,认为当前系统时间准确,正常启动服务,同时写临时节点leaf_temporary/${self} 维持租约。

否则认为本机系统时间发生大步长偏移,启动失败并报警。

每隔一段时间(3s)上报自身系统时间写入leaf_forever/${self}。

由于强依赖时钟,对时间的要求敏感,需要关闭机器的NTP同步;

并且在时钟回拨时不提供服务或者返回Error_Code,或者摘除节点并报警;

// 当前时间小于上次的发号时间

if (timestamp < lastTimeStamp) {

// 发生时钟回拨

}

优点

目前Leaf的性能在4C8G的机器上QPS能压测到近5万/s,TP999 1ms

缺点

参考文档

leaf 美团的分布式ID生成器

【阅读】Leaf——美团点评分布式ID生成系统相关推荐

  1. Leaf——美团点评分布式ID生成系统

    背景 在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识.如在美团点评的金融.支付.餐饮.酒店.猫眼电影等产品的系统中,数据日渐增长,对数据分库分表后需要有一个唯一ID来标识一条数据或消息,数 ...

  2. [分布式id]:Leaf——美团点评分布式ID生成系统

    文章目录 摘要 1 分布式id相关概念 1.1 为什么需要分布式id 1.1.1 BTree 1.1.2 B+Tree 1.1.3 B+Tree相比于BTree优势 1.2 什么是分布式id 1.3 ...

  3. 美团开源分布式ID生成系统——Leaf源码阅读笔记(Leaf的号段模式)

    Leaf 最早期需求是各个业务线的订单ID生成需求.在美团早期,有的业务直接通过DB自增的方式生成ID,有的业务通过redis缓存来生成ID,也有的业务直接用UUID这种方式来生成ID.以上的方式各自 ...

  4. 带你了解「美团、百度和滴滴」的分布式 ID 生成系统

    文章目录 美团 背景 常见方法介绍 UUID 类snowflake方案 数据库生成 Leaf 方案实现 Leaf-segment 数据库方案 双 buffer 优化 Leaf 高可用容灾 Leaf-s ...

  5. 美团技术分享:深度解密美团的分布式ID生成算法

    本文来自美团技术团队"照东"的分享,原题<Leaf--美团点评分布式ID生成系统>,收录时有勘误.修订并重新排版,感谢原作者的分享. 1.引言 鉴于IM系统中聊天消息I ...

  6. 在 .NET6.0 中实现 Leaf-segment 分布式 ID 生成系统

    背景 分布式 ID (Distributed ID)是指在分布式系统中,为了保证全局唯一性而生成的一类 ID.在分布式系统中,由于存在多个节点同时生成 ID 的情况,因此需要采用一定的算法来保证生成的 ...

  7. 分布式 ID 生成系统 Leaf 的设计思路,源码解读

    什么是分布式ID? ID 最大的特点是 唯一 而分布式 ID,就是指分布式系统下的 ID,它是 全局唯一 的. 为啥需要分布式ID呢? 这就和 唯一 息息相关了. 比如我们用 MySQL 存储数据,一 ...

  8. 滴滴开源的分布式id生成系统

    ID Generator id生成器 分布式id生成系统,简单易用.高性能.高可用的id生成系统 简介 Tinyid是用Java开发的一款分布式id生成系统,基于数据库号段算法实现,关于这个算法可以参 ...

  9. Leaf-美团分布式id生成系统

    概述 分布式id生成已经有业界较为成熟的方案.现在公司使用的是美团的Leaf的号码段模式.之所以不用雪花算法模式还是因为雪花算法的自身缺陷,即时间回拨问题.本文就从源码角度剖析leaf项目的两种id生 ...

最新文章

  1. linux shell ls 时间排序显示
  2. 《游戏引擎架构》笔记十四
  3. The Linux SG_IO ioctl in the 2.6 series
  4. 肉体之爱的解释圣经_可以解释的AI简介,以及我们为什么需要它
  5. 汇编Ring 3下实现 HOOK API
  6. [Spring-cloud-eureka]使用 gradle, spring boot,Spring cloud Eureka 搭建服务消费者
  7. Java编程的逻辑 (43) - 剖析TreeMap
  8. 《Servlet和JSP学习指南》一导读
  9. vs 生成get set_TVM代码学习 -- 代码生成流程(一)
  10. STM32的串口DMA收发以及双缓冲区的实现
  11. vue 判断是否function_vue2.0组件的prop验证中的Function类型怎么使用(向子组件传递函数对象的正确方法)?...
  12. cdr软件百度百科_cdr是什么软件?
  13. eclipse安装反编译软件jd-gui
  14. C++实现的windows系统下的WIFI管理
  15. ESP8266学习笔记:实现ESP8266的局域网内通信
  16. Android——广播
  17. 【论文阅读】ICRA2021: VDB-EDT An Efficient Euclidean Distance Transform Algorithm Based on VDB Data Struct
  18. java的日历类_java 中的Calendar日历类
  19. 解析SQL的表间血缘关系工具
  20. HTML+CSS期末网页设计前端作品(大三)

热门文章

  1. String...str是什么?
  2. 浏览器大战中的搜狗浏览器
  3. 存储一万亿张图片,需要怎样的架构?
  4. 撤消git stash pop导致合并冲突
  5. matlab之请求用户输入函数input
  6. 在 LaTeX 中直接作图:Picture环境
  7. C++ 视频学习笔记
  8. AJAX的教程(一)
  9. 电子邮箱为何依然重要?企业办公邮箱的使用好处
  10. nginx 动态添加模块