比如:一个资源变量A,在单体应用中,如果有多个线程同时来竞争该资源A,可以通过Synchronized、或者ReentrantLcok上锁来解决资源共享的问题。
但是,在分布式系统后,由于分布式系统是分布在不同机器上,布式系统中竞争共享资源的最小粒度从线程升级成了进程,这将使原单机并发控制锁策略失效。
图片
为了解决这个问题,就需要一种跨服务,跨JVM的锁机制,来控制共享资源的访问,这就是分布式锁。
分布式锁的实现
首先为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
图片
互斥性
任意时刻只能有一个客户端获取锁,不能同时有两个客户端获取到锁。
安全性
锁只能被持有该锁的客户端删除,不能由其它客户端删除。
死锁
获取锁的客户端因为某些原因,比如:down机等,而未能释放锁,其它客户端再也无法获取到该锁。
容错
当部分节点down机时,客户端仍然能够获取锁和释放锁。
常见的分布式锁的实现有:Redis分布式锁、Zookeeper分布式锁等方式来实现分布式锁。
如下所示:
import redis.clients.jedis.Jedis;
public class RedisDistributedLock {
private Jedis jedis;
private String lockKey;
private String lockValue; // 唯一标识,如UUID
private int expireTime; // 锁的过期时间,单位毫秒
public RedisDistributedLock(Jedis jedis, String lockKey, String lockValue, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.lockValue = lockValue;
this.expireTime = expireTime;
}
public boolean tryLock() {
// 尝试获取锁
String result = jedis.set(lockKey, lockValue, "NX", "PX", expireTime);
return "OK".equals(result);
}
}
单实例的Redis存在单点故障问题,推荐使用Redis集群、或哨兵模式以增加可用性。
分布式锁的应用场景
1.共享资源竞争
如果涉及到分布式环境(多机器)的资源竞争,多个进程同时操作共享资源,则需要分布式锁。
原因刚才已经讲过了,因为共享资源已经跨越到不同的服务器进程上了,java的锁已经锁不住了。
2.效率性
使用分布式锁可以避免不同节点重复相同的工作。
3.业务场景
在电商业务里,最常见的场景:扣减库存,以及在高并发的场景下,阻止流量打到后边等等。