用redis实现分布式锁时容易踩的5个坑

简介: 云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 近有不少小伙伴投入短视频赛道,也出现不少第三方数据商,为大家提供抖音爬虫数据。 小伙伴们有没有好奇过,这些数据是如何获取的,普通技术小白能否也拥有自己的抖音爬虫呢? 本文会全面解密抖音爬虫的幕后原理,不需要任何编程知识,还请耐心阅读。

云栖号资讯:【点击查看更多行业资讯
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!


我的业务场景是这样的,我们服务有库存模块,而我的服务又是多节点部署,要高峰期会存在库存差异,后面分析问题之后,打算采用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

解决办法

    do{
        redis=JedisUtil.getJedis();
        flag = getLock(key,redis);
        if(flag){
            update();
        }else{
            // 释放当前redis连接
            // 由于我们的业务场景属于比较耗时的业务型,所以在这里休眠1000毫秒
            redis.close();
            sleep(1000);
        }
    }while(true)
}

当前请求获取锁,如果获取不到,则释放当前连接,并休眠一会;

合理配置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算法做封装。

【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live

立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK

原文发布时间:2020-04-16
本文作者:Java圈子
本文来自:“掘金”,了解相关信息可以关注“掘金”

相关文章
|
8月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
550 2
|
8月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
590 6
|
9月前
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
7月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
643 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
7月前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
9月前
|
NoSQL Redis
Lua脚本协助Redis分布式锁实现命令的原子性
利用Lua脚本确保Redis操作的原子性是分布式锁安全性的关键所在,可以大幅减少由于网络分区、客户端故障等导致的锁无法正确释放的情况,从而在分布式系统中保证数据操作的安全性和一致性。在将这些概念应用于生产环境前,建议深入理解Redis事务与Lua脚本的工作原理以及分布式锁的可能问题和解决方案。
333 8
|
10月前
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
2828 7
|
NoSQL Java 关系型数据库
浅谈Redis实现分布式锁
浅谈Redis实现分布式锁
|
存储 canal 缓存
|
NoSQL PHP Redis
redis实现分布式锁
redis实现分布式锁
343 0
redis实现分布式锁
下一篇
开通oss服务