伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

大厂的Redis锁竟然是这么用的,难怪不会超卖!

来源:本站原创 浏览:49次 时间:2023-07-18
1 本地锁

常用的即 synchronize 或 Lock 等 JDK 自带的锁,只能锁住当前进程,仅适用于单体架构服务。 而在分布式多服务实例场景下必须使用分布式锁

2 分布式锁

2.1 分布式锁的原理

厕所占坑理论

可同时去一个地方“占坑”:

  • 占到,就执行逻辑
  • 否则等待,直到释放锁

可通过自旋方式自旋

“占坑”可以去Redis、DB、任何所有服务都能访问的地方。

2.2 分布式锁演进

一阶段

// 占分布式锁,去redis占坑Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");if(lock) {    //加锁成功... 执行业务    Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();    redisTemplate . delete( key: "lock");//fHßti    return dataF romDb ;} else {    // 加锁失败,重试。synchronized()    // 休眠100ms重试    // 自旋    return getCatalogJsonFromDbwithRedisLock();}关注公众号:麒麟改bug,可获取Redis实战学习笔记一份。

问题场景

  • setnx占好了坑,但是业务代码异常或程序在执行过程中宕机,即没有执行成功删除锁逻辑,导致死锁

解决方案:设置锁的自动过期,即使没有删除,会自动删除。

阶段二

// 1. 占分布式锁,去redis占坑Boolean lock = redisTemplate.opsForValue().setIfAbsent( "lock", "110")if(lock) {    // 加锁成功...执行业务    // 突然断电    // 2. 设置过期时间    redisTemplate.expire("lock", timeout: 30, TimeUnit.SECONDS) ;    Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();    //删除锁    redisTemplate. delete( key; "lock");    return dataFromDb;} else {    // 加锁失败...重试。 synchronized ()    // 休眠100ms重试    // 自旋的方式    return getCatalogJsonF romDbWithRedisLock();}

问题场景

  • setnx设置好,正要去设置过期时间,宕机,又死锁

解决方案:设置过期时间和占位必须是原子操作。redis支持使用setNxEx命令

阶段三

// 1. 分布式锁占坑Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "110", 300, TimeUnit.SECONDS);if(lock)(    // 加锁成功,执行业务    // 2. 设置过期时间,必须和加锁一起作为原子性操作    // redisTemplate. expire( "lock", з0, TimeUnit.SECONDS);    Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();    // 删除锁    redisTemplate.delete( key: "lock")    return dataFromDb;else {    // 加锁失败,重试    // 休眠100ms重试    // 自旋    return getCatalogJsonFromDbithRedislock()}

阶段四

已经拿到了 lockvalue ,有了 UUID,但是过期了现在!其他人拿到所锁设置了新值,于是 if 后将别人的锁删了!!也就是删除锁不是原子操作。

Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();String lockValue = redisTemplate.opsForValue().get("lock");if(uuid.equals(lockValue)) {    // 删除我自己的锁    redisTemplate.delete("lock");}

问题场景

  • 如果正好判断是当前值,正要删除锁时,锁已过期,别人已设置成功新值。那删除的就是别人的锁.
  • 解决方案

删除锁必须保证原子性。使用redis+Lua脚本。

阶段五

  • 确保加锁/解锁都是原子操作
String script =     "if redis.call('get', KEYS[1]) == ARGV[1]         then return redis.call('del', KEYS[1])     else         return 0     end";    关注公众号:麒麟改bug,可获取Redis实战学习笔记一份。

保证加锁【占位+过期时间】和删除锁【判断+删除】的原子性。 更难的事情,锁的自动续期。

  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net