在什么情况下需要分布式锁?

举个栗子:

高并发下争夺共享资源,比如秒杀对于库存这种共享资源需要用到分布式锁,如果不用分布式锁很可能造成超卖。

分布式锁也是锁

  • 在单体应用的时候,如果多个线程要访问共享资源的时候,我们通常线程间加锁的机制,在某一个时刻,只有一个线程可以对这个资源进行操作,其他线程需要等待锁的释放,Java中也有一些处理锁的机制,比如synchronized。

  • 而到了分布式的环境中,当某个资源可以被多个系统访问使用到的时候,为了保证大家访问这个数据是一致性的,那么就要求再同一个时刻,只能被一个系统使用,这时候线程之间的锁机制就无法起到作用了,因为分布式环境中,系统是会部署到不同的机器上面的,那么就需要【分布式锁】了。
    在这里插入图片描述

什么时候需要使用分布式锁

总结来看,当有多个客户端需要访问并操作同一个资源,还需要保持这个资源一致性的时候,就需要使用【分布式锁】,让多客户端互斥的对共享资源进行访问。

举个例子来说明一下:

  • 有多个批处理任务,两台机器同时处理,如果不加任何控制的话,很有可能同一个批处理被两台机器分别处理一遍;如果使用分布式锁,在领取任务的时候,一个任务只会被一台机器领到,这样就不会造成任务的重复执行;

  • 再多思考一些,如果A/B两台机器,任务1被A机器领取到进行处理,在处理到一半的时候,A机器挂掉了,那么这个批处理任务也就无法顺利执行了,除非A机器可以恢复。

在这里插入图片描述

这时候就可以知道分布式锁需要做哪些工作了

  • 排他性:在同一时间只会有一个客户端能获取到锁,其它客户端无法同时获取;
  • 避免死锁:锁在一段时间内有效,超过这个时间后会被释放(正常释放或异常释放);
  • 高可用:获取或释放锁的机制必须高可用且性能佳。

在这里插入图片描述

使用场景

当你的后端服务是以集群形式存在的时候,是一定需要分布式锁的。集群与分布式不同,而这里的分布式与分布式锁也不是同一回事儿。集群可以指多台服务器实现了同样的需求,比如有三台Tomcat,都负责查询模块;而分布式指多台服务器各自不同的功能点,多台功能的整合对外是一个完整的服务,比如一台Tomcat负责查询,一台负责下单。

说回集群,当后端集群要去访问同一个资源的时候,就需要对该资源加锁,保证同一时刻只能有一个对象来修改该资源数据,如果不加锁会导致什么情况呢?

举一个例子:

有两个线程(分别叫T1,T2)做的都是同样的事情,拿到一个叫做A的资源,然后对其进行+1操作。由于线程之间是不会互相通信的,于是就有可能出现下面这种情况:

T1拿到A,读入内存,此时A值为T;

T2拿到A,读入内存,此时A值为T;

T1进行+1操作,此时A实际值为T+1;

T2进行+1操作,此时A的实际值仍然为T+1;

然而,此时A经过两个线程执行+1操作,应该为T+2才对的,所以可以看出,如果没有分布式锁,就会出现数据不一致的问题。如果是上面这种简单的计算还好,如果是你的银行账户,没用分布式锁,此时有两个人给你打钱,结果只有其中一个人的到账了,另一个人的被作为无主钱财被银行充公了,肯定是不行的吧。

所以,保障数据一致性和准确性就是分布式锁的重要性。

如何实现

在这里可以给大家介绍一个用redis来实现分布式锁的方案。

Redis对外开放了一个非常厉害的api,目前经常被大家用来做分布式锁,是绝对的线程安全,这个函数就是SET key field value加上NX参数。这个NX参数可是了不得,通常来说,set函数是不管field字段是否存在,只要写入成功就会返回1,但是如果增加了NX参数,那么如果field值在redis中已经存在,就会返回nil,否则才返回1。因此可以通过这个函数来执行加锁操作,如果返回值不为nil,则加锁成功,否则代表有其他线程在操作数据,当前请求需要等待。

不仅如此,为了避免死锁,SET还有一个参数为EX,即EX毫秒后,field会自动清空。

此外,还有PX,XX参数,具体含义见如下文档。

在这里插入图片描述

非分布式环境下,用锁可以解决什么?

多线程环境下,共享资源的线程安全问题!这个时候的共享资源通常是在单机里面的多线程里存在竞争,从JAVA内存模型来看,可以通过锁住对象,锁住方法,锁住代码块等方式,避免共享资源的竞争!

在这里插入图片描述

而在分布式环境中,共享资源所要经过的代码,方法,都不是在一个JVM里面,也不是同一个进程!通过锁方法,代码块的方式不能解决共享资源的竞争,需要分布式的锁!

在这里插入图片描述

分布式锁通常在以下场景中使用:

1,全局ID的生成;

2,全局配置文件的修改;

3,分布式服务中的秒杀问题;

4,分布式环境下的重复提交;

分布式锁通常有以下实现方式:

1,使用数据库的唯一主键来实现锁!

2,使用redis的指令:通常使用setnx方法,incr方法等进行实现

3,使用zookeeper:使用api生成临时节点实现锁!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值