本文介绍: 例如,每次从数据库获取 id 时,获取一个号段,如[1,2999],这个范围表示3000 个 ID,业务应用请求获取 id 时,只需要本地从 1 开始自增返回(注意线程安全问题使用子类来做自增操作),而不用每次去请求数据库,一直到本地自增到 2999 时,再去数据库重新获取新的号段,后续流程循环往复。分布式ID生成系统需要具有较高的可用性,因为业务数据唯一标识都由该系统分配,若系统不可用,将直接影响用户订单这些强依赖于ID生成系统模块。如果id乱序,将不利于数据库写入排序操作。

为什么需要分布式唯一id

        开发项目时,我们需要给每一个角色“都打上唯一标签比如用户订单消息等都需要唯一的标识,以此来区分不同的用户订单消息单体项目使用数据库自增主键作为唯一标识可能就绰绰有余了,但分布式系统可以使用这种方案吗?显然不行,此时就需要用到分布式id了。

分布式唯一id需要具有哪些特性

        (1)全局唯一基本的要求,必须保证全局不会出现重复ID。

        (2)有序id作为唯一标识肯定是字段之一,要随业务数据写入数据库的;如果id乱序,将不利于数据库写入排序操作。

        (3)高可用分布式ID生成系统需要具有较高的可用性,因为业务数据的唯一标识都由该系统分配,若系统不可用,将直接影响用户订单这些强依赖于ID生成系统的模块。

        (4)安全不会暴露业务信息

分布式唯一ID的生成方案哪些

        1、UUID由32个十六进制数组成的字符串,并用-分割成了五个部分,如:b86d54e5-0452-4e0bb15a-94af36d68022这种形式。

        常用的UUID版本

        1.1、基于随机数的UUID基于随机数或伪随机数实现较为简单,但存在id重复的可能性(java中的randomUUID就是该版本)。

        1.2、基于名字空间的UUID:基于指定命名空间生成SHA1散列,命名空间下唯一,但计算耗时。

        UUID方案优点:本地生成,没有网络开销,性能好。

        UUID方案缺点:总共36个字符长度较长;没有递增趋势,作为主键插入数据时可能会造成大量的页分裂现象产生。

        2、数据库自增ID:数据库插入数据时,若创建表时主键设置auto_increment,那么主键自动递增,我们可以用递增的主键作为分布式id

具体实现

        2.1、创建id生成表:

DROP TABLE IF EXISTS `id_generator`;
CREATE TABLE `id_generator` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`mark` char(1) not null,
PRIMARY KEY (`id`),
UNIQUE KEY `mark` (`mark`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

        2.2、开启事务获取唯一id:

begin;
replace into id_generator (mark) VALUES ('x');
select last_insert_id();
commit;

        数据库方案优点:实现简单,id递增且唯一性由数据库保证。        

        数据库方案缺点:多个线程并发获取id时,性能不好;数据库压力较大。

        2.3、高并发场景解决方案

        数据库进行水平拆分,每个数据库设置不同的初始值、相同的步长,如下图所示

        3、Redis基于redis线程执行命令特性,使用原子命令INCR或INCRBY命令来获取全局唯一并且递增的序列号作为分布式id。

        redis方案优点:基于内存、不依赖于数据库,性能较好;能保证id唯一且递增。

        redis方案缺点:id生成强依赖redisredis挂了会导致服务不可用;redis在宕机时,如果没有将id持久化到磁盘重启后可能会生成重复id。

        4、Snowflake算法该算法生成的是一个64位的long型id。其核心思想是使用 41bit 作为时间戳(当前时间戳-起始时间戳),10bit 作为机器ID,12bit 作为自增序列号(意味着每个节点在每毫秒可以产生 2^12 = 4096 个 ID),最高位是符号位0(id不可能为负数)。

        雪花算法方案优点:id是趋势递增的;不依赖于数据库、redis第三方服务本地生成,性能较好;可根据业务调整bit,灵活性好。

        雪花算法方案缺点:在分布式环境下由于每个机器时钟无法做到完全一致,id不一定是全局递增的;依赖于机器时钟,如果时钟回拨,会生成重复id或非递增id。

        4.1、时钟回拨问题解决方案:

        a只让少量服务器生成id,并关闭这些服务器时钟回拨。

        b当发生时钟回拨时直接报错,交给上层业务处理

        c如果时钟回拨时间较短,在容忍范围内,可以等待回拨时间后再生成id。

        5、号段Segment从数据库批量获取id,将 id 缓存本地,以此来提高业务获取 id 的效率。例如,每次从数据库获取 id 时,获取一个号段,如[1,2999],这个范围表示3000 个 ID,业务应用请求获取 id 时,只需要在本地从 1 开始自增并返回(注意线程安全问题,使用原子类来做自增操作),而不用每次去请求数据库,一直到本地自增到 2999 时,再去数据库重新获取新的号段,后续流程循环往复。

        号段方案优点:即使数据库不可用了,在本地号段用尽之前,仍能够正常获取id;id是递增;只需操作一次数据库就可以获取多个id,同时业务可以在本地获取id,性能好。

        号段方案缺点:还是依赖于数据库。

原文地址:https://blog.csdn.net/Annancqxxx/article/details/134699066

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_26336.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注