当前位置: 首页 > news >正文

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。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Unity URPShader支持多光源处理
  • Qt杂项功能实现
  • Linux 数据结构 树知识
  • 学习bat脚本
  • 自然语言处理系列四十七》Elasticsearch搜索引擎》Elasticsearch代码实战
  • 川崎机器人维修请开启马达电源报警故障
  • 使用Lora微调LLM——笔记
  • okhttp异步请求连接阻塞问题排查
  • cenos 7 安装 golang
  • vue3 自定义hooks(组合式函数)
  • PHP语言有哪些优势和特点?
  • C——四种排序方法
  • 84、 k8s的pod基础+https-harbor
  • 行级安全的艺术:SQL中的精细化数据保护策略
  • C++中类的相关学习
  • [case10]使用RSQL实现端到端的动态查询
  • 【5+】跨webview多页面 触发事件(二)
  • 03Go 类型总结
  • Codepen 每日精选(2018-3-25)
  • CSS 三角实现
  • css系列之关于字体的事
  • JAVA 学习IO流
  • javascript数组去重/查找/插入/删除
  • Java-详解HashMap
  • Js基础知识(四) - js运行原理与机制
  • php的插入排序,通过双层for循环
  • python docx文档转html页面
  • Python打包系统简单入门
  • QQ浏览器x5内核的兼容性问题
  • SpringCloud集成分布式事务LCN (一)
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 从零开始学习部署
  • 从重复到重用
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 批量截取pdf文件
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 翻译 | The Principles of OOD 面向对象设计原则
  • 回归生活:清理微信公众号
  • #if 1...#endif
  • #LLM入门|Prompt#3.3_存储_Memory
  • (CPU/GPU)粒子继承贴图颜色发射
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (Python) SOAP Web Service (HTTP POST)
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (三十)Flask之wtforms库【剖析源码上篇】
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (已解决)Bootstrap精美弹出框模态框modal,实现js向modal传递数据
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • (最全解法)输入一个整数,输出该数二进制表示中1的个数。
  • .gitignore
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .Net Winform开发笔记(一)
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .net实现头像缩放截取功能 -----转载自accp教程网
  • .net与java建立WebService再互相调用