目录
- 分布式锁
- 分布式锁的引出
- 单体锁存在的问题
- 分布式锁的引出
- 分布式锁的设计思路
- 分布式锁的常见应用场景
- 分布式锁方案
分布式锁
分布式锁的引出
单体锁存在的问题
在单体应用中,如果我们对共享数据不进行加锁操作,多线程操作共享数据时会出现数据一致性问题。
我们的解决办法通常是加锁。如加单体锁(synchronized或RentranLock)来保证单个实例并发安全:
但上锁代码块内线程只能串行执行,效率低。单体应用难以满足实际高并发访问需求,我们会将单体应用部署到多个tomcat实例上,由负载均衡将请求分发到不同实例上。
一个tomocat实例是一个JVM进程,单体锁(synchronized、ReentrantLock)是JVM层面的锁,只能控制单个实例上的并发访问安全,多实例下依然存在数据一致性问题。
分布式锁的引出
由于单体锁是基于 JVM 层面上的锁,只能控制单个实例上的并发访问安全,多个实例下依然存在数据一致性的问题,这个时候,就轮到我们的分布式锁出场了。
分布式锁是指:所有服务中的所有线程都去获取同一把锁,但只有一个线程可以成功获取锁,其他没有获取锁的线程必须全部等待,直到持有锁的线程释放锁。分布式锁可以跨越多个JVM,跨越多个进程的锁。
分布式锁的设计思路
由于Tomcat是由Java启动的,所以每个Tomcat可以看成一个JVM,JVM内部的锁是无法跨越多个进程的。所以,我们要实现分布式锁,我们只能在这些JVM之外去寻找,通过其他的组件来实现分布式锁。系统的架构如图所示:
两个Tomcat通过第三方的组件实现跨JVM、跨进程的分布式锁。这就是分布式锁的解决思路,找到所有JVM可以共同访问的第三方组件,通过第三方组件实现分布式锁。
分布式锁的常见应用场景
一般电商网站都会遇到秒杀、特价之类的活动,大促活动有一个共同特点就是访问量激增,在高并发下会出现成千上万人抢购一个商品的场景。虽然在系统设计时会通过限流、异步、排队等方式优化,但整体的并发还是平时的数倍以上,参加活动的商品一般都是限量库存,如何防止库存超卖,避免并发问题呢?分布式锁就是一个解决方案。
我们都知道,在业务开发中,为了保证在多线程下处理共享数据的安全性,需要保证同一时刻只有一个线程能处理共享数据。
Java 语言给我们提供了线程锁,开放了处理锁机制的 API,比如 Synchronized、Lock 等。当一个锁被某个线程持有的时候,另一个线程尝试去获取这个锁会失败或者阻塞,直到持有锁的线程释放了该锁。在单台服务器内部,可以通过线程加锁的方式来同步,避免并发问题,那么在分布式场景下呢?
分布式锁的目的是保证在分布式部署的应用集群中,多个服务在请求同一个方法或者同一个业务操作的情况下,对应业务逻辑只能被一台机器上的一个线程执行,避免出现并发问题。分布式场景下解决并发问题,需要应用分布式锁技术。
文章部分内容部分引自:Redis实现分布式锁
分布式锁方案
实现分布式锁目前有三种流行方案,即基于数据库、Redis、ZooKeeper 的方案。