
CAP指的是 一致性(Consistency) ,可用性(Availability), 分区容错性(Partition tolerance)
eureka ap zookeeper cp redis cp
Eureak选择AP 保证了可用性降低了一致性 , Zookeeper 就是 CP ; Redis AP ; Nacos 默认 AP ,可以 CP和AP可以切换
可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁,也要释放多少次 ReentrantLock和sychronized是可重入锁 拿到锁情况下就是不需要排队就可以在此拿到锁
!!而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁
公平锁依次顺序 非公平锁
//可以看看源码
RLock redissonLock = redissonClient.getLock(“redissonLock”);
//参数:等待时间,过期时间,时间单位
boolean lockFlag = redissonLock.tryLock(1, 10, TimeUnit.SECONDS);
if (lockFlag) {
try {
//业务逻辑
} finally {
redissonLock.unlock();
}
}
Redis分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能。Zookeeper分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小
Redis获取锁的那个客户端bug了或者挂了,那么只能等待超时时间之后才能释放锁;而Zookeeper的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁
redis的性能高于zk太多了,可在可靠性上又远远不如zk redis锁响应更快,对并发的支持性能更好
//启动客户端
zkCli.sh -server 127.0.0.1:2181
ls get set delete
Znode分为四种类型: 持久节点 默认(PERSISTENT)持久节点顺序节点(PERSISTENT_SEQUENTIAL) 临时节点(EPHEMERAL)与zookeeper断开连接后,临时节点会被删除
公平锁:顺序临时节点!!,只需要注册个检测器在上一个节点 不会引起羊群效应!!
非公平锁:抢占式 都只创建一个节点!!
死锁问题:出现异常情况下,没来得及删除节点,锁将一直被占用无法释放 惊群效应:可以看到输出日志里面,有很大比例都是删除回调事件。原因是所有服务实例同时监听此节点,每次的释放锁删除节点都会触发回调事件,而所有等待锁的服务实例都会接收回调,并执行抢占代码,那么将造成通信,服务器资源不必要的浪费
zookeeper锁的过程就是先创建一个永久节点,在其下面创建临时有序子节点,并且在前一个节点上创建监听事件 占用锁节点被删除后再去递归!getLock
com.101tec zkclient0.10
public class ZookeeperTest {
public static void main(String[] args) throws InterruptedException {
List threadList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threadList.add(new Thread(new Runnable() {
@Override
public void run() {
ZookeeperClient zkLock = new ZookeeperClient();
zkLock.getLock();
try {
Thread.sleep(1*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
zkLock.unlock();
}
}));
}
threadList.forEach(thread -> thread.start());
Thread.sleep(1000000);
}
}
class ZookeeperClient{
// 锁节点路径
final String LOCK_PATH = "/Lock";
// 当前锁节点路径
private String currentPath;
// 前一个锁节点路径
private String prevPath;
ZkClient zkClient = new ZkClient("192.168.31.30", 45 * 1000);//指的是获取锁后的连接时间
public void getLock() {
System.out.println("getLock");
// 尝试获取锁
if (tryLock()) {
System.out.println(Thread.currentThread().getName() + " 获取锁成功");
} else {
// 等待锁
waitLock();
// 再次获取锁
getLock();
}
}
public boolean tryLock() {
//先创建锁节点路径
if (!zkClient.exists(LOCK_PATH)) {
zkClient.createPersistent(LOCK_PATH);
}
if (currentPath == null) {
//创建有序节点
currentPath = zkClient.createEphemeralSequential(LOCK_PATH + "/", "testdata");
System.out.println("创建节点:" + currentPath);
}
List childrenList = zkClient.getChildren(LOCK_PATH);
Collections.sort(childrenList);//会导致有序123
if (currentPath.equals(LOCK_PATH + "/" + childrenList.get(0))) {
return true;
} else {
int currentIndex = childrenList.indexOf(currentPath.substring(LOCK_PATH.length() + 1));
prevPath = LOCK_PATH + "/" + childrenList.get(currentIndex - 1);
return false;
}
}
public void waitLock() {
CountDownLatch countDownLatch = new CountDownLatch(1);
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataChange(String s, Object o) {
}
@Override
public void handleDataDeleted(String s) {
System.out.println("收到节点:" + s + "被删除的消息");
countDownLatch.countDown();
}
};
// 注册监听器
zkClient.subscribeDataChanges(prevPath, listener);
// 检查该节点是否存在
if (zkClient.exists(prevPath)) {
try {
// 阻塞等待节点的删除事件
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 解除监听
zkClient.unsubscribeDataChanges(prevPath, listener);
}
public void unlock() {
// 释放锁
releaseLock();
}
public void releaseLock() {
zkClient.delete(currentPath);
}
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)