使用Redis分布式锁控制请求串行处理

1.需求背景

在一些写接口的场景下,由于一些网络因素导致用户的表单重复提交,就会在相邻很短的时间内,发出多个数据一样的请求。后台接口的幂等性保证一般都是先检查数据的状态,然后决定是否进行执行写入操作,最后更新状态。那么在这个很短的时间内,数据可能还没来及写入,多个请求同时进入了状态判断的逻辑,此时就可能绕过检查,执行多次重复的写入。

在此给出的解决方案是,使用redis分布式锁,控制用户的请求串行处理:客户端的请求进入时,基于用户的维度进行抢锁,抢到了就可以往下执行逻辑,抢不到锁的请求直接被拒绝。

2.redis分布式锁的使用

2.1.使用下面的命令获取锁:

 SET resource_name my_random_value EX 100 NX

当 resource_name 不存在的时候设置,将值设置为 my_random_value 同时指定 100秒过期时间,my_random_value 必须在锁定请求中绝对唯一,用于后面的解锁释放。

2.2.使用Lua脚本解锁:

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

这段Lua脚本执行的时候将 resource_name 作为 KEYS[1],将 my_random_value 作为 ARGV[1] 的值传进去,只有当 my_random_value 的值恰好是之前存的值,才删除它。

3. Redlock算法的高级锁

Redlock算法 的介绍可以看Redis官网,关于这个算法的安全性问题,发生过一场 争论 ,在此不展开分析。

就我目前的业务中是直接使用云厂商 集群版的redis,客户端的连接上只有一个实例,业务开发时等效于单机版来使用,云厂商负责后面的主从支持。那么使用单redis节点的锁方案就足够了,简单且效率高;用不了,也没法用 Redlock算法的高级锁方案。其实,最后是一个问题,有没有必要去使用 Redlock这个过重的实现?还是看个人负责的业务场景吧,就我目前的业务需求是用不上的,也许后续会有更严苛的业务场景,到那时再会。

参考资料

  1. Distributed locks with Redis – Redis
  2. How to do distributed locking — Martin Kleppmann’s blog
posted @ 2020-12-03 20:44  MarsZuo  阅读(671)  评论(0编辑  收藏  举报