1.什么是分布式锁,为什么需要分布式锁?
答:随着互联网的发展,单机项目已经远远不能满足市场的需求,许多项目开始使用基于springCloud和dubbo的分布式解决方案,但是由于许多项目采用集群方案部署,导致jvm自带的synchronized、Lock等不能满足项目的需求,例如当实现商品秒杀时,前端的高并发请求会同时访问不同的服务器,当你使用synchronized或者Lock的时候,只能锁定本台服务器的某个方法或代码块。这时候分布式锁就显得尤为重要。
2.分布式锁有哪几种结局方案?
答:基于zookeeper解决方案、基于redis解决方案、基于数据库的解决方案
3.zookeeper方案是如何解决的,原理是什么?
答:zookeeper官网数据结构图
这个是官网的zookeeper数据图,从图中就可以看出zookeeper是一种树形的数据结构,它存贮数据的地方就是它的节点,zookeeper分布式锁也是基于此来做的,当某个程序获得锁之后,创建一个临时节点,其它并发请求获取锁的时候,先判断一下,该节点存不存在,若存在则等待并监听,不存在,创建临时节点获取锁。当程序运行完断开连接,或者删除临时节点来进行锁释放。
4.zookeeper如何使用代码来实现分布式锁?
答:pom.xml文件
<!--zookeeper客户端-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.11</version>
</dependency>
接口
/**
* @author oumiga
*/
public interface ZookeeperLock {
/**
* 获取锁
*/
public void lock();
/**
* 释放锁
*/
public void closeLock();
}
抽象类
import org.I0Itec.zkclient.ZkClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
/**
* @author oumiga
*/
public abstract class AbstractZookLock implements ZookeeperLock {
@Value("${zookeeper.LockIp}")
protected String zookeeperIp;
protected ZkClient zkClient;
protected String elementName = "/lock";
protected CountDownLatch countDownLatch;
@Override
public void lock() {
boolean lock = tryLock();
if(!lock){
waitLock();
lock();
}
}
/**
* 关闭连接,释放锁
*/
@Override
public void closeLock() {
if(Objects.nonNull(zkClient)){
zkClient.close();
}
}
public abstract boolean tryLock();
public abstract void waitLock();
/**
* 获取Zkclient对象
* @return
*/
public ZkClient getZkClient(){
if(zkClient == null){
if(StringUtils.isEmpty(zookeeperIp)){
new ZkClient(zookeeperIp);
return zkClient;
}
zkClient = new ZkClient("127.0.0.1");
return zkClient;
}
return zkClient;
}
}
抽象实现类
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
/**
* @author oumiga
*/
public class ZookLockImpl extends AbstractZookLock {
/**
* 尝试获取锁
* @return
*/
@Override
public boolean tryLock() {
try{
ZkClient zkClient = getZkClient();
if(!zkClient.exists(elementName)){
return false;
}
zkClient.createEphemeral(elementName);
countDownLatch = new CountDownLatch(1);
return true;
}catch(Exception e){
return false;
}
}
/**
* 等待锁释放
*/
@Override
public void waitLock() {
ZkClient zkClient = getZkClient();
IZkDataListener iZkDataListener = new IZkDataListener() {
//监听数据的改变
@Override
public void handleDataChange(String s, Object o) throws Exception {
}
//监听数据的删除
@Override
public void handleDataDeleted(String s) throws Exception {
if(Objects.nonNull(countDownLatch)){
countDownLatch.countDown();
}
}
};
//监听节点
zkClient.subscribeDataChanges(elementName,iZkDataListener);
if(zkClient.exists(elementName)){
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
zkClient.unsubscribeDataChanges(elementName,iZkDataListener);
}
}
工具使用类
/**
* @author oumiga
*/
public class zookLockUtils {
private static ZookeeperLock zookeeperLock = new ZookLockImpl();
/**
* 获取锁
*/
public static void lock(){
zookeeperLock.lock();
}
/**
* 释放锁
*/
public static void closeLock(){
zookeeperLock.closeLock();
}
}