- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
现如今可谓是微服务、分布式、IoT(物联网)横行的时代,作为一名开发者始终还是要保持一定的危机意识,特别是在日常的项目开发中,若是有机会接触到一些关于微服务、分布式下的应用场景,应当硬着头皮、排除万难,主动应承下来上去大干一场;这期间不管结果如何,积累下来的经验将会让自己受益匪浅;而本文要介绍的“分布式全局唯一ID”便是一种典型的分布式应用场景!!!
话不多说,咱们直接进入正题~~~
说起这个全局唯一ID,你可能会第一时间想到“数据库的自增主键”、“UUID”、“雪花算法”等等,更有甚者,还能说出一些大厂开源的组件,比如滴滴的IDWorker、美团的Leaf等等,没错,这些确实是可以实现全局唯一ID的方案,你能想到这些点,那涉猎其实还是挺广的。
而对于“全局唯一ID/编号/编码”的应用场景,在现实生活中还是比较多的,比如电商平台中“订单系统”的订单编号,“进销存系统”中的商品编号、订单编号,“支付”过程中订单流水号等等;接下来debug将会总结性的介绍下目前市面上比较流行的“全局唯一ID”的几种实现方式,并针对分布式场景下的几种实现方式进行代码实战。
话不多说,直接进入正题,先贴张思维导图吧,总结性地概括下目前网上比较流行的几种方式
结合上图几种方式,再概括性的介绍下吧:
简介:这一点相信写过代码的小伙伴都晓得,主要利用主键ID的auo_increment特性,每进来一条数据时数据库自动为其生成当前最大的ID并作为该条记录的主键;
优点:简单、便捷;
缺点:只能限于单机,严重依赖于DB,仅可限于DB相关的业务,可用性还是有点差;
TIPS: 生成的id是连续的吗?https://www.jianshu.com/p/369559f399d0
简介:DB只存储当前最大的ID值,每次需要ID时,则按照顺序批量生成N个有序的ID列表,并将最大的ID值 + N。
优点:相对于第一种方式性能还是提高了不少;
缺点:仍然得依赖于DB,可用性还是有点差;而且批量生成的ID可能断层(比如服务挂了然后重启就可能跳过部分ID,如果服务有多个,将难以保证其有序性)
TIPS:已废弃 20200708 go服务billno解耦方案
简介:通用唯一识别码,这个估计众所周知啦,不作过多的介绍了!
优点:简单,直接 UUID.randomUUID().toString()即可搞定;
缺点:比较长、占用空间大;无序且不利于索引,在实际项目中不建议使用;特别是在插入数据库时如果用UUID生成的ID作为主键的话,很可能会引起B+树的不断重平衡;
简介:比如按照规则:yyyyMMdd+ N位随机数 或者 yyyyMMddHHmmss + N位随机数。
优点:可行,而且生成的ID编号前半段有序,有一定的业务意义;
缺点:当并发产生的数据量比较大时,那N位随机数会出现重复的可能(虽然可以通过各种方式去重,比如Redis的Set,但代价还是相当高的,因为得不断的 while判断是否重复…)
**TIPS:**linux下生成随机数 https://blog.51cto.com/13236892/2426623
简介:Twitter开源的一种分布式ID生成算法,结果是一个Long型的64位的ID;其核心思想是将64位划分为各个段,其中0号位不用,连续41位表示时间戳,连续10位表示工作机器ID,最后12位则表示毫秒级别的序列号,如下图所示:
算法产生的是一个long型 64 比特位的值,第一位未使用。接下来是41位的毫秒单位的时间戳,我们可以计算下:
2^41/1000*60*60*24*365 = 69
也就是这个时间戳可以使用69年不重复,这个对于大部分系统够用了。
很多人这里会搞错概念,以为这个时间戳是相对于一个我们业务中指定的时间(一般是系统上线时间),而不是1970年。这里一定要注意。
10位的数据机器位,所以可以部署在1024个节点。
12位的序列,在毫秒的时间戳内计数。 支持每个节点每毫秒产生4096个ID序号,所以最大可以支持单节点差不多四百万的并发量,这个妥妥的够用了。
优点:可以说是分布式场景下生成全局唯一ID的一种经典算法吧,采用Java生成,对于咱们Java的小伙伴来说可以说是相当接地气的了;
缺点:目前倒没发现有啥缺陷,如果硬要说有,那就是“时钟回播”的问题了。
**TIPS:**时钟回拨问题
简介:JUC(java.util.concurrent)包下经典的原子操作类,可以基于它生成自增、有序且全局唯一的编号
优点:底层采用CAS(Compare And Swap)机制实现,并发场景下可以保证“自增”代码逻辑的安全性;
缺点:依赖于JDK,只适合单机环境
简介:熟悉这个命令的应该都知道它是啥意思,不知道的 自己打开redis-cli执行下该命令就可以了!
优点:可行,分布式场景下是适用的;
缺点:基本上没想到有啥缺陷,如果要挑刺的话,那就是依赖于中间件服务,如果Redis挂掉,那基本上该ID生成服务就不可用了
**TIPS:**redis的单机处理是每秒10w左右,如果并发超过10w如何处理?集群式redis如何生成唯一id
简介:这个大家可能有点陌生,其实就是利用ZooKeeper底层树形节点ZNode(类似于Windows的文件目录数)的有序性,循环不断生成其对应的版本号或者节点本身的数据
优点:可行,分布式场景下是适用的;
缺点:基本上没想到有啥缺陷,跟第七点类似吧,需要保证ZK服务的高可用即可
我的应用程序中有一个 settings.php 页面,它使用 $GLOBALS 来存储网络应用程序中使用的配置。 例如,他是我使用的一个示例设置变量: $GLOBALS["new_login_page
我正在尝试编译我们在 OS 类上获得的简单操作系统代码。它在 Ubuntu 下运行良好,但我想在 OS X 上编译它。我得到的错误是: [compiling] arch/i386/arch/start
我知道distcp无法使用通配符。 但是,我将需要在更改的目录上安排distcp。 (即,仅在星期一等“星期五”目录中复制数据),还从指定目录下的所有项目中复制数据。 是否有某种设计模式可用于编写此类
是否可以在config.groovy中全局定义资源格式(json,xml)的优先级,而不是在每个Resource上指定?例如,不要在@Resource Annotation的参数中指定它,例如: @R
是否有一些简单的方法来获取大对象图的所有关联,而不必“左连接获取”所有关联?我不能只告诉 Hibernate 默认获取 eager 关联吗? 最佳答案 即使有可能有一个全局 lazy=false(谷歌
我正在尝试实现一个全局加载对话框...我想调用一些静态函数来显示对话框和一些静态函数来关闭它。与此同时,我正在主线程或子线程中做一些工作...... 我尝试了以下操作,但对话框没有更新...最后一次,
当我偶然发现 this question 时,我正在阅读更改占位符文本。 无论如何,我回去学习了占位符。一个 SO 的回答大致如下: Be careful when designing your pl
例如,如果我有这样的文字: "hello800 more text 1234 and 567" 它应该匹配 1234 和 567,而不是 800(因为它遵循 hello 的 o,这不是一个数字)。 这
我一直在尝试寻找一种无需使用 SMS 验证系统即可验证电话号码(Android 和 iPhone)的方法。原因纯粹是围绕成本。我想要一个免费的解决方案。 我可以安全地假设 Android 操作系统会向
解决此类问题的规范 C++ 设计模式是什么? 我有一些共享多个类的多线程服务器。我需要为大多数类提供各种运行时参数(例如服务器名称、日志记录级别)。 在下面的伪 C++ 代码中,我使用了一个日志记录类
这个问题在这里已经有了答案: Using global variables in a function (25 个答案) 关闭 9 年前。 我是 python 的新手,所以可能有一个简单的答案,但我
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Does C++ call destructors for global and class static
我正在尝试使用 Objective-C 中的 ArrayList 的等价物。我知道我必须使用 NSMutableArray。我想要一个字符串列表 (NSString)。关键是我的列表应该可以从我类(c
今天刚开始学习 Android 开发,我找不到任何关于如何定义 Helper 类或将全局加载的函数集合的信息,我会能够在我创建的任何 Activity 中使用它们。 我的计划是创建(至少目前)2 个几
为什么这段代码有效: var = 0 def func(num): print num var = 1 if num != 0: func(num-1) fun
$GLOBALS["items"] = array('one', 'two', 'three', 'four', 'five' ,'six', 'seven'); $alter = &$GLOBALS
我想知道如何实现一个可以在任何地方使用您自己的设置的全局记录器: 我目前有一个自定义记录器类: class customLogger(logging.Logger): ... 该类位于一个单独的
我需要使用 React 测试库和 Jest 在我的测试中模拟不同的窗口大小。 目前我必须在每个测试文件中包含这个beforeAll: import matchMediaPolyfill from 'm
每次我遇到单例模式或任何静态类(即(几乎)只有静态成员的类)的实现时,我想知道这是否实际上不是一种黑客行为,因此只是为了设计而严重滥用类和实例的原则单个对象,而不是设计类和创建单个实例。对我来说,看起
这个问题在这里已经有了答案: Help understanding global flag in perl (2 个回答) 7年前关闭。 my $test = "There was once an\n
我是一名优秀的程序员,十分优秀!