总结
大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。
麻烦帮忙转发一下这篇文章+关注我
private static final int connectionTimeout = 5000;
private static final String lockPath = “/lockPath”;
private ZkClient client;
public ZkTemplateLock() {
client = new ZkClient(zkServers, sessionTimeout, connectionTimeout);
log.info(“zk client 连接成功:{}”,zkServers);
}
@Override
protected void waitLock() {
CountDownLatch latch = new CountDownLatch(1);
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println(“监听到节点被删除”);
latch.countDown();
}
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {}
};
//完成 watcher 注册
client.subscribeDataChanges(lockPath, listener);
//阻塞自己
if (client.exists(lockPath)) {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取消watcher注册
client.unsubscribeDataChanges(lockPath, listener);
}
@Override
protected boolean tryLock() {
try {
client.createEphemeral(lockPath);
System.out.println(Thread.currentThread().getName()+“获取到锁”);
} catch (Exception e) {
log.error(“创建失败”);
return false;
}
return true;
}
@Override
public void releaseLock() {
client.delete(this.lockPath);
}
}
缺点:
每次去竞争锁,都只会有一个线程拿到锁,当线程数庞大时会发生“惊群”现象,zookeeper节点可能会运行缓慢甚至宕机。这是因为其他线程没获取到锁时都会监听/lockPath节点,当A线程释放完毕,海量的线程都同时停止阻塞,去争抢锁,这种操作十分耗费资源,且性能大打折扣。
基于临时顺序节点方案
临时顺序节点与临时节点不同的是产生的节点是有序的,我们可以利用这一特点,只让当前线程监听上一序号的线程,每次获取锁的时候判断自己的序号是否为最小,最小即获取到锁,执行完毕就删除当前节点继续判断谁为最小序号的节点。
序列化节点
临时顺序节点
临时顺序节点操作源码
public class ZkSequenTemplateLock extends AbstractTemplateLock {
private static final String zkServers = “127.0.0.1:2181”;
private static final int sessionTimeout = 8000;
private static final int connectionTimeout = 5000;
private static final String lockPath = “/lockPath”;
private String beforePath;
private String currentPath;
private ZkClient client;
public ZkSequenTemplateLock() {
client = new ZkClient(zkServers);
if (!client.exists(lockPath)) {
client.createPersistent(lockPath);
}
log.info(“zk client 连接成功:{}”,zkServers);
}
@Override
protected void waitLock() {
CountDownLatch latch = new CountDownLatch(1);
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println(“监听到节点被删除”);
latch.countDown();
}
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {}
};
//给排在前面的节点增加数据删除的watcher,本质是启动另一个线程去监听上一个节点
client.subscribeDataChanges(beforePath, listener);
//阻塞自己
if (client.exists(beforePath)) {
try {
System.out.println(“阻塞”+currentPath);
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取消watcher注册
client.unsubscribeDataChanges(beforePath, listener);
}
@Override
protected boolean tryLock() {
if (currentPath == null) {
//创建一个临时顺序节点
currentPath = client.createEphemeralSequential(lockPath + “/”, “lock-data”);
System.out.println(“current:” + currentPath);
}
//获得所有的子节点并排序。临时节点名称为自增长的字符串
List childrens = client.getChildren(lockPath);
//排序list,按自然顺序排序
Collections.sort(childrens);
if (currentPath.equals(lockPath + “/” + childrens.get(0))) {
return true;
} else {
//如果当前节点不是排第一,则获取前面一个节点信息,赋值给beforePath
int curIndex = childrens.indexOf(currentPath.substring(lockPath.length() + 1));
beforePath = lockPath + “/” + childrens.get(curIndex - 1);
}
System.out.println(“beforePath”+beforePath);
return false;
}
@Override
public void releaseLock() {
System.out.println(“delete:” + currentPath);
client.delete(currentPath);
}
}
Curator分布式锁工具
curator提供了以下种类的锁:
-
共享可重入锁(Shared Reentrant Lock):全局同步锁,同一时间不会有两个客户端持有一个锁
-
共享锁:与共享可重入锁类似,但是不可重入(有时候会因为这个原因造成死锁)
-
共享可重入读写锁
-
共享信号量
-
Multi Shared Lock:管理多种锁的容器实体
我们采用第一种Shared Reentrant Lock中的InterProcessMutex来完成上锁、释放锁的的操作
public class ZkLockWithCuratorTemplate implements Lock { // zk host地址 private String host = "localhost"; ### 最后 在面试前我整理归纳了一些面试学习资料,文中结合我的朋友同学面试美团滴滴这类大厂的资料及案例 ![](https://img-blog.csdnimg.cn/img_convert/f10257b0616e58cbdd4884adb4f6b542.webp?x-oss-process=image/format,png) ![MyBatis答案解析](https://img-blog.csdnimg.cn/img_convert/5054cf0ba8042dea936adf1fc7c70b15.webp?x-oss-process=image/format,png) **由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!** 大家看完有什么不懂的可以在下方留言讨论也可以关注。 觉得文章对你有帮助的话记得关注我点个赞支持一下! > **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录** **[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)** -2pyNUVoA-1715612540744)] **由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!** 大家看完有什么不懂的可以在下方留言讨论也可以关注。 觉得文章对你有帮助的话记得关注我点个赞支持一下! > **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录** **[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**