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 = (“redissonLock”);
//参数:等待时间,过期时间,时间单位
boolean lockFlag = (1, 10, );
if (lockFlag) {
try {
//业务逻辑
} finally {
();
}
}
Redis分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能。Zookeeper分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小
Redis获取锁的那个客户端bug了或者挂了,那么只能等待超时时间之后才能释放锁;而Zookeeper的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁
redis的性能高于zk太多了,可在可靠性上又远远不如zk redis锁响应更快,对并发的支持性能更好
//启动客户端
-server 127.0.0.1:2181
ls get set delete
Znode分为四种类型: 持久节点 默认(PERSISTENT)持久节点顺序节点(PERSISTENT_SEQUENTIAL) 临时节点(EPHEMERAL)与zookeeper断开连接后,临时节点会被删除
公平锁:顺序临时节点!!,只需要注册个检测器在上一个节点 不会引起羊群效应!!
非公平锁:抢占式 都只创建一个节点!!
死锁问题:出现异常情况下,没来得及删除节点,锁将一直被占用无法释放 惊群效应:可以看到输出日志里面,有很大比例都是删除回调事件。原因是所有服务实例同时监听此节点,每次的释放锁删除节点都会触发回调事件,而所有等待锁的服务实例都会接收回调,并执行抢占代码,那么将造成通信,服务器资源不必要的浪费
zookeeper锁的过程就是先创建一个永久节点,在其下面创建临时有序子节点,并且在前一个节点上创建监听事件 占用锁节点被删除后再去递归!getLock
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
public class ZookeeperTest {
public static void main(String[] args) throws InterruptedException {
List threadList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
(new Thread(new Runnable() {
@Override
public void run() {
ZookeeperClient zkLock = new ZookeeperClient();
();
try {
(1*1000);
} catch (InterruptedException e) {
();
}
();
}
}));
}
(thread -> ());
(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() {
("getLock");
// 尝试获取锁
if (tryLock()) {
(().getName() + " 获取锁成功");
} else {
// 等待锁
waitLock();
// 再次获取锁
getLock();
}
}
public boolean tryLock() {
//先创建锁节点路径
if (!(LOCK_PATH)) {
(LOCK_PATH);
}
if (currentPath == null) {
//创建有序节点
currentPath = (LOCK_PATH + "/", "testdata");
("创建节点:" + currentPath);
}
List<String> childrenList = (LOCK_PATH);
(childrenList);//会导致有序123
if ((LOCK_PATH + "/" + (0))) {
return true;
} else {
int currentIndex = ((LOCK_PATH.length() + 1));
prevPath = LOCK_PATH + "/" + (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) {
("收到节点:" + s + "被删除的消息");
();
}
};
// 注册监听器
(prevPath, listener);
// 检查该节点是否存在
if ((prevPath)) {
try {
// 阻塞等待节点的删除事件
();
} catch (InterruptedException e) {
();
}
}
// 解除监听
(prevPath, listener);
}
public void unlock() {
// 释放锁
releaseLock();
}
public void releaseLock() {
(currentPath);
}
}