一篇讲明白分布式锁
1.什么是分布式锁?
分布式锁是一种在分布式系统中用来协调多个进程或线程对共享资源的访问机制。它的主要目的是防止多个进程或线程同时访问或修改共享资源,从而避免数据冲突和一致性问题。
在单机(单个jvm)环境中,通常可以使用jdk提供的互斥锁(如线程锁)来实现同步,但在分布式(多个JVM)系统中,各个进程或线程可能运行在不同的机器上,因此需要一种特殊的机制来实现同步,这就是分布式锁。
2.实现一个分布式锁考虑的点?
互斥性:一个分布式锁,最基本的就是在同一时间,只能有一个线程访问共享数据的互斥原则。
避免死锁:死锁问题不得不考虑,特别是在分布式环境中,由于网络原因,节点宕机等,必须考 虑超时时间及死锁检查机制。
阻塞或非阻塞:这点要根据业务进行区分对待。
可重入:一个线程在获取到锁时,在没有释放锁时,是否可以继续获取该锁。
锁性能:在并发的情况下,加锁,释放锁的性能至关重要。
可靠性:锁是否可靠,关系着一个系统的存亡,业务的好坏。
其他:是否简单易用,是否复杂。
3.分布式锁实现方式?
数据库,Redisson(redis) Zookeeper
基于数据库:
这个好理解,就是获取锁时进行insert into ,释放锁时 delete 。
出现几个问题:
- 过度依赖数据库,可能有点问题。
- 没有锁的实效时间,一旦delete失败,就阻塞在这里了。
- 是一把非重入的锁,无法重新获取该锁。
基于Redisson:
引入Maven jar包,业务代码中注入 RedissonClient。调用getLock(Key),加锁/设置过期间 lock(,)释放锁 unLock.
出现几个问题:
1. 单点问题。
基于Zookeeper:
Zookeeper是分布式协调服务中间件,它的职责是保证数据在旗下保持同步一致,故Zookeeper是CP强一致性。基于zookeeper的临时有序节点实现分布式锁。一般使用三方库Curator客户端。
<dependency>
<groupId>curator</groupId>
<artifactId>curator</artifactId>
<version>0.0.7</version>
</dependency>
代码如下:
加锁 /解锁
InterProcessMutex interProcessMutex = new InterProcessMutex(client, "/lock");
try{
//加锁
interProcessMutex.acquire(Long long,TimeUnit unit);
if (interProcessMutex.isAcquiredInThisProcess()) {
//执行业务逻辑
}else{
//其他逻辑
}
}catch(Exception e){
e.printStackTrace();
}finally {
try {
// 释放锁
if (interProcessMutex.isAcquiredInThisProcess()) {
interProcessMutex.release();
System.out.println("Lock released");
}
} catch (Exception e) {
e.printStackTrace();
}
}
4.redis和Zookeeper 比较?
主要在如下方面体现,性能方面,自动释放,一致性,高可用
性能 | 自动释放 | 一致性 | 高可用 | |
redis | 内存 | 有时效(设置超时时间) | AP | 高 |
zookeeper | 磁盘 | 无时效 | CP | 中(在集群情况出现过半选举机制) |
5.经验总结
Redis 实现的分布式锁、性能更好,可用性更高。ZK 实现的分布式锁可以自动释放,减少死锁出现的概率,并且他的一致性更有保障。
所以,如果你的分布式锁使用场景,对性能要求更高,可以牺牲一点一致性,那么就选择 Redis的分布式锁。而如果你的场景对性能要求没那么高,但是对一致性要求非常高,那么则可以选择 Zookeeper。