【从零开始学习Redis | 第七篇】利用Redis构造全局唯一ID(含其他构造方法)

目录

前言:

什么是全局唯一ID? 

尝试构造全局唯一ID: 

其他构造全局唯一ID的方法

1.基于数据库自增构造全局唯一ID:

2.基于UUID构造全局唯一ID:

3.基于雪花算法构造全局唯一ID:

总结:


 

前言:

        在各种实际业务中,全局唯一ID是一个重要的存在,它用来标识用户的特定服务,方便用户在后续基于这个ID来进行各种服务。而如何构造全局唯一ID也是一个比较重要的知识点。因此今天来介绍一下如何基于Redis构造全局唯一ID。

什么是全局唯一ID? 

        全局唯一ID(Global Unique Identifier,简称GUID)是在计算机系统中用于唯一标识实体或对象的标识符。它通常由一个128位的数字字符串组成,采用特定的算法生成,以确保在相同的算法和生成器设置下几乎不会重复。


让我们回到业务中:

每个店铺都可下发自己店铺的优惠卷,当用户抢购的时候,就会生成订单到订单表中,并且返回订单号给用户。但是如果只是使用简单的数据库自增就会出现问题:

        1.少量数据下,采用数据库自增的方式,会泄漏信息给用户。用户可以根据订单ID推测出优惠卷的订单数,可能会引发恶意行为。

        2.大量数据下,如果所有的订单都在一个张表中,在进行SQL查询的时候效率会大大降低,并且如果我们进行了分表,那么多个订单表中间的数据库自增是隔离的,并不能保证多表下的ID唯一


        那么我们目前可以知道:如果要追求ID的唯一性,那么就应该避免在数据库中进行ID的构造。基于这种情况,那么我们就把ID的构造放到Redis中进行。

尝试构造全局唯一ID: 

而为了增加ID的安全性,我们也不直接使用Redis的自增数值,而是再拼接一些其他的信息:

由图可看得,我们设计的ID一共分为三部分:

1.符号位:永远为0,标识我们的ID是一个整数。

2.时间戳:从自定义时间开始,按秒计算。那么32位我们大约可以使用60多年。

3.序列号:同一时间内下单进行自增。在时间戳相等的形况下的区分不同的订单。

代码实现:

    public long nextId(String keyPrefix) {//1.生成时间戳LocalDateTime now = LocalDateTime.now();long nowhSecond = now.toEpochSecond(ZoneOffset.UTC);long timestamp = nowhSecond - BEGIN_TIMESTAMP;//2.生成序列号//1.获取日期,精确到天String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));Long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);return (timestamp << COUNT_BITS) | count;}

 在这里我们唯一需要讲的就是返回结果中的(timestamp << COUNT_BITS) | count

                其实是他就是一个拼接序列号的过程,只不过相比较于符号运算来讲,使用位运算的效率更高。

其他构造全局唯一ID的方法

1.基于数据库自增构造全局唯一ID:

 基于数据库自增构造ID,之前我们讲了主要的难点是:分表之后无法统一构造自增唯一ID,多个订单表在构造ID的时候可能会出现重复。

那么其实解决方案很简单:既然多个表在构造ID的时候会出现重复问题,那么我们就不要在订单表中构造ID了,创建一个订单ID表去专门维护ID

比如我们可以这样设计一个订单ID表:

create table order_test.order_id
(id   int auto_incrementprimary key,name varchar(20) null,constraint nameunique (name)
);

那么我们就得到了这样一张表:

在查询的时候,我们使用这样一条语句:

begin ;
replace into order_id (name) values ("order_id");
SELECT last_insert_id();
COMMIT ;

 这样我们基于name的唯一性,就做到了对id的自增:

 但是这种创建一张表去维护订单ID的方式仍然是有问题的:高并发场景下,万一这张表挂了怎么办

所以为了优化,我们还可以采取多表的思想:

在新思想中,我们让一个表维护订单id为偶数,一个表维护订单id为奇数。这样的话,我们就是实现了减轻单表压力。而且这种思想是可以不断的改进的,我们可以通过让表维护不同类型的数字来不断的拆表,减轻单表压力

但是这种方法得到的订单id,他不一定是逐个递增的,只能说是整体呈现递增趋势

而且这种方式如果要抵抗高并发的话,就要不断的去加数据库,对维护数字进行分类。因此这种方式其实缺点还是比较明显的。

但其实基于数据库构造全局唯一ID是有成熟的方案的:美团的LEAF数据库方案,原文链接我也留在这里:

Leaf——美团点评分布式ID生成系统 - 美团技术团队 (meituan.com)icon-default.png?t=N7T8https://tech.meituan.com/2017/04/21/mt-leaf.html        LEAF数据库方案简而言之就一句话:批量获取ID进行处理。在上文我们简单的对数据库进行优化的时候,优化问题基本都来源于高并发下数据库高频的读写操作。而LEAF数据库方案也是针对这个方面进行优化的

我们可以把图中的leaf简单的理解为是一个生成全局唯一ID的服务。那么整个LEAF数据库的思想就是:leaf服务提前就拿好一批号端,例如从0-1000。那么我在生成唯一ID的时候,压力就从数据库转到了Leaf这个服务里面。

优点:

        1.leaf只是一个简单的web服务,方便进行扩展

        2.ID号也满足趋势递增的要求

        3.容灾性高,由于生成唯一ID的是leaf服务,而且内部有号段缓存,因此即使数据库挂了,短时间内也可以正常对外提供服务

缺点:

        当所有的leaf用完自己的号段之后,就会向数据库再次请求号段,此时leaf服务是不可用的。而如果此时有大量的请求leaf服务,就会引发一段尖刺。

解决方案:

        我们并不会等到号段全部用完之后再去请求新的号段。美团给出的技术方案是当号段消费到某个点时就异步的把下一个号段加载到内存中。而不需要等到号段用尽的时候才去更新号段。

        一开始先用A号段,等 A号段消耗10%的时候,就向数据库请求新号段。之后当前号段消耗完之后就可以进行快速的切换。如此循环往复。

2.基于UUID构造全局唯一ID

虽然基于UUID可以保证构造ID的唯一性,但是UUID是随机生成的数字+字母。这使得UUID构造出的ID不具备递增性,在做数据库索引的时候效率比较慢。

而且UUID也存在安全性问题:UUID有一版是基于MAC地址来构造唯一标识的,可能会有泄漏MAC地址的风险

import java.util.UUID;public class UUIDExample {public static void main(String[] args) {// 生成随机的UUIDUUID uuid = UUID.randomUUID();System.out.println("随机生成的UUID: " + uuid.toString());// 根据字符串生成UUIDString uuidString = "38400000-8cf0-11bd-b23e-10b96e4ef00d";UUID fromString = UUID.fromString(uuidString);System.out.println("从字符串生成的UUID: " + fromString.toString());}
}

3.基于雪花算法构造全局唯一ID

六十四位雪花算法构成:

其实可以看出,雪花算法跟我们上文提到的基于Redis生成全局唯一ID的思路是一样的。因此这里不做赘述。

而基于雪花算法,最常问的一个面试问题就是:如何解决时间回拨问题

其实就是说:如果时间戳回拨了,我们要如何处理?因为时间戳回拨之后,生成的id就有可能和以前的重合,那么我们要如何进行处理呢?

大部分的开源版本的雪花算法面对时间回拨问题采用的是抛异常的处理方法,其实我感觉这属于是没处理。

比较好的处理方法是根据回拨时间的长短来个性化处理方案:

        1.回拨时间很短(<=100ms):直接睡眠当前线程,等到时间戳加载正常之后再生成ID

        2.回拨时间适中(>100ms<=1s):寻找当前回拨时间毫秒内的最大id,直接沿着那个id++就可以。

        3.回拨时间较长(>1s<=5s):创建多个雪花算法服务,当前使用的雪花算法服务时间戳发生回拨就换一个。

        4.回拨时间很长(>5s):直接下线服务,人工介入手动调试时间戳。

除此之外,我们还可以提前就预留好一部分的分布式ID,在时间戳回拨之后,我们使用这部分预留的分布式ID,直至时间戳恢复正常。

总结:

当我们在设计分布式系统时,唯一ID的生成是一个非常重要的问题。为了保证分布式环境下ID的唯一性和无序性,我们可以采用雪花算法、UUID、数据库自增等方式生成唯一ID。

其中,雪花算法是目前应用最广泛的分布式ID生成算法之一。它通过使用时间戳、机器ID和序列号来生成64位的唯一ID,可以在多个节点上生成ID而不会重复。

除了ID的生成算法外,还需要考虑时钟回拨问题、ID的长度、ID的可读性等问题。为了解决时钟回拨问题,我们可以采取物理时钟、NTP同步、预留ID范围等方式;

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

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

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

相关文章

在客户端访问远程Linux服务器的私有IP地址的URL

文章目录 环境背景SSH tunnel和正向/反向代理步骤第一步第二步效果考一考 其它多次跳转另一种方法&#xff1a;正向代理 参考 环境 服务器&#xff1a;Ubuntu 22.04客户端&#xff1a;Mac 14.2.1 背景 在远程Linux服务器上搭建了minikube环境。minikube提供了dashboard功能&…

ChatGPT付费创作系统V2.5.8独立版+前端

小狐狸ChatGPT付费创作系统V2.5.8版本最大特点新增PC端绘画功能全新升级。该版本为编译版无开源&#xff0c;本版本同样处理了后台弹窗、暗链网址。单独制作了2.5.5升级至2.5.8数据库升级包及升级文件&#xff0c;直接导入即可使用。本版本升级后唯一BUG后台绘画功能新增的翻译…

酷开科技将AR技术多方应用 打造全能酷开系统

酷开系统AR技术的核心是通过计算机视觉、图形渲染和深度感知等技术&#xff0c;将虚拟物体或信息精确地叠加到现实世界的场景中。通过智能摄像头捕捉真实环境的图像和视频&#xff0c;结合3D渲染技术&#xff0c;生成与现实场景相融合的虚拟图像&#xff0c;实现虚实结合的视觉…

最新ChatGPT/GPT4科研应用与AI绘图及论文高效写作

详情点击链接&#xff1a;最新ChatGPT/GPT4科研应用与AI绘图及论文高效写作 一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型Clau…

编译FFmpeg4.3.1 、x264并移植到Android

1、前言 FFmpeg 既是一款音视频编解码工具&#xff0c;同时也是一组音视频编解码开发套件。 2、准备工作 系统&#xff1a;LinuxNDK&#xff1a;android-ndk-r21b-linux-x86_64.zipFFmpeg&#xff1a;ffmpeg-snapshot.tar.bz2x264&#xff1a;x264 3、下载NDK 在linux环境中…

hanlp,pkuseg,jieba,cutword分词实践

总结&#xff1a;只有jieba,cutword,baidu lac成功将色盲色弱成功分对,这两个库字典应该是最全的 hanlp[持续更新中] https://github.com/hankcs/HanLP/blob/doc-zh/plugins/hanlp_demo/hanlp_demo/zh/tok_stl.ipynb import hanlp # hanlp.pretrained.tok.ALL # 语种见名称最…

RabbitMQ交换机(3)-Topic

1.Topic模式 RabbitMQ的Topic模式是一种基于主题的消息传递模式。它允许发送者向一个特定的主题&#xff08;topic&#xff09;发布消息&#xff0c;同时&#xff0c;订阅者也可以针对自己感兴趣的主题进行订阅。 在Topic模式中&#xff0c; 主题通过一个由单词和点号组成的字…

Git教程学习:07 打标签

文章目录 0 前言1 列出标签2 创建标签3 附注标签4 轻量标签5 后期打标签6 共享标签7 删掉标签8 检查标签 0 前言 像其他版本控制系统&#xff08;VCS&#xff09;一样&#xff0c;Git 可以给仓库历史中的某一个提交打上标签&#xff0c;以示重要。 比较有代表性的是人们会使用…

Unity使用Protobuf

1.下载Protobuf ProtoBuf 2.打开它并且编译 如果有报错下载相应的.net版本即可 这里默认是6.0.100 由于我本机是8.0.100所以我改了这个文件 3.编译后的文件复制到Unity Assets/Plugins下 4.写个测试的proto文件 5.然后使用protoc生成 这里实现了一个简单的bat批量生成 Protos C…

微软与沃达丰签订10年合作,提供Copilot等生成式AI服务

1月16日&#xff0c;微软在官网宣布&#xff0c;与全球最大电信公司之一沃达丰&#xff08;Vodafone&#xff09;签订10年合作协议&#xff0c;将为3亿多企业、消费者提供生成式AI、云和数字服务等。 通过此次合作&#xff0c;沃达丰将利用微软的Copilot等生成式AI来改变客户、…

新版AndroidStudio dependencyResolutionManagement出错

在新版AndroidStudio中想像使用4.2版本或者4.3版本的AndroidStudio来构造项目&#xff1f;那下面这些坑我们就需要来避免了&#xff0c;否则会出各种各样的问题。 一.我们先来看看新旧两个版本的不同。 1.jdk版本的不同 新版默认是jdk17 旧版默认是jdk8 所以在新版AndroidSt…

FlinkAPI开发之状态管理

案例用到的测试数据请参考文章&#xff1a; Flink自定义Source模拟数据流 原文链接&#xff1a;https://blog.csdn.net/m0_52606060/article/details/135436048 Flink中的状态 概述 有状态的算子 状态的分类 托管状态&#xff08;Managed State&#xff09;和原始状态&…

如何用GPT进行数据处理?

详情点击链接&#xff1a;如何用GPT进行数据处理&#xff1f; 一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型Claude2二定制自己…

线性代数基础【5】特征值和特征向量

第五章 特征值和特征向量 第一节、特征值和特征向量的基本概念 一、特征值和特征向量的理论背景 在一个多项式中,未知数的个数为任意多个,且每一项次数都是2的多项式称为二次型,二次型分为两种类型:即非标准二次型及标准二次型 注意: ①二次型X^T AX为非标准二次型的充分必…

docker部署项目,/var/lib/docker/overlay2目录满了如何清理?

docker部署项目&#xff0c;/var/lib/docker/overlay2目录满了如何清理&#xff1f; 一、问题二、解决1、查看 /var/lib/docker 目录&#xff08;1&#xff09;、containers 目录&#xff08;2&#xff09;、volumes 目录&#xff08;3&#xff09;、overlay2 目录 2、清理&…

总结1094

昨天又摆烂了&#xff0c;总结后面补的。 记录一个as中的错误&#xff1a; 一年没碰android了&#xff0c;下载安装AS,发现出现Gradle问题&#xff1a; ERROR: Connection timed out: connect&#xff1a;错误:连接超时:连接 这个错误 一般来说是因为.gradle引起的 搞了半…

Python编辑开发---pycharm pro 2023 中文

PyCharm Pro 2023是一款功能强大的Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;旨在提高Python开发人员的生产力。它提供了智能代码编辑、实时代码分析和调试工具&#xff0c;支持版本控制和数据库工具&#xff0c;以及可扩展的插件系统。PyCharm Pro 2023可在多…

《30天自制操作系统》学习笔记(七)

先体验一下编译仿真方法&#xff1a; 30天自制操作系统光盘代码在下面链接&#xff0c;但是没有编译仿真工具&#xff1a; https://gitee.com/zhanfei3000/30dayMakeOS 仿真工具在下面链接&#xff1a; https://gitee.com/909854136/nask-code-ide 这是一个集成的编译仿真工…

jrebel IDEA 热部署

1 下载 2022.4.1 JRebel and XRebel - IntelliJ IDEs Plugin | Marketplace 2 选择下载好的zip 离线安装IDEA 插件 重启IDEA 3 打开 [Preference -> JRebel & XRebel] 菜单&#xff0c;输入 GUID address 为 https://jrebel.qekang.com/1e67ec1b-122f-4708-87d…

WINCC读写EXCEL-VBS

原创 RENHQ WINCC 关于VBS操作EXCEL的文档不管在论坛上还是在网上&#xff0c;相关的脚本已经很多&#xff0c;但是依然有很多人在问这个问题&#xff0c;于是把我以前在论坛上发的一个集合帖子的脚本拿来&#xff0c;重新开个帖子&#xff0c;如果再有人问的话&#xff0c;可…