利用redis实现分布式锁

199 阅读2分钟

业务里为什么要使用分布式锁

商城业务

在上面的商城业务中,由于没有进行发货的校验,且数据库使用的是mongodb并不支持事务,所以导致会出现两次发货请求

如何解决此问题

利用redis实现分布式锁

那么问题来了,如何利用redis实现分布式锁:

redis数据结构

  1. 字符串
  2. 列表
  3. hash
  4. zset
  5. 集合 这里面先介绍下redis的字符串数据结构,说到字符串其实是最常见和最长使用的数据机构够,无论是在编程语言(java)还是数据库中都有用到,也是作者比较熟悉的数据结构

如何使用

  • 首先使用redis 设置一个key

示例: setnx key value

  • 设置一个过期时间

    Q1:为什么要设置一个过期时间

    A1:理论上使用setnx命令已经可以实现一个分布式锁了,但是这里存在一个问题, 对于分布式锁来说如果不进行解锁那么就会陷入死锁,导致业务逻辑出现问题。例如当一笔订单发货失败后,如果一直没有解锁,那么这笔订单就算是丢单了。但是解锁如果失败了也会出现同样的问题。所以给当前的key设置一个过期时间是很重要的。

    Q2:过期时间设置多久

    A2:我们业务里的过期时间是3秒。

  • 使用lua脚本设置

    Q1: 为什么使用lua脚本设置 A1: 首先setnx 和过期时间的设置不是事务的,也就是说可能过期时间没有设置成功。这样会导致死锁,redis支持使用lua脚本来实现redis的事务。

实践

if (redis.call('setnx',KEYS[1],ARGV[1]) < 1) then return 0; end; redis.call('expire',KEYS[1],tonumber(ARGV[2])); return 1;

解锁

解锁的实现基本和加锁一样,同样是使用lua脚本来删除key的

if (redis.call('get', KEYS[1]) == ARGV[1])
    then return redis.call('del', KEYS[1])
else return 0
end

最后

微信公众号地址