分布式系统专题第八章-分布式锁

Posted by Ethan Blog on February 5, 2022

在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。那具体什么是分布式锁,分布式锁应用在哪些业务场景、如何来实现分布式锁呢? 本章节基于redis的redlock讲解

Redlock

全名叫做 Redis Distributed Lock; 即使用redis实现的分布式锁;

使用场景

多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击)

最低保证分布式锁的有效性及安全性的要求如下:

  • 1.互斥;任何时刻只能有一个client获取锁
  • 2.释放死锁;即使锁定资源的服务崩溃或者分区,仍然能释放锁
  • 3.容错性;只要多数redis节点(一半以上)在使用,client就可以获取和释放锁

redis单实例中实现分布式锁的正确方式

1、 设置锁

设置锁时,使用set命令,因为其包含了setnx,expire的功能,起到了原子操作的效果,value设置随机值,并且只有在key不存在时才设置成功返回True,并且设置key的过期时间(最好用毫秒)

1
SET key_name my_random_value NX PX 30000 

NX 表示if not exist 就设置并返回True,否则不设置并返回False PX 表示过期时间用毫秒级, 30000 表示这些毫秒时间后此key过期

2、解锁

在获取锁后,并完成相关业务后,需要删除自己设置的锁(必须是只能删除自己设置的锁,不能删除他人设置的锁),最好使用Lua脚本删除

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

流程图如下

img

总结:

  • 1.TTL时长 要大于正常业务执行的时间+获取所有redis服务消耗时间+时钟漂移
  • 2.获取redis所有服务消耗时间要远小于TTL时间,并且获取成功的锁个数要 在总数的一半以上:N/2+1
  • 3.尝试获取每个redis实例锁时的时间要远小于TTL时间
  • 4.尝试获取所有锁失败后重新尝试一定要有一定次数限制
  • 5.在redis崩溃后(无论一个还是所有),要延迟TTL时间重启redis
  • 6.在实现多redis节点时要结合单节点分布式锁算法共同实现