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

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

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

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

因为线程会交替执行,所以线程查询优惠价的数据量后,线程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。

相关推荐
草莓熊Lotso4 小时前
【Redis 初阶】Set 类型深度解析:去重集合的运算能力与实战场景
linux·网络·数据库·windows·redis·tcp/ip·缓存
煎饼皮皮侠5 小时前
【设计】设计一个web版的数据库管理平台后端(之五) --借鉴mybatis
数据库·mybatis
东风破_11 小时前
danci 2:创建的单词书到底存在哪里?从 Supabase 一路理解 ORM、Drizzle 和 RLS
数据库·后端·node.js
橙子家13 小时前
OSS 文件上传的几个风险点和解决方案
数据库
2601_9620664914 小时前
【Sql Server】Update中的From语句,以及常见更新操作方式
android·java·数据库
愤怒的苹果ext15 小时前
MySQL Shell备份恢复数据库
数据库·mysql·备份恢复·mysqlsh
数字新视界17 小时前
DCIM管理系统的技术架构与部署模式详解
数据库·物联网·数据中心·数据中心基础设施管理·dcim管理系统
何以解忧,唯有..17 小时前
Pydantic 介绍与使用:Python 数据校验的现代方案
数据库·python·microsoft
小白勇闯网安圈17 小时前
String、Hash、List、Set 四大数据结构与通用命令
redis
这个DBA有点耶18 小时前
数据库容灾进入“秒级时代”:同城双活架构原理、关键技术选型与落地实践
数据库·架构·dba