分布式系统全局唯一ID的几种实现方式

现如今可谓是微服务、分布式、IoT(物联网)横行的时代,作为一名开发者始终还是要保持一定的危机意识,特别是在日常的项目开发中,若是有机会接触到一些关于微服务、分布式下的应用场景,应当硬着头皮、排除万难,主动应承下来上去大干一场;这期间不管结果如何,积累下来的经验将会让自己受益匪浅;而本文要介绍的“分布式全局唯一ID”便是一种典型的分布式应用场景!!!
话不多说,咱们直接进入正题~~~

说起这个全局唯一ID,你可能会第一时间想到“数据库的自增主键”、“UUID”、“雪花算法”等等,更有甚者,还能说出一些大厂开源的组件,比如滴滴的IDWorker、美团的Leaf等等,没错,这些确实是可以实现全局唯一ID的方案,你能想到这些点,那涉猎其实还是挺广的。

而对于“全局唯一ID/编号/编码”的应用场景,在现实生活中还是比较多的,比如电商平台中“订单系统”的订单编号,“进销存系统”中的商品编号、订单编号,“支付”过程中订单流水号等等;接下来debug将会总结性的介绍下目前市面上比较流行的“全局唯一ID”的几种实现方式,并针对分布式场景下的几种实现方式进行代码实战。

话不多说,直接进入正题,先贴张思维导图吧,总结性地概括下目前网上比较流行的几种方式img

结合上图几种方式,再概括性的介绍下吧:

1、 数据库的自增主键

简介:这一点相信写过代码的小伙伴都晓得,主要利用主键ID的auo_increment特性,每进来一条数据时数据库自动为其生成当前最大的ID并作为该条记录的主键;

优点:简单、便捷;

缺点:只能限于单机,严重依赖于DB,仅可限于DB相关的业务,可用性还是有点差;

TIPS: 生成的id是连续的吗?https://www.jianshu.com/p/369559f399d0

2、批量预生成ID

简介:DB只存储当前最大的ID值,每次需要ID时,则按照顺序批量生成N个有序的ID列表,并将最大的ID值 + N。

优点:相对于第一种方式性能还是提高了不少;

缺点:仍然得依赖于DB,可用性还是有点差;而且批量生成的ID可能断层(比如服务挂了然后重启就可能跳过部分ID,如果服务有多个,将难以保证其有序性)

TIPS:已废弃 20200708 go服务billno解耦方案

3、 UUID的方式

简介:通用唯一识别码,这个估计众所周知啦,不作过多的介绍了!
优点:简单,直接 UUID.randomUUID().toString()即可搞定;

缺点:比较长、占用空间大;无序且不利于索引,在实际项目中不建议使用;特别是在插入数据库时如果用UUID生成的ID作为主键的话,很可能会引起B+树的不断重平衡;

4、基于时间戳

简介:比如按照规则:yyyyMMdd+ N位随机数 或者 yyyyMMddHHmmss + N位随机数。

优点:可行,而且生成的ID编号前半段有序,有一定的业务意义;

缺点:当并发产生的数据量比较大时,那N位随机数会出现重复的可能(虽然可以通过各种方式去重,比如Redis的Set,但代价还是相当高的,因为得不断的 while判断是否重复…)

**TIPS:**linux下生成随机数 https://blog.51cto.com/13236892/2426623

5、SnowFlake算法

简介:Twitter开源的一种分布式ID生成算法,结果是一个Long型的64位的ID;其核心思想是将64位划分为各个段,其中0号位不用,连续41位表示时间戳,连续10位表示工作机器ID,最后12位则表示毫秒级别的序列号,如下图所示:

img

算法产生的是一个long型 64 比特位的值,第一位未使用。接下来是41位的毫秒单位的时间戳,我们可以计算下:

2^41/1000*60*60*24*365 = 69

也就是这个时间戳可以使用69年不重复,这个对于大部分系统够用了。

很多人这里会搞错概念,以为这个时间戳是相对于一个我们业务中指定的时间(一般是系统上线时间),而不是1970年。这里一定要注意。

10位的数据机器位,所以可以部署在1024个节点。

12位的序列,在毫秒的时间戳内计数。 支持每个节点每毫秒产生4096个ID序号,所以最大可以支持单节点差不多四百万的并发量,这个妥妥的够用了。

优点:可以说是分布式场景下生成全局唯一ID的一种经典算法吧,采用Java生成,对于咱们Java的小伙伴来说可以说是相当接地气的了;

缺点:目前倒没发现有啥缺陷,如果硬要说有,那就是“时钟回播”的问题了。

**TIPS:**时钟回拨问题

  • UidGenerator,时间递增(传统的雪花算法实现都是通过System.currentTimeMillis()来获取时间并与上一次时间进行比较,这样的实现严重依赖服务器的时间。而UidGenerator的时间类型是AtomicLong,且通过incrementAndGet()方法获取下一次的时间,从而脱离了对服务器时间的依赖,也就不会有时钟回拨的问题)(https://zhuanlan.zhihu.com/p/77737855)
  • leaf 5ms内等待,如果时钟回拨超过5ms,依然会抛出异常。(https://www.jianshu.com/p/bd6b00e5f5ac)
  • sharding jdbc直接拒绝

6、 原子操作类AtomlcXX

简介:JUC(java.util.concurrent)包下经典的原子操作类,可以基于它生成自增、有序且全局唯一的编号

优点:底层采用CAS(Compare And Swap)机制实现,并发场景下可以保证“自增”代码逻辑的安全性;

缺点:依赖于JDK,只适合单机环境

7、Redis的INCRBY操作

简介:熟悉这个命令的应该都知道它是啥意思,不知道的 自己打开redis-cli执行下该命令就可以了!

优点:可行,分布式场景下是适用的;

缺点:基本上没想到有啥缺陷,如果要挑刺的话,那就是依赖于中间件服务,如果Redis挂掉,那基本上该ID生成服务就不可用了

**TIPS:**redis的单机处理是每秒10w左右,如果并发超过10w如何处理?集群式redis如何生成唯一id

8、基于ZooKeeper的节点版本号生成ID

简介:这个大家可能有点陌生,其实就是利用ZooKeeper底层树形节点ZNode(类似于Windows的文件目录数)的有序性,循环不断生成其对应的版本号或者节点本身的数据

优点:可行,分布式场景下是适用的;

缺点:基本上没想到有啥缺陷,跟第七点类似吧,需要保证ZK服务的高可用即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555582.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git如何查看缓存区文件内容_详解Git工作区、暂存区、历史记录区以及git reset、git revert、git checkout等撤销命令的区别...

一、可以将git简单的分为三个区域 1、工作区(working directory) 2、暂缓区(stage index) 3、历史记录区(history) 如图:其中git add files 把当前工作目录中的文件放入暂存区域这其实做了两件事: 1、将本地文件的时间戳、长度&#xff0…

Java接口学习(接口的使用、简单工厂、代理模式、接口和抽象类的区别)

前言引入 官方解释:Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能&#xff0…

最短路径 floyd java_java实现Floyd算法求最短路径

关于无向图的最短路径问题:这个程序输出:最短路径矩阵例如:W[0][5]9 代表vo->v5的最短路径为9W:0 1 3 7 4 91 0 2 6 3 83 2 0 4 1 67 6 4 0 3 24 3 1 3 0 59 8 6 2 5 0package com.xh.Floyd;import java.util.ArrayList;public class Floyd_01 {publi…

SpringBoot 使用 log4j2

一、新建工程 选择一些基础依赖 填写工程名称和项目路径 二、工程配置 修改文件编码格式 设置Java Compiler 修改maven配置文件路径 三、pom.xml的web依赖中排除掉logging依赖&#xff0c;并且引入log4j2依赖 <dependency><groupId>org.springframework.…

springBoot 通过使用log4j2

1.排除 Spring-boot-starter 默认的日志配置 将原本的 spring-boot-starter 改为 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>…

SpringBoot默认日志logback配置解析

SpringBoot默认日志logback配置解析 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候&#xff0c;是带着下面几个问题来查资料的&#xff0c;你呢 如何引入日志&#xff1f;日志输出格式以及输出方式如何配置&#xff1f;代码中如何使用&#xff1f; 正文…

SpringBoot查看和修改依赖的版本

springBoot依赖管理&#xff1a; 1、引入父项目的作用是实现对所有依赖的管理。 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version> &l…

在IDEA中解决jar包冲突的神操作-必看

在开发过程中&#xff0c;经常会遇到导入jar包后jar包冲突的情况&#xff0c;大家也都知道&#xff0c;解决jar包冲突通常都比较麻烦&#xff0c;要找到多余的依赖&#xff0c;把低版本的依赖去掉。而大家通常能搜到IDEA解决jar包冲突的方法&#xff0c;应该是这样的&#xff1…

MySQL保存或更新 saveOrUpdate

1. 引子 在项目开发过程中&#xff0c;有一些数据在写入时候&#xff0c;若已经存在&#xff0c;则覆盖即可。这样可以防止多次重复写入唯一键冲突报错。下面先给出两个MyBatis配置文件中使用saveOrUpdate的示例 <!-- 单条数据保存 --> <insert id"saveOrUpdat…

分布式事务六种解决方案

前言 事务想必大家并不陌生&#xff0c;至于什么是 ACID&#xff0c;也是老生常谈了。不过为了保证文章的完整性确保所有人都听得懂&#xff0c;我还是得先说说 ACID&#xff0c;然后再来介绍下什么是分布式事务和常见的分布式事务包括 2PC、3PC、TCC、本地消息表、消息事务、…

Minor GC、Major GC和Full GC之间的区别

概念&#xff1a; ● 新生代 GC&#xff08;Minor GC&#xff09;&#xff1a;从年轻代空间&#xff08;包括 Eden 和 Survivor 区域&#xff09;回收内存被称为 Minor GC,因为 Java 对象大多都具备朝生夕灭的特性&#xff0c;所以 Minor GC 非常频繁&#xff0c;一般回收速度也…

SpringBoot——实现WebService接口服务端以及客户端开发

文章目录一、服务端代码开发1、pom依赖2、接口类3、接口实现类4、webservice配置文件2、客户端开发&#xff08;1&#xff09;pom依赖&#xff08;2&#xff09;封装客户端方法clientUtil&#xff08;3&#xff09;调用接口类&#xff08;4&#xff09;运行结果我们经常需要在两…

springboot集成webService开发详解

webService优缺点 webService优点 WebService是一种跨编程语言和跨操作系统平台的远程调用技术远程调用技术&#xff1a;不用担心防火墙的问题 webService缺点 服务端接口方为webservice则客户端也必须使用webservice&#xff0c;双方保持一致因为webservice使用xml传输数据…

WebService就是这么简单

WebService介绍 首先我们来谈一下为什么需要学习webService这样的一个技术吧…. 问题一 如果我们的网站需要提供一个天气预报这样一个需求的话&#xff0c;那我们该怎么做&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 天气预报这么一个功能并不是简单的J…

python使用xlrd读取xlsx文件_$ 用python处理Excel文档(1)——用xlrd模块读取xls/xlsx文档...

本文主要介绍xlrd模块读取Excel文档的基本用法&#xff0c;并以一个GDP数据的文档为例来进行操作。1. 准备工作&#xff1a;1. 安装xlrd&#xff1a;pip install xlrd2. 准备数据集&#xff1a;从网上找到的1952~2012年中国国内GDP的数据&#xff0c;数据结构如下&#xff1a;2…

WebService技术详解CXF

WebService WebService简介 Web Service技术&#xff0c; 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件&#xff0c; 就可相互交换数据或集成。依据Web Service规范实施的应用之间&#xff0c; 无论它们所使用的语言、 平台或内部协议是什么&…

Java webservice详解

文章目录1 webservice概述2 webservice核心要素2.1 SOAP2.2 WSDL3 webservice的使用场景4 webservice的结构5 Java中的webservice5.1 webservice服务端5.2 webservice客户端6 WDSL文件说明7 webservice 请求与响应监控8 webservice 在Tomcat中发布9 在Spring中使用webservice1 …

hibernate mysql cascade_Hibernate第五篇【inverse、cascade属性详解】

前言上一篇博文已经讲解了一对多和多对一之间的关系了&#xff0c;一对多和多对一存在着关联关系(外键与主键的关系)。本博文主要讲解Inverse属性、cascade属性。这两个属性对关联关系都有影响Inverse属性Inverse属性&#xff1a;表示控制权是否转移..true:控制权已转移【当前一…

spring boot中打包插件spring-boot-maven-plugin和maven-jar-plugin的关联

简介 用spring boot快速开发时&#xff0c;通常用spring-boot-maven-plugin插件将springboot的应用程序打包成jar文件&#xff0c;然后通过java -jar运行&#xff0c;很方便。但是如果是部署到服务器上&#xff0c;每次更改代码后替换的包都比较大&#xff0c;至少30MB以上&am…

Maven父子结构的项目依赖使用以及打包依赖_微服务项目(maven父子级项目)怎么打包

Maven父子结构的项目依赖使用以及打包依赖 1&#xff1a;在父子结构项目中&#xff0c;如果要是用其他模块的类。在当前项目中的pom中 加入 其他模块的配置 <dependency><groupId>com.spring.mySpring</groupId><artifactId>mySpring-utils</artif…