分布式锁的原理与实现 一、分布式锁的原理

一、分布式锁的使用场景

  在web开发中,我们经常会用到单机无法支撑业务的情况,比如,当在访问量比较大的情况下,单机的速度可能会很慢,因为同一时间单机的处理速度是有限的,这时我们就可以使用分布式来解决上述问题,由nginx来做一个负载均衡,把负载均匀的分布在多台单机上。

  当我们使用了分布式的架构后,问题也就随之而来了。比如一个业务我们需要串行化实现(通俗的说,也就是同一时间只能处理一个请求),那该怎么办呢?疑问

  举一个例子,现在需要实现一个领券的接口,一个券会对应多个券码,用户领取的是对应的券码,我们的处理逻辑如下:


  乍一看流程很简单,我们只需要从数据库中取出一个可用的券码,然后与用户绑定即可,这不是一个很简单的问题么大笑。可是仔细考虑一下,这里面其实是有并发问题的。

  比如,现在数据库中只有一个券码,按道理来说只允许有一个人来领取。但是这时候如果有两个请求同时过来,我们都走到了第一步,从数据库取出一个可用的券码,两个请求都取出来了。然后再进行绑定,然后返回成功。这时候就出现了问题。本来只允许一个人来领取,结果有两个人都领取成功了,就出现了bug。

  有人说了,解决这种情况使用java里面的 synchronized 关键字不就行了,但是这是在单机的情况下,可以保证多个线程下的安全,如果是分布式呢?有多台单机呢?java里面的 synchronized 就不行了。所以这种情况下,我们需要使用分布式锁,保证在分布式的情况下也能串行的处理业务。


二、分布式锁的原理

  分布式锁如何实现呢?如何保证在分布式的情况下串行处理?疑问

  这时候需要使用到Redis,众所周知,Redis是一个高性能的key-value内存数据库。我们可以使用里面的 set Nx 命令,即在没有这个key的时候设置value。当设置成功后,表示我们拿到了这个分布式锁,即可以执行我们的业务,在业务执行成功后,使用 del 命令来删除对应的分布式锁的key。

  即,我们需要一个分布式锁的key,这个key是与对应分布式业务挂钩的。比如上述场景,我们使用一个 distributed_key_card_code 来作为key,然后在需要执行业务之前使用 set Nx 来设置 distributed_key_card_code 这个key-value。如果成功了,即可以处理业务。

  但是上述处理还有一些问题,具体在生产环境中的处理逻辑见下:


三、分布式锁的问题

  上述处理会带来两个问题:

  1、如果没有获取到分布式锁怎么办?

  使用 synchronized 关键字时,如果没有获取到锁,会一直等待,直到获取锁。那么按照上述逻辑,如果没有获取到分布式锁,那么有两种处理逻辑,一种是直接失败,一种即是重试,即在指定时间内一直重试(当然中间会有暂停),我们知道前端在请求接口中是有超时时间的,如果我们在这些时间内没有获取到分布式锁,那么就只能失败了。

  2、假如在一个分布式系统中,有三台单机,分别是单机A、单机B、单机C。这时候假如单机A拿到了分布式锁,然后单机A宕机了,单机B和单机C岂不是拿不到分布式锁了?

  是的,这个问题很致命,所以我们需要给分布式锁设置一个超时时间,避免因为单机的宕机导致整个分布式锁系统的崩溃。

  3、如果设置超时时间,比如一个分布式锁给设置5s的超时时间,假如单机A设置了这个超时时间,但是单机A在5s内没有完成业务,然后单机B拿到了锁,这之后单机A完成了业务,把分布式锁删除了,这时候单机C就拿到了这个分布式锁。导致了单机B、单机C同一时间都在处理业务。

  解决这个问题的方案就是,一个单机在获取分布式锁的时候,即使用 setNx 命令的时候,给对应的分布式锁的key设置一个随机的value值,然后记住这个value值,当完成业务后,get分布式锁的value,当发现是之前自己设置的value时,才删除分布式锁。


四、分布式锁的实现:

  在下一节中,我们实现了基于Redis的分布式锁,地址为 分布式锁的原理与实现 二、分布式锁的基础实现   





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值