redis实现分布式锁踩坑记录
这里主要记录项目中使用基于redis的分布式锁所遇到的问题及解决方案;
业务场景
我的业务场景是这样的,我们服务有库存模块,而我的服务又是多节点部署,要高峰期会存在库存差异,后面分析问题之后,打算采用redis实现分布式锁(主要的原因是服务已经集成了redis,不需要做额外的配置)
踩坑1. 数据库事务超时
不要感觉奇怪,分布式锁怎么会导致数据库事务超时呢?
我的代码大概是这样的:
伪代码 @Transaction(readOnly=false) void update(){ do{ redis=JedisUtil.getJedis(); flag = getLock(key,redis); if(flag){ update(); } }while(true) }
当你的key长时间获取不到锁,并且数据库事务都有超时时间的限制,那么就会出现数据库事务超时问题;
解决方案
数据库事务改为手动提交事务;
踩坑2. redis key过期,而业务没有执行完
我的key的过期时间设置的是30s,如果30秒业务还没有执行完毕,锁就会自动释放,锁释放之后,其它线程又会去占用锁,同样会导致问题的发生;
解决方案
最简单的解决方案就是使用redisson;
如果非要用redis来解决的话,只能使用定时器去检测key,如果说key还有2秒就快过期了,那么再为key重新设置30秒的过期时间;
踩坑3. redis连接池爆满
分布式锁刚加上之后,生产出现一个问题,就是:redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
解决办法
开始查代码,发现是开发人员没有对连接进行释放;
修复bug之后,又在线上跑了一段时间,又出现了redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
解决办法
void update(){ do{ redis=JedisUtil.getJedis(); flag = getLock(key,redis); if(flag){ update(); }else{ // 释放当前redis连接 // 由于我们的业务场景属于比较耗时的业务型,所以在这里休眠1000毫秒 redis.close(); sleep(1000); } }while(true) }
1.当前请求获取锁,如果获取不到,则释放当前连接,并休眠一会;
2.合理配置redis连接池大小,主要参考具体业务场景的并发量来设置;
踩坑4. 解铃还须系铃人
回顾一下加锁的参数:
set(key, vlue,"NX","PX", 30000);
其中:value,我使用它来表示加锁人,必须是一个唯一的标识
比如:
A线程 key=test value=01
B线程 key=test value=02如果A线程执行业务耗时超过了锁的持有时间,锁会自动释放;锁自动释放之后,线程B又加锁成功,但是,此时A线程执行完业务逻辑之后,去释放锁,但A线程的锁已经自动释放了,如果没有value来标识的话,它可能就会去释放B线程的锁;
踩坑5. redis集群实现分布式锁
这种情况我没有遇到,因为公司的redis集群做了改进;
先说一下这种问题产生的原因:
如果master节点由于某原因发生了主从切换,那么就会出现锁丢失的情况;
- 在master节点上拿到了锁;
- 但是这个加锁的key还没有同步到slave节点;
- master故障,发生故障转移,slave节点升级为master节点;
- 故导致锁丢失;
解决办法
需要通过使用redlock算法;
或使用redisson,它有对redlock算法做封装;

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
重磅! 全新国产OS系统降临:永久免费
继1月份国产操作系统UOS v20版发布之后,深度的Deepin v20操作系统正式发布了,带来了全新的Deepin桌面及全家桶软件,Linux 5.3内核,永久免费使用。 Deepin v20 beta版原本在2月份发布,因为深度Deepin的团队在武汉,之后因为疫情的原因延期到3月,然后几经波折到4月15日才正式推出。 与统信软件的UOS主打商业发行相比,Deepin v20是社区版,永久免费使用,双方大部分功能及资源库都是一样的。 以下是官方公告: 深度操作系统是一个致力于为全球用户提供美观易用、安全可靠的Linux发行版。 深度操作系统 20 Beta采取统一的设计风格,从桌面环境和应用重新进行设计,其中底层仓库、内核分别升级到Debian 10、Kernel 5.3,全新的设计带来不一样的交互体验,同时不断优化系统各个方面,带来更加丰富的应用生态和系统稳定性,本次深度应用家族也带来全新的设计和新的应用。 令您耳目一新的deepin桌面环境 焕然一新的图形界面,具备独树一帜的圆角窗口设计,自然、平滑的动画过渡效果,精美绝伦的多任务视图,别出心裁的配色与图标设计,处处精心,只为令...
- 下一篇
Java并发之显式锁和隐式锁的区别
Java并发之显式锁和隐式锁的区别 在面试的过程中有可能会问到:在Java并发编程中,锁有两种实现:使用隐式锁和使用显示锁分别是什么?两者的区别是什么?所谓的显式锁和隐式锁的区别也就是说说Synchronized(下文简称:sync)和lock(下文就用ReentrantLock来代之lock)的区别。 本文主要内容:将通过七个方面详细介绍sync和lock的区别。通过生活case中的X二代和普通人比较大家更容易理解这两者之间的区别 Java中隐式锁:synchronized;显式锁:lock sync和lock的区别 一:出身不同 从sync和lock的出身(原始的构成)来看看两者的不同。 Sync:Java中的关键字,是由JVM来维护的。是JVM层面的锁。 Lock:是JDK5以后才出现的具体的类。使用lock是调用对应的API。是API层面的锁 sync是底层是通过monitorenter进行加锁(底层是通过monitor对象来完成的,其中的wait/notify等方法也是依赖于monitor对象的。只有在同步块或者是同步方法中才可以调用wait/notify等方法的。因为只有在...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Hadoop3单机部署,实现最简伪集群
- MySQL8.0.19开启GTID主从同步CentOS8