Redis分布式锁以及集群下分布式锁的实现与问题
1、 分布式锁的相关概念

分布式系统的出现:单台机器的计算能力和存储都是有限的,之所以需要分布式系统,是为了摆脱单机资源的束缚,解决单台机器计算慢和存储少的问题。分布式计算框架,可以将复杂的计算任务分为小任务,交给不同的机器节点运算。分布式存储引擎,可以将大量的数据分成小部分数据,存储在不同的节点上。

分布式锁的概念:分布式锁与线程锁、进程锁相对应。线程锁只在同一JVM进程中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state)。进程锁是为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源。分布式锁是当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。分布式锁是一种跨进程,跨节点的一种互斥锁,它可以保证多个机器节点对访问共享资源的排他性。

分布式锁的特征:分布式锁与其他锁,既有相同点也有不同点,分布式锁的特征如下图所示:

在这里插入图片描述

2 、Redis实现分布式锁

​ Redis是一个单独的中间件,不同客户端可以往同一个Redis或者集群中加锁,这样就能保证加锁的地方或者是资源是相同的。并且由于Redis也是单线程的,同时也支持lua脚本,可以保证并发安全的问题,所以可以很简单的实现分布式锁的功能。

简单实现分布式锁:

客户端A:

127.0.0.1:6379> setnx lock 1 #使用setnx命令设置锁lock
(integer) 1  #设置成功
127.0.0.1:6379> del lock #释放锁lock
(integer) 1 #释放成功

客户端B:

127.0.0.1:6379> setnx lock 1 #尝试获取锁lock失败
(integer) 0 
127.0.0.1:6379> setnx lock 1 #客户端A释放后,获取lock锁
(integer) 1

​ 但是,这样设置分布式锁,当客户端A获取锁资源后,服务器宕机,就会出现死锁现象。未避免死锁,可设置锁的过期时间。

127.0.0.1:6379> set lock 1 ex 10 nx #设置锁lock的过期时间为10秒,防止出现死锁现象
OK

​ 获取锁资源的节点在锁过期时间之内未完成任务,会不断延长锁的过期时间,Redisson实现类自动续时的看门狗功能。

3 、Redis集群下的分布式锁

​ Redis单节点实现了分布式锁。如果你通过 Sentinel 有高可用,如果Master发生宕机,Master节点上锁信息没来得及去新的Master节点,就会发生锁丢失。在这种情况下,可能多个客户端拿到相同的锁,违反互斥性,Redlock 算法可以解决单点故障问题。

RedLock算法

RedLock需要5个完全独立的Redis服务器作Master。

使用步骤:

  • 获取当前时间戳,单位是毫秒。
  • 轮流用相同的Key和Value在5个Redis节点上请求上锁时,会有一个和总的锁释放时间比小的多的超时时间。
  • 客户端通过获取所有节点获取锁后的时间减去第一步的时间戳,这个时间要小于TTL时间并且至少要有三个Redis实例获取锁,才能说明真正获取锁成功。
  • 如果获取锁成功,则锁的真正有效时间是TTL减去第三步的时间差的时间。
  • 如果获取锁失败了,向所有Redis节点发送锁释放命令。

缺点:

  • 使用五个Redis服务器,成本高。
  • RedLock属于重锁,效率低。
  • 会出现分布式系统的NPC问题(Network Delay 、Process Pause、Clock Drift)。
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐