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); } ListchildrenList = 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条)