热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

各种分布式全局唯一ID生成算法汇总大全(共12种)有3种你没见过的雪花算法

​各种分布式全局唯一ID生成算法汇总大全(共12种);设计分布式微服务系统,面试看这篇就够了。在复杂分布式系统中,往往需要对大量的数据和消

​    各种分布式全局唯一ID生成算法汇总大全(共12种);设计分布式微服务系统,面试看这篇就够了。

 

   在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识。在系统中,数据日渐增长,对数据分库分表后需要有一个唯一ID来标识一条数据或消息,数据库的自增ID显然不能满足需求;此时一个能够生成全局唯一ID的系统是非常必要的。概括下来,那业务系统对ID号的要求有哪些呢?

1.     全局唯一性:不能出现重复的ID号,保证生成的 ID 全局唯一,这是最基本的要求。

2.     趋势递增:有利于保证DB插入、查询等操作的性能。

3.     单调递增:保证下一个ID一定大于上一个ID,例如版本号、排序等特殊需求。

4.     信息安全:如果ID是连续的,容易被猜测出url,ID号码的数量,对业务产生影响。所以在一些应用场景下,会需要ID无规则、不规则。

上述需求对应不同的场景,3和4需求还是互斥的,无法使其在同一个方案满足。

同时除了对ID号码自身的要求,业务还对ID号生成系统的可用性要求极高,想象一下,如果ID生成系统瘫痪,整个电商系统都无法完成业务,这就会带来一场灾难。

由此总结出一个ID生成系统应该做到如下几点:

     1.     平均延迟和TP999延迟都要尽可能低;

     2.     可用性5个9;

     3.     高QPS。

 

划重点了:如果前9种,你都看过了,就直接跳到第10种看吧。

分段模式与雪花到底有什么区别?

一个是依赖DB,一个是依赖时间的.

能不能找到一种,既不依赖DB,也不依赖时间的算法呢?答案是,肯定有的,找吧(本文就能找到)!

DB表自增ID真的不能用在分布式场景吗?  不要让前人把你的思维带偏了!

 

以下,将为大家讲解各种分布式全局唯一ID生成算法(共12种)。

  1.   基于数据库自增ID(单个DB)

  2.   基于数据库自增ID(主从DB结构)

  3. UUID  全球唯一,但生成的是字符串。

  4. Redis

  5. 号段模式

  6. twitter snowflake   Twitter时钟回拨时直接抛异常。时钟回拨时会不可用。

  7. 美团leaf: 该篇文章详细的介绍了snowflake和db号段方案,近期也进行了Leaf开源。

还可以完善的地方:

没有:连续单调递增ID生成方案;没有批量获取ID号的方法。

snowflake弱化毫秒的时钟回拨,默认能容错5毫秒,避免润秒问题要在外部调用100次。弱依赖Zookeeper分配workerid.  返回结果用Result结构包装,会影响一点性能。时钟回拨时会不可用。

workerid有重复时,会有重号风险。workerid分配方案提供ZooKeeper,但想改其它分配方案需要改源码。

 

db号段模式属于依赖DB的号段模式,一次取一个号段的ID,减少对ID的访问。

8. 百度uid-generator: 这是基于snowflake方案实现的开源组件. 支持容器重启,workerid用后即弃,机器id占22位,最多可支持约419w次机器启动。

sequence (13 bits)每秒下的并发序列,13 bits可支持每秒8192个并发。

缺点:机器号占太多位,每个时间点能用的号码太少。

9. tinyid :属于依赖DB的号段模式,一次取一个号段的ID,减少对ID的访问。

全局唯一的long型id

趋势递增的id,即不保证下一个id一定比上一个大

非连续性(不支持:连续单调递增ID)

优点:

支持批量获取id

支持多个db的配置,无单点

适用场景:只关心id是数字,趋势递增的系统,可以容忍id不连续,有浪费的场景

缺点:

不适用场景:类似订单id的业务(因为生成的id大部分是连续的,容易被扫库、或者测算出订单量)

作为分布式DB表主键,不是特别合适。不支持,连续单调递增ID,依赖DB

 

以上几种算法还存在的问题。

依赖DB分段批量获取的算法,是可以产生全局唯一,且批内连续单调递增的ID。但多个请求分别调用生成一批,多个批都插入数据到库,还是不会连续的。强依赖DB。

雪花生成的是不连续,全局唯一,但只能是趋势递增的ID,部分区间连续,整体不连续。过于依赖时间。

因此又延伸出以下三种算法。

10. 梨花算法:改进的雪花算法,弱依赖时间,对毫秒不敏感,可以允许2分钟即120秒的时钟回拨(实际上可以根据业务场景设置更长或更短的容错时间),可以轻松避免润秒问题。workerid默认从配置文件获取,代码架构可方便扩展workerid分配算法,能处理workerid冲突问题。可提前消费1秒。。。

返回结果用原生long返回&#xff0c;异常使用小于0&#xff08;<0&#xff09;的数表示。

workerid有重复时&#xff0c;会有重号风险。应该选择合适的workerid分配方案避免。

支持批获取ID号.

 

梨花算法&#xff0c;原文介绍链接

源码&#xff1a;

https://github.com/automvc/bee/blob/master/src/main/java/org/teasoft/bee/distribution/GenId.java

 

11. 连续单调递增全局唯一的ID生成算法SerialUniqueId&#xff1a;不依赖于时间&#xff0c;也不依赖于任何第三方组件&#xff0c;只是启动时&#xff0c;用一个时间作为第一个ID设置的种子&#xff0c;设置了初值ID后&#xff0c;就可获取并递增ID在一台DB内与传统的一样&#xff0c;连续单调递增&#xff08;而不只是趋势递增&#xff09;&#xff0c;而代表DB的workerid作为DB的区号放在高位(类似电话号码的国际区号&#xff09;&#xff0c;从所有DB节点看&#xff0c;则满足分布式DB生成全局唯一ID。本地&#xff08;C8 I7 16g&#xff09;1981ms可生成1亿个ID号,利用上批获取&#xff0c;分隔业务&#xff0c;每秒生成过10亿个ID号不成问题&#xff0c;能满足双11的峰值要求。

    可用作分布式DB内置生成64位long型ID自增主键(数据库能更新功能&#xff0c;为我们生成第一个ID最好。不能的话&#xff0c;我们就自己根据算法设置第一个ID)。只要按本算法设置了记录的ID初值&#xff0c;然后默认让数据库表id主键自增就可以&#xff08;如MYSQL&#xff09;。这样&#xff0c;不管是多少个节点插入到该DB的数据&#xff0c;记录的ID都是连续单调递增的。而从全局看&#xff0c;因为workerid不一样&#xff0c;多个数据库间的ID又不会重复。像中国的号码是:12345678,美国的号码也是12345678,但国际区号不一样&#xff0c;号码也就不一样。比如这样100-12345678&#xff0c;101-12345678。

    有的人设计软件系统时&#xff0c;即使当初设计的是单体系统&#xff0c;为了让以后DB能适应分布式环境&#xff0c;主键不会重复&#xff0c;使用了UUID的字符生成形式&#xff0c;从而牺牲了数字id的优越性能。其实何须这样呢&#xff01;只需要按本算法设置了记录的ID初值&#xff0c;然后默认让数据库表id主键自增就可以啦。DBid主键自增不能用在分布式场景——这是之前的一种错误认识。

可以一次取一批ID&#xff08;即一个范围内的ID一次就可以获取了&#xff09;。是不是可以取代依赖DB的号段模式呢!!

对于单点问题&#xff0c;提供高可用解决方案。将该算法打包成一个服务替换<依赖DB的号段模式>中的DB即可&#xff0c;服务与服务调用&#xff0c;无数据库IO开销&#xff0c;从而提高了性能。 &#xff08;但这样就不能连续单调了&#xff0c;但也总比之前的号段模式&#xff0c;要依赖DB好吧!&#xff09;。

 

  使用国际电话号码作类比说明。只不过是用二进制还看得比较清楚。

国际区号&#43;本国&#xff08;地区&#xff09;号码

为什么在一个国家或地区的电话号码不会重复&#xff1f;为什么在国际上一个国家或地区的电话号码还是不会重复&#xff1f;国际区号放在电话号码的最高位部分&#xff0c;只要一国内电话号码不会重复&#xff0c;不同国家用不同的区号&#xff0c;在国际上&#xff0c;电话号码还是不会重复。连续单调递增唯一ID生成算法与这个例子也类似。

绝对全局连续单调递增的DB表主键解决方案&#xff1f;&#xff1f;&#xff1a;

绝对全局连续单调递增的方案不存在。如(1,2,3,…10)分到5个DB&#xff0c;则每个库的ID为&#xff1a;

DB1&#xff08;1,6&#xff09;,  DB2&#xff08;2,7&#xff09;, DB3&#xff08;3,8&#xff09;,  DB4&#xff08;4,9&#xff09;, DB5&#xff08;5,10&#xff09;

或者&#xff1a;

DB1&#xff08;1,2&#xff09;,  DB2&#xff08;3,4&#xff09;, DB3&#xff08;5,6&#xff09;,  DB4&#xff08;7,8&#xff09;, DB5&#xff08;9,10&#xff09;

要么总体有序&#xff0c;在各个库趋势递增&#xff1b;要么各个库内连续有序&#xff0c;但各部分DB1

绝对连续单调递增&#xff0c;全局唯一的方案&#xff0c;如下&#xff1a;

只能是在新增一个库时&#xff0c;就分配一个库的workerid. 然后在初始化表时&#xff0c;设置初始ID开始用的值&#xff0c;以后由DB自动增长。Workerid的分配可统一放在一个配置文件&#xff0c;由工具检测到某个表是空表&#xff0c;且使用的主键对应的是Java的long型时&#xff0c;设置初始ID开始用的值。

当用作表ID的主键时&#xff0c;可以在表结构创建时&#xff0c;设置不同数据源表主键开始用的ID初值。风险几乎没有&#xff0c;保证100%不重号。

 

内存生成时&#xff0c;可间隔一定时间(如3分钟&#xff09;缓存当前ID值到文件&#xff0c;供重启时设置回初值用。新ID初始值&#61;缓存的ID值&#43;间隔时间会生成的ID数量最大值。重启会浪费一个间隔时间生成的ID号。

 

源码&#xff1a;

https://github.com/automvc/bee/blob/master/src/main/java/org/teasoft/bee/distribution/GenId.java

https://github.com/automvc/honey/blob/master/src/main/java/org/teasoft/honey/distribution/SerialUniqueId.java

 

12. 不依赖时间的梨花算法OneTimeSnowflakeId:

进一步改进第10点提到的梨花算法

通过代码调用生成ID插入DB的&#xff0c;需要整体有序性。不依赖时间的梨花算法&#xff0c;Workerid应放在序号的上一段&#xff0c;且应用SerialUniqueId算法&#xff0c;使ID不依赖于时间自动递增。使用不依赖时间的梨花算法&#xff0c;应保证各节点大概均衡轮流出号&#xff0c;这样入库的ID会比较有序&#xff0c;因此每个段号内的序列号不能太多。

支持批获取ID号。可以一次取一批ID&#xff08;即一个范围内的ID一次就可以获取了&#xff09;。是不是可以取代依赖DB的号段模式呢!!

可间隔时间缓存时间值到文件&#xff0c;供重启时设置回初值用。若不缓存&#xff0c;则重启时&#xff0c;又用目前的时间点&#xff0c;重设开始的ID。只要平均不超过419w/s&#xff0c;重启时造成的时钟回拨都不会有影响&#xff08;但却浪费了辛苦攒下的每秒没用完的ID号&#xff09;。要是很多时间都超过419w/s&#xff0c;证明你有足够的能力做这件事&#xff1a;间隔时间缓存时间值到文件。

 

详细代码&#xff0c;可查看源码:

https://github.com/automvc/honey/blob/master/src/main/java/org/teasoft/honey/distribution/OneTimeSnowflakeId.java

 

总结1&#xff1a;

应用场景区别&#xff1a;主键ID一般需要连续递增&#xff1b;但订单ID为了安全则不需要太有序。

按是否可以浪费ID区别&#xff1a;

1.浪费ID&#xff0c;

2.不浪费ID&#xff1b;

2.1可以不强依赖于时间;用完时间自动加1秒;

2.2可以不强依赖于时间&#xff0c;当将Workid放最高位部分时&#xff0c;则可以在Workerid内连续单调递增

 

总结2&#xff1a;

分段模式与雪花到底有什么区别&#xff1f;

一个是依赖DB,一个是依赖时间的.

一个是取的号码可以一直连续递增的&#xff1b;一个是趋势递增&#xff0c;会因workerid的原因产生的ID号是会跳很大一段的.

依赖于DB的号段模式&#xff0c;当多个节点一起拿号时&#xff0c;最终落库的ID还是不能连续的。

雪花ID适合做分布式数据库表主键吗&#xff1f;它只保证递增&#xff0c;没保证连续。

 

能不能找到一种&#xff0c;既不依赖DB&#xff0c;也不依赖时间的算法呢&#xff1f;答案是&#xff0c;肯定有的&#xff0c;找吧&#xff01;

SerialUniqueId,可以代替分段模式类的算法&#xff0c;随机丢弃部分批量号码&#xff08;成为不连续&#xff09;还可以代替雪花类算法。

OneTimeSnowflakeId可以代替雪花类算法(设置每个段开始的第一个ID号码随机生成&#xff0c;即可不暴露实际使用的ID数量)。

 

这个都被大家忽略了:

DB表自增ID&#xff0c;也是可以改成分布式特性的&#xff0c;SerialUniqueId就是&#xff01;

---------------------------------------

有中关村&#xff0c;有科技园。一个南漂在深圳一线的IT小哥&#xff0c;资深工程师也罢&#xff0c;架构师也罢&#xff0c;我独喜欢软件设计&#xff01;带你了解最前沿的软件设计思想与技术。

  长按二维码可关注(公众号: AiTeaSoft)

          更多重磅文章等着你!


推荐阅读
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • ElasticSerach初探第一篇认识ES+环境搭建+简单MySQL数据同步+SpringBoot整合ES
    一、认识ElasticSearch是一个基于Lucene的开源搜索引擎,通过简单的RESTfulAPI来隐藏Lucene的复杂性。全文搜索,分析系统&# ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
author-avatar
linxiuying261
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有