前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >redis分布式锁解决多进程/多线程下单个进程/单个线程运行

redis分布式锁解决多进程/多线程下单个进程/单个线程运行

作者头像
公众号guangcity
发布2021-09-18 14:57:24
发布2021-09-18 14:57:24
1.1K00
代码可运行
举报
文章被收录于专栏:光城(guangcity)光城(guangcity)
运行总次数:0
代码可运行

redis分布式锁解决多进程/多线程下单个进程/单个线程运行

1.导语

在业务开发中像订单写入,一般需要单线程来保证订单写入数据库,防止数据多次被插入。

最近,有两台容器,当程序运行时,会发送多份通知,那么需要保证同一时刻只有一个进程(一台容器)来运行,此时用分布式锁解决该问题。

业界也有许多解决这种方案,这里以redis分布式锁来解决。

简单来说就是采用golang redis库实现下面方案即可。

2.redis的分布式锁实现

2.1 setnx+expire

setnx key value,将key设置为value,当键不存在时,才能成功,若键存在,什么也不做,成功返回1,失败返回0。

SETNX实际上就是SET IF NOT Exists的缩写。

代码语言:javascript
代码运行次数:0
运行
复制
setnx key val
expire key seconds

但是,上述两个操作不具有原子性,如果执行完第一条指令应用异常或者重启了,锁将无法过期。

2.2 lua脚本

既然是原子性无法保证,那就采用执行lua脚本的原子性,将上述两个操作封装到lua脚本中便可以实现。

代码语言:javascript
代码运行次数:0
运行
复制
if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then
   redis.call('expire',KEYS[1],ARGV[2])
else
   return 0
end;

2.3 携带TTL的set

从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改。

代码语言:javascript
代码运行次数:0
运行
复制
SET key value [EX seconds] 
[PX milliseconds] [NX|XX]

将字符串值 value 关联到 key 。

如果 key 已经持有其他值, SET 就覆写旧值,无视类型。

对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。

  • EX second :设置键的过期时间为 second 秒。SET key value EX second 效果等同于 SETEX key second value 。
  • PX millisecond :设置键的过期时间为 millisecond 毫秒。SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
  • NX :只在键不存在时,才对键进行设置操作。SET key value NX 效果等同于 SETNX key value 。
  • XX :只在键已经存在时,才对键进行设置操作。

直接使用可能存在如下问题:

  • 超时解锁导致并发

例如:如果线程 A 成功获取锁并设置过期时间 30 秒,但线程 A 执行时间超过了 30 秒,锁过期自动释放,此时线程 B 获取到了锁,线程 A 和线程 B 并发执行。

A、B 两个线程发生并发显然是不被允许的,一般有两种方式解决该问题:

解决方案:1)确保代码在过期时间之前释放。2)为获取锁的线程增加守护线程,为将要过期但未释放的锁增加有效时间。

  • 锁被别的线程误删除。

例如:如果线程 A 成功获取到了锁,并且设置了过期时间 30 秒,但线程 A 执行时间超过了 30 秒,锁过期自动释放,此时线程 B 获取到了锁;随后 A 执行完成,线程 A 使用 DEL 命令来释放锁,但此时线程 B 加的锁还没有执行完成,线程 A 实际释放的线程 B 加的锁。

解决方案是:通过在 value 中设置当前线程加锁的标识,在删除之前验证 key 对应的 value 判断锁是否是当前线程持有。可生成一个 UUID 标识当前线程,使用 lua 脚本做验证标识和解锁操作。

学习文章:

https://xiaomi-info.github.io/2019/12/17/redis-distributed-lock/

https://zhuanlan.zhihu.com/p/115848078

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • redis分布式锁解决多进程/多线程下单个进程/单个线程运行
    • 1.导语
    • 2.redis的分布式锁实现
      • 2.1 setnx+expire
      • 2.2 lua脚本
      • 2.3 携带TTL的set
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档