redis setnx 原子性_技术篇 | 分布式锁漫游指南:Redis篇

本文介绍了Redis实现分布式锁的原因和方式,包括利用SETNX和EXPIRE命令,以及通过LUA脚本保证原子性。同时,文章讨论了使用Redisson作为更完善的分布式锁解决方案,提供自动续期、可重入锁等功能,并展示了Redisson的配置和使用示例。
摘要由CSDN通过智能技术生成
40dbc89691b1ded3a11f9f1ce629753c.png

题外话:标题来自于道格拉斯·亚当斯的经典科幻小说《银河系漫游指南》

目前越来越多的应用使用负载均衡,以往传统单体应用单机部署的情况下使用的JAVA并发处理资源竞争方式(J.U.C或synchronized等)在集群部署中已经无法保证资源的安全访问。

为什么需要分布式锁

需要考虑以下情况:

  • 只允许一个客户端操作共享资源:这种情况下,对共享资源的操作一般是非幂等性操作。在这种情况下,如果出现多个客户端操作共享资源,就可能意味着数据不一致,数据丢失。

  • 允许多个客户端操作共享资源:对共享资源的操作一定是幂等性操作,无论你操作多少次都不会出现不同结果。在这里使用锁,无外乎就是为了避免重复操作共享资源从而提高效率。

为了解决分布式应用中对资源的安全访问于是便有了分布式锁。

实现分布式锁一般基于Zookeeper或者Redis,前者可靠性高而后者效率高

如果并发量不大但是追求可靠性那么可以选择Zookeeper,反之可以选择Redis。

Redis实现分布式锁

分布式锁一大特点就是排他性,临界条件下仅有获得锁的调用者才能访问资源。

Redis是基于内存设计的K-V数据库且单线程执行命令。所以使用Redis作为分布式锁的中间件具有两个重要的优势:

  • 基于内存:加锁/解锁效率高

  • 单线程:请求先后顺序执行没有并发冲突,所以任意时刻只有一个调用者能成功获取锁。

而且Redis支持集群部署(sentinel, cluster),保障了可用性。

可以利用Redis提供的两个命令(SETNX和DEL)实现加锁和解锁的操作。

加  锁

使用SETNX()便可以完成加锁操作。setnx的含义就是SET if Not Exists,其主要有两个参数 setnx(key, value)。该方法是原子的,如果key不存在,则设置当前key成功,返回1;如果当前key已经存在,则设置当前key失败,返回0。

setnx key value
507026a3ef7fb6e5c2fdafc57afb86b0.png

这样便只允许一个调用者可以访问。等等似乎少了什么?没错我们没有设置KEY的过期时间,如果此时调用者宕机这把锁就无法释放了。

我们使用EXPIRE加上过期时间,默认单位为秒。

EXPIRE key seconds
65a42f0fb772ec8ead35bdec47ba19f0.png

但是这样做就完了吗?SETNX跟EXPIRE是两个独立的操作,即加锁操作不具备原子性。假如加锁调用成功,但是设置过期时间的时候调用服务宕机,依然存在锁无法正常释放的问题。

于是我们还需要把这两条命令合为一条命令。

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
  • expiration:过期时间,EX表示秒,PX表示毫秒

  • NX:表示如果不存在则写入(显然我们需要这条语句)

  • XX:表示如果存在则写入

7639facd707838995df3d702822bddd5.png

目前终于算是完成了原子加锁命令并且锁存在过期时间即使调用者宕机到期之后也会自动释放。

解  锁

使用DEL便可以删除锁。

DEL key [key ...]
42ef9b2c771f500dc30a3baf3e4b5645.png

但是事情不是这么简单的,因为:

  • 假设调用者A加锁成功并且设置锁超时时间为30秒。但是因为某些原因导致调用者A处理业务逻辑所花费的时间超过了30秒。

  • 锁超时自动释放之后调用者B刚好加锁成功,这时调用者A使用DEL语句释放了调用者B的锁。

  • 因为锁被调用者A释放导致后续的调用者可以参与锁竞争,例如调用者C获取到锁。

  • 从而发送在同一个时间内调用者B与调用者C同时运行业务逻辑从而破坏了资源的安全访问。

如图所示:

7fa094359f78f894e5f289bc7bf7e821.png

从图中可以发现A、B有并行,B、C有并行不符合我们的要求。

那么怎样才能让调用者只能释放自己占用的锁呢?这个时候K-V中的V就发挥作用了。如果我们的Value都是唯一(例如

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值