为什么要使用分布式锁

业务场景:

系统A是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会给用户下单。

由于系统有一定的并发,所以会预先将商品的库存保存在redis中,用户下单的时候会更新redis的库存。

此时系统架构如下:

但是这样一来会产生一个问题:假如某个时刻,redis里面的某个商品库存为1,此时两个请求同时到来,其中一个请求执行到上图的第3步,更新数据库的库存为0,但是第4步还没有执行。

而另外一个请求执行到了第2步,发现库存还是1,就继续执行第3步。

这样的结果,是导致卖出了2个商品,然而其实库存只有1个。

很明显不对啊!这就是典型的库存超卖问题

我们很容易想到解决方案:用锁把2、3、4步锁住,让他们执行完之后,另一个线程才能进来执行第2步。


按照上面的图,在执行第2步时,使用Java提供的synchronized或者ReentrantLock来锁住,然后在第4步执行完之后才释放锁。

Synchronized(this){

//扣减库存逻辑代码

……


}

这样一来,2、3、4 这3个步骤就被“锁”住了,多个线程之间只能串行化执行。

但是好景不长,整个系统的并发飙升,一台机器扛不住了。现在要增加一台机器,如下图:


增加机器之后,系统变成上图所示,我的天!

假设此时两个用户的请求同时到来,但是落在了不同的机器上,那么这两个请求是可以同时执行了,还是会出现库存超卖的问题。

为什么呢?因为上图中的两个A系统,运行在两个不同的JVM里面,他们加的锁只对属于自己JVM里面的线程有效,对于其他JVM的线程是无效的。

因此,这里的问题是:Java提供的原生锁机制在多机部署场景下失效了

这是因为两台机器加的锁不是同一个锁(两个锁在不同的JVM里面)。

那么,我们只要保证两台机器加的锁是同一个锁,问题不就解决了吗?

此时,就该分布式锁隆重登场了,分布式锁的思路是:

在整个系统提供一个全局、唯一的获取锁的“东西”,然后每个系统在需要加锁时,都去问这个“东西”拿到一把锁,这样不同的系统拿到的就可以认为是同一把锁。

至于这个“东西”,可以是Redis、Zookeeper,也可以是数据库。

文字描述不太直观,我们来看下图:


通过上面的分析,我们知道了库存超卖场景在分布式部署系统的情况下使用Java原生的锁机制无法保证线程安全,所以我们需要用到分布式锁的方案。

那么,如何实现分布式锁呢?请看我的下一篇文章

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。