redis分布式是如何实现的(面试版)

devtools/2024/12/22 3:00:37/

需要结合项目中的业务进行回答,通常情况下,分布式锁使用的场景集群情况下的定时任务、抢单、幂等性场景。

下面先来看一个抢卷场景:

以下情况会出现超卖情况:

因为线程会交替执行,所以线程查询优惠价的数据量后,线程2又查询优惠券的数据量,此时如果优惠券总数是1,最后优惠券的数量会变成-1,出现超卖。

使用synchronized解决:

但在集群的情况下,这种方式(本地加锁)会失效,因为synchronized是本地锁,这个锁属于JVM,每个服务都有各自的JVM,它只能解决同一个JVM下线程的互斥:

此时需要加分布式锁:

redis分布式

什么是分布式锁:支持分布式集群环境下的锁

基于redis来实现分布式锁,底层使用的是setnx和lua脚本。

                                                                        图1-1 

上图中,必须设置锁的超时时间,否则当服务宕机的时候就不会释放锁了。

redisson实现的分布式锁如何合理控制锁的有效时长

继续看图1-1,因为加锁的时候给了一个失效时间,假如业务的执行时机太长,已经超出了锁的释放时间,但此时业务还没有执行完成,假如其他线程来获得锁就会获得成功

出现这种情况后,可以给锁续期:redisson实现的分布式-执行流程:

  1. 有一个线程(线程1)过来,它获取锁并加锁成功后,然后就会去操作redis
  2. 加锁成功后,会另开一个线程(Watch dog)监控  持有锁的线程给持有锁的线程 增加锁的持有时间(续期)。续期的规则为每隔 releaseTime/3(releaseTime是锁的过期时间) 的时间做一次续期,默认为10秒。
  3. 手动释放锁,手动释放锁之后,需要通知对应线程的Watch dog不需要再监听了

                                                                        图2-1

假如,现在又来了一个新的线程(线程2),想获取锁,它先尝试去加锁,如果加锁成功,和 图2-1的流程是一样的,但如果没有加锁成功呢?redisson实现的分布式锁中,它设置了一个while循环来不断的尝试去加锁,如果加锁成功了就成功了,如果线程1一直没有释放锁,线程2有一个阈值,只要循环到了阈值,线程2就会获取锁失败,这种机制会在高并发下,大程度增加分布式锁的性能:

下图为redisson的使用,所有的redisson命令基于lua脚本完成,保证脚本执行的原子性

redisson实现的分布式锁是否可以重入

首先分析下图的代码:

  • 在add1中尝试获取了锁,再去调用add2,add又去尝试获取锁,此时都是同一个线程,可以重入。

回答:可以重入,判断是否是当前线程,通过线程id去判断,如果是同一个线程就可重入,否则不能

redisson中可重入的实现

使用hash类型来存储锁数据(线程的唯一标识和重入次数):

  • 每加一次锁,重入次数都会+1,每释放一次锁重入次数-1,全部释放完变成0后删除锁信息。

redisson实现的分布式锁可以保证主从一致吗

不能解决,但可以使用红锁保证主从一致,但性能太低,一般项目中用的不多,哪有服务器天天挂;如果想要保证数据的强一致性就去使用CP思想的zookeeper。


http://www.ppmy.cn/devtools/101925.html

相关文章

探索Git:分布式版本控制系统的力量(二)

😀前言 本篇博文是关于分布式版本控制系统Git的一些基本介绍,希望你能够喜欢 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我…

Android自定义一个带背景的圆环形进度条(Kotlin)

前言 在Android开发过程中,难免遇到一些复杂的UI组件需要我们自定义 当然使用系统原生组件拼凑也能完成,但是UI复杂度增加了不说,在更新UI状态的时候还不好管理,最重要的是复用的价值不大,上述的操作很容易引增加码冗…

Oracle字符串聚合函数LISTAGG

在Oracle 19c中,LISTAGG函数是一个非常有用的字符串聚合函数,它可以将来自多个行的值连接成一个单独的字符串。这个函数特别适用于将分组内的多个值合并为一个逗号分隔(或其他分隔符)的字符串。 LISTAGG函数的基本语法如下&#…

LeetCode 3133.数组最后一个元素的最小值:位运算+双指针

【LetMeFly】3133.数组最后一个元素的最小值&#xff1a;位运算双指针 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-array-end/ 给你两个整数 n 和 x 。你需要构造一个长度为 n 的 正整数 数组 nums &#xff0c;对于所有 0 < i < n - 1 &#xff0…

网络游戏运营

游戏运营是将一款游戏平台推入市场&#xff0c;并通过一系列的策略和行动&#xff0c;使玩家从接触、认识到最终成为忠实玩家的过程。这一过程涵盖了多个方面&#xff0c;包括前期准备、上线运营、活动策划、数据分析、渠道合作以及用户维护等。以下是对游戏运营的详细解析&…

用ChatGPT精确营销:如何让AI深度理解并推广你的产品

在现代商业中,人工智能(AI)正迅速成为企业成功的关键因素之一。ChatGPT作为一种强大的语言模型,不仅能回答问题,还能通过深度理解和互动,帮助企业精准推广产品。然而,如何让ChatGPT真正了解并有效地推广你的产品,是许多使用者面临的挑战。在本文中,我们将探讨如何通过…

debian/ubuntu 通过串口连接WiFi

修改 /etc/wpa_supplicant.conf&#xff0c;如果没有这个文件就创建文件 vi /etc/wpa_supplicant.conf设置wifi信息 network{ssid"这里是你的wifi账号"psk"这里是你的wifi密码" }连接wifi killall wpa_supplicant wpa_supplicant -i wlan0 -c /etc/wpa_…

SQLite 插入数据并返回自增ID

要插入数据并返回自增ID&#xff0c;我们可以使用SQLite的last_insert_rowid()函数。这个函数返回了最后一次插入操作的自增ID。 下面我们通过一个示例来演示如何插入数据并返回自增ID。 首先&#xff0c;创建一个表来存储学生信息&#xff1a; CREATE TABLE students (id I…