Redis学习打卡-Day3-分布式ID生成策略、分布式锁

news2025/5/20 23:08:36

分布式 ID

  • 当单机 MySQL 已经无法支撑系统的数据量时,就需要进行分库分表(推荐 Sharding-JDBC)。在分库之后, 数据遍布在不同服务器上的数据库,数据库的自增主键已经没办法满足生成的主键全局唯一。这个时候就需要生成分布式 ID了。

分布式 ID 应满足的需求

  • 一个最基本的分布式 ID 需要满足下面这些要求:
    • 全局唯一:ID 的全局唯一性肯定是首先要满足的!
    • 高性能:分布式 ID 的生成速度要快,对本地资源消耗要小。
    • 高可用:生成分布式 ID 的服务要保证可用性无限接近于 100%。
    • 有序递增:如果要把 ID 存放在数据库的话,ID 的有序性可以提升数据库写入速度。并且很多时候 ,我们还很有可能会直接通过 ID 来进行排序。
  • 除了这些之外,一个比较好的分布式 ID 还应保证:
    • 安全:ID 中不包含敏感信息。
    • 方便易用:拿来即用,使用方便,快速接入!
    • 有具体的业务含义:生成的 ID 如果能有具体的业务含义,可以让定位问题以及开发更透明化(通过 ID 就能确定是哪个业务)。
    • 独立部署:也就是分布式系统单独有一个发号器服务,专门用来生成分布式 ID。这样就生成 ID 的服务可以和业务相关的服务解耦。不过,这样同样带来了网络调用消耗增加的问题。总的来说,如果需要用到分布式 ID 的场景比较多的话,独立部署的发号器服务还是很有必要的。

分布式 ID 的生成策略

1)UUID
  • UUID 是 Universally Unique Identifier(通用唯一标识符) 的缩写。UUID 包含 32 个 16 进制数(8-4-4-4-12)。
  • JDK 就提供了现成的生成 UUID 的方法,一行代码就行了。
    //输出示例:cb4a9ede-fa5e-4585-b9bb-d60bce986eaa
    UUID.randomUUID()
    
  • 优点:生成速度通常比较快、简单易用。
  • 缺点:
    • 存储消耗空间大(32 个字符串,128 位)。
    • 不安全(基于 MAC 地址生成 UUID 的算法会造成 MAC 地址泄露)。
    • 无序(非自增)。
    • 没有具体业务含义。
    • 需要解决重复 ID 问题(当机器时间不对的情况下,可能导致会产生重复 ID)。
2)Snowflake(雪花算法)
  • Snowflake 是 Twitter 开源的分布式 ID 生成算法。Snowflake 由 64 bit 的二进制数字组成,这 64bit 的二进制被分成了几部分,每一部分存储的数据都有特定的含义:
    Snowflake
    • sign(1bit):符号位(标识正负),始终为 0,代表生成的 ID 为正数。
    • timestamp (41 bits):一共 41 位,用来表示时间戳,单位是毫秒,可以支撑 2 41 毫秒(约 69 年)。
    • datacenter id + worker id (10 bits):一般来说,前 5 位表示机房 ID,后 5 位表示机器 ID(实际项目中可以根据实际情况调整),这样就可以区分不同集群/机房的节点。
    • sequence (12 bits):一共 12 位,用来表示序列号。 序列号为自增值,代表单台机器每毫秒能够产生的最大 ID 数(212 = 4096),也就是说单台机器每毫秒最多可以生成 4096 个 唯一 ID。
  • 优点:生成速度比较快、生成的 ID 有序递增、比较灵活(可以对 Snowflake 算法进行简单的改造比如加入业务 ID)。
  • 缺点:
    • 需要解决重复 ID 问题(ID 生成依赖时间,在获取时间的时候,可能会出现时间回拨的问题,也就是服务器上的时间突然倒退到之前的时间,进而导致会产生重复 ID)。
    • 依赖机器 ID 对分布式环境不友好(当需要自动启停或增减机器时,固定的机器 ID 可能不够灵活)。
3)Redis自增
  • 为了增加ID的安全性,我们可以不直接使用Redis自增的数值,而是拼接一些其它信息:
    在这里插入图片描述
  • 符号位:1bit,永远为0。
  • 时间戳:31bit,以秒为单位,可以使用69年。
  • 序列号:32bit,秒内的计数器,支持每秒产生232个不同ID。

悲观锁

  • 悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。
  • 也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程。
  • 对于单机多线程来说,在 Java 中,我们通常使用 ReentrantLock 类、synchronized 关键字这类 JDK 自带的本地锁来控制一个 JVM 进程内的多个线程对本地共享资源的访问。

乐观锁

  • 乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源是否被其它线程修改了(具体方法可以使用版本号机制或 CAS 算法)。
  • 版本号机制
    • 一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。
    • 当数据被修改时,version 值会+1。当线程 A 要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值为当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。
  • CAS 算法
    • CAS 的全称是 Compare And Swap(比较与交换) ,用于实现乐观锁,被广泛应用于各大框架中。CAS 的思想很简单,就是用一个预期值和要更新的变量值进行比较,两值相等才会进行更新。
    • CAS 是一个原子操作,底层依赖于一条 CPU 的原子指令。
    • 当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败,但失败的线程并不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。
    • 问题:
      • "ABA"问题:如果一个变量 V 初次读取的时候是 A 值,并且在准备赋值的时候检查到它仍然是 A 值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回 A,那 CAS 操作就会误认为它从来没有被修改过。
      • 循环时间长开销大:CAS 经常会用到自旋操作来进行重试,也就是不成功就一直循环执行直到成功。如果长时间不成功,会给 CPU 带来非常大的执行开销。
      • 只能保证一个共享变量的原子操作:CAS 操作仅能对单个共享变量有效。当需要操作多个共享变量时,CAS 就显得无能为力。

分布式锁

  • 通过加synchronized锁可以解决在单机情况下的一人一单等安全问题,但是在集群模式下就不行了。
  • 分布式系统下,不同的服务/客户端通常运行在独立的 JVM 进程上。如果多个 JVM 进程共享同一份资源的话,使用本地锁就没办法实现资源的互斥访问了。于是,分布式锁就诞生了。
    分布式锁

分布式锁应满足的需求

  • 一个最基本的分布式锁需要满足:
    • 互斥:任意一个时刻,锁只能被一个线程持有。
    • 高可用:锁服务是高可用的,当一个锁服务出现问题,能够自动切换到另外一个锁服务。并且,即使客户端的释放锁的代码逻辑出现问题,锁最终一定还是会被释放,不会影响其他线程对共享资源的访问。这一般是通过超时机制实现的。
    • 可重入:一个节点获取了锁之后,还可以再次获取锁。
  • 除了上面这三个基本条件之外,一个好的分布式锁还需要满足下面这些条件:
    • 高性能:获取和释放锁的操作应该快速完成,并且不应该对整个系统的性能造成过大影响。
    • 非阻塞:如果获取不到锁,不能无限期等待,避免对系统正常运行造成影响。

分布式锁实现方案

分布式锁实现方案

基于 Redis 实现分布式锁

  • 在 Redis 中, SETNX 命令是可以帮助我们实现互斥。SETNXSET if Not eXists (对应 Java 中的 setIfAbsent 方法),如果 key 不存在的话,才会设置 key 的值。如果 key 已经存在, SETNX 啥也不做。
  • 为了避免锁无法被释放,我们可以给这个 key(也就是锁) 设置一个过期时间 。一定要保证设置指定 key 的值和过期时间是一个原子操作!!! 不然的话,依然可能会出现锁无法被释放的问题。
    127.0.0.1:6379> SET lockKey uniqueValue EX 3 NX
    OK
    
  • 释放锁的话,直接通过 DEL 命令删除对应的 key 即可。
  • 为了防止误删其他的锁,这里我们建议使用 Lua 脚本通过 key 对应的 value(唯一值)来判断。选用 Lua 脚本是为了保证解锁操作的原子性。因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,从而保证了锁释放操作的原子性
    // 释放锁时,先比较锁对应的 value 值是否相等,避免锁的误释放
    if redis.call("get",KEYS[1]) == ARGV[1] then
        return redis.call("del",KEYS[1])
    else
        return 0
    end
    
    基于 Redis 实现分布式锁
基于 Redis 的分布式锁存在的问题
  • 不可重入
    • 同一个线程无法多次获取同一把锁。
    • 解决:利用hash结构,记录线程标示和重入次数。
  • 不可重试
    • 获取锁只尝试一次就返回false,没有重试机制。
    • 解决:利用信号量控制锁重试
  • 超时释放
    • 虽然可以避免死锁,但如果业务执行耗时较长,也会导致锁释放,存在安全隐患。
    • 解决:Watch Dog
  • 主从一致性
    • 如果 Redis 提供了主从集群,主从同步存在延迟,当主宕机时,如果并未同步主中的锁数据,则会出现锁失效。
    • 解决:Redisson 的 multiLock,多个独立的 Redis 节点,必须在所有节点都获取重入锁,才算获取锁成功。

Redisson

  • Redisson 是一个开源的 Java 语言 Redis 客户端,提供了很多开箱即用的功能,不仅仅包括多种分布式锁的实现。并且,Redisson 还支持 Redis 单机、Redis Sentinel、Redis Cluster 等多种部署架构。
  • Redisson 中的分布式锁自带自动续期机制,使用起来非常简单,原理也比较简单,其提供了一个专门用来监控和续期锁的 Watch Dog( 看门狗),如果操作共享资源的线程还未执行完成的话,Watch Dog 会不断地延长锁的过期时间,进而保证锁不会因为超时而被释放。
    Redisson
  • 默认情况下,每过 10 秒,看门狗就会执行续期操作,将锁的超时时间设置为 30 秒。看门狗续期前也会先判断是否需要执行续期操作,需要才会执行续期,否则取消续期操作。

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

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

相关文章

数据库第二次作业--SQL的单表查询与多表查询

单表查询 查询专业信息表中的专业名称和专业类型 SELECT Mname, Mtype FROM MajorP;查询一个学校有多少个专业 SELECT COUNT(Mno) AS 专业数量 FROM MajorP;查询学校的男女学生各有多少位 SELECT Ssex, COUNT(*) AS 人数 FROM StudentP GROUP BY Ssex查询每个专业…

在Cursor中启用WebStorm/IntelliJ风格快捷键

在Cursor中启用WebStorm/IntelliJ风格快捷键 方法一:使用预置快捷键方案 打开快捷键设置 Windows/Linux: Ctrl K → Ctrl SmacOS: ⌘ K → ⌘ S 搜索预设方案 在搜索框中输入keyboard shortcuts,选择Preferences: Open Keyboard Shortcuts (JSON) …

vue3:十三、分类管理-表格--编辑、新增、详情、刷新

一、效果 实现封装表格的新增、编辑、详情查看,表格刷新功能 实现表格组件中表单的封装 1、新增 如下图,新增页面显示空白的下拉,文本框,文本域,并实现提交功能 2、编辑 如下图,点击行数据,可将行数据展示到编辑弹窗,并实现提交功能 3、详情 如下图,点击行数据,…

c#基础01(.Net介绍)

文章目录 .Net平台介绍.Net平台简介跨平台开源.Net Core.Net Framework开发工具安装选项 创建项目 .Net平台介绍 .Net平台简介 .NET是一种用于构建多种应用的免费开源开放平台,例如: Web 应用、Web API 和微服务 云中的无服务器函数 云原生应用 移动…

Logrotate:配置日志轮转、高效管理Linux日志文件

Logrotate 是 Linux 系统中用于自动化管理日志文件的工具,能够定期轮转、压缩、删除日志文件,确保系统日志不会无限制增长,占用过多磁盘空间。 它通常由 Cron 作业定期执行,也可以手动触发。 1. 🔧 核心功能 日志轮转…

贵州某建筑物挡墙自动化监测

1. 项目简介 某建筑物位于贵州省某县城区内,靠近县城主干道,周边配套学校、医院、商贸城。建筑物临近凤凰湖、芙蓉江等水系,主打“湖景生态宜居”。改建筑物总占地面积:约5.3万平方米;总建筑面积:约15万平…

nginx服务器实验

1.实验要求 1)在Nginx服务器上搭建LNMP服务,并且能够对外提供Discuz论坛服务。 在Web1、Web2服务器上搭建Tomcat 服务。 2)为nginx服务配置虚拟主机,新增两个域名 www.kgc.com 和 www.benet.com,使用http://www.kgc.…

高速光耦在通信行业的应用(五) | 5Mbps通信光耦的特性

针对5MBd速率光耦市场,晶台推出KL2200、KL2201和KL2202系列光耦 ,对标大部分国外品牌产品的应用;它分别由一个红外发射二极管和一个高速集成光电检测器逻辑门组成。 它采用 8 引脚 DIP 封装,并提供 SMD 选项。KL2200 的检测器具有一个三态输出…

Apidog MCP服务器,连接API规范和AI编码助手的桥梁

#作者:曹付江 文章目录 1.了解 MCP2.什么是 Apidog MCP 服务器?3.Apidog MCP 服务器如何工作4.利用人工智能改变开发工作流程5.设置 Apidog MCP 服务器: 分步指南5.高级功能和提示5.1 使用 OpenAPI 规范5.2.多个项目配置5.3.安全最佳实践5.4…

国内MCP服务平台推荐 AIbase推出MCP服务器客户端商店

在当今数字化时代,人工智能(AI)技术正以前所未有的速度发展,不断改变着我们的生活和工作方式。2025年,AI领域迎来了一项重要的技术进展——MCP(Model Context Protocol,模型上下文协议)的广泛应用。这一技术…

Profinet转Ethernet IP主站网关:点燃氢醌生产线的智慧之光!

案例分享:转角指示器和Profinet转EthernetIP网关的应用 在现代工业自动化中,设备和系统之间的高效通信至关重要。最近,我们在某大型化工企业的生产线上实施了一个项目,旨在通过先进的设备和通信技术提高生产效率和安全性。该项目…

爬虫攻防战:从入门到放弃的完整对抗史与实战解决方案

爬虫攻防战:从入门到放弃的完整对抗史与实战解决方案 这张有趣的图片生动描绘了爬虫开发者与反爬工程师之间的"军备竞赛"。作为技术博主,我将基于这张图的各个阶段,深入分析爬虫技术的演进与对应的反制措施,提供一套完整的反爬解决方案,包括技术原理、实施方法…

[ctfshow web入门] web75

信息收集 启用了open_basedir,所以之前的方法又不能用了 解题 cforeach(new DirectoryIterator("glob:///*") as $a){echo($a->__toString(). ); } ob_flush();cif ( $a opendir("glob:///*") ) {while ( ($file readdir($a)) ! false …

交流学习 | 江西同为科技有限公司赴海尔总部考察交流

2025年4月8日至9日,江西同为科技有限公司在江西省科技装备商会的带领下,以蔡文君经理为代表,一行人赴山东青岛海尔总部开展两天的考察交流活动。本次考察不仅深入剖析了海尔企业的前沿技术与管理理念,更促进了行业内科技创新、商业…

React方向:react的基本语法-数据渲染

1、安装包(js库) yarn add babel-standalone react react-dom 示例图.png 2、通过依赖包导入js库文件 <script src"../node_modules/babel-standalone/babel.js"></script> <script src"../node_modules/react/umd/react.development.js"&g…

RK3568-鸿蒙5.1镜像烧录与调试

参考https://gitee.com/hihope_iot/docs/blob/master/HiHope_DAYU200/docs/%E7%83%A7%E5%BD%95%E6%8C%87%E5%AF%BC%E6%96%87%E6%A1%A3.md https://blog.csdn.net/pengjiadashaoye/article/details/144448126 固件烧录 缺了3个 , 没找着,烧录试试看 ,看了参考也不太一样 缺了…

游戏引擎学习第294天:增加手套

准备战斗 我们正在进行的是第294天的开发&#xff0c;目前暂时没有特别确定要做的内容&#xff0c;但我们决定继续研究移动模式相关的部分。虽然一些小型实体系统已经在运行&#xff0c;但并不确定最终效果如何。 今天我们决定实现一个全新的功能&#xff1a;战斗系统。这是游…

C# Try Catch Finally 执行顺序是什么?有返回值呢?

Try Catch Finally 执行顺序是什么&#xff1f;有返回值呢&#xff1f; 大部分程序员都认为&#xff1a;C#异常处理执行顺序&#xff0c;很简单&#xff0c;没什么可说的。 正常情况&#xff1a;执行顺序为 1、3(下图) 异常情况&#xff1a;执行顺序为1、2、3 文章目录 Tr…

水库雨水情测报与安全监测系统解决方案

一、方案概述 本水库雨水情测报与安全监测解决方案的核心目标在于利用尖端的技术手段&#xff0c;确保对水库雨水情势以及大坝安全状况的持续监控和及时预警&#xff0c;从而为水库的稳定运行提供坚实的支持和保障。该方案严格遵循“统筹协调、因库制宜、实用有效、信息共享”的…

架构选择/区别

目录 一、分层架构&#xff08;Layered Architecture&#xff09; 二、微服务架构&#xff08;Microservices Architecture&#xff09; 三、分布式架构&#xff08;Distributed Architecture&#xff09; 四、单体架构&#xff08;Monolithic Architecture&#xff09; 五…