接上篇:一套方案轻松实现Zookeeper服务器动态上下线和分布式锁 ...

打印 上一主题 下一主题

主题 510|帖子 510|积分 1530

ZooKeeper是⼀个典型的发布/订阅模式的分布式数据管理与协调框架,我们可以使⽤它来进⾏分布式 数据的发布与订阅。另⼀⽅⾯,通过对ZooKeeper中丰富的数据节点类型进⾏交叉使⽤,配合Watcher 事件通知机制,可以⾮常⽅便地构建⼀系列分布式应⽤中都会涉及的核⼼功能,如数据发布/订阅、命名 服务、集群管理、Master推举、分布式锁和分布式队列等。那接下来就针对这些典型的分布式应⽤场景 来做下先容。
Zookeeper的两⼤特性:
===============


  • 1.客户端如果对Zookeeper的数据节点注册Watcher监听,那么当该数据节点的内容或是其⼦节点 列表发⽣变更时,Zookeeper服务器就会向订阅的客户端发送变更通知。
  • 2.对在Zookeeper上创建的暂时节点,⼀旦客户端与服务器之间的会话失效,那么暂时节点也会被 ⾃动删除
利⽤其两⼤特性,可以实现集群呆板存活监控系统,若监控系统在/clusterServers节点上注册⼀个 Watcher监听,那么但凡进⾏动态添加呆板的操作,就会在/clusterServers节点下创建⼀个暂时节 点:/clusterServers/[Hostname],这样,监控系统就能够实时监测呆板的变更情况。
服务器动态上下线监听:
===========
分布式系统中,主节点会有多台,主节点大概由于任何原因出现宕机大概下线,⽽恣意⼀台客户端都要 能实时感知到主节点服务器的上下线。
思绪分析:

具体实现:
服务端:
// 1 连接ZK
// 2 创建暂时顺序节点,数据内容写ip和端口
// 3 创建时间服务线程
import org.I0Itec.zkclient.ZkClient;
//服务端主要提供了client需要的一个时间查询服务,服务端向zk建立暂时节点
public class Server {
//获取zkclient
ZkClient zkClient = null;
private void connectZk() {
// 创建zkclient
zkClient = new ZkClient(“linux121:2181,linux122:2181”);
//创建服务端建立暂时节点的目录
if (!zkClient.exists(“/servers”)) {
zkClient.createPersistent(“/servers”);
}
}
//告知zk服务器相干信息
private void saveServerInfo(String ip, String port) {
final String sequencePath = zkClient.createEphemeralSequential(“/servers/server”, ip + “:” + port);
System.out.println(“----->>> ,服务器:” + ip + “:” + port + “,向zk生存信息成功,成功上线可以接受client查询”);
}
public static void main(String[] args) {
//准备两个服务端启动上线(多线程模拟,一个线程代表一个服务器)
final Server server = new Server();
server.connectZk();
server.saveServerInfo(args[0], args[1]);
//提供时间服务的线程没有启动,创建一个线程类,可以吸取socket请求
new TimeService(Integer.parseInt(args[1])).start();
}
}
服务端提供时间查询的线程类:
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
//提供时间查询服务
public class TimeService extends Thread {
private int port = 0;
public TimeService(int port) {
this.port = port;
}
@Override
public void run() {
//通过socket与client举行交流,启动serversocket监听请求
try {
//指定监听的端口
final ServerSocket serverSocket = new ServerSocket(port);
//保证服务端不停运行
while (true) {
final Socket socket = serverSocket.accept();
//不关心client发送内容,server只思量发送一个时间值
final OutputStream out = socket.getOutputStream();
out.write(new Date().toString().getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
client端:
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
// 注册监听zk指定目录,
//维护自己本地一个servers信息,收到通知要举行更新
//发送时间查询请求并接受服务端返回的数据
public class Client {
//获取zkclient
ZkClient zkClient = null;
//维护一个serversi 信息集合
ArrayList infos = new ArrayList();
private void connectZk() {
// 创建zkclient
zkClient = new ZkClient(“linux121:2181,linux122:2181”);
//第一次获取服务器信息,所有的子节点
final List childs = zkClient.getChildren(“/servers”);
for (String child : childs) {
//存储着ip+port
final Object o = zkClient.readData(“/servers/” + child);
infos.add(String.valueOf(o));
}
//对servers目录举行监听
zkClient.subscribeChildChanges(“/servers”, new IZkChildListener() {
public void handleChildChange(String s, List children) throws Exception {
//吸取到通知,说明节点发生了变革,client需要更新infos集合中的数据
ArrayList list = new ArrayList();
//遍历更新过后的所有节点信息
for (String path : children) {
final Object o = zkClient.readData(“/servers/” + path);
list.add(String.valueOf(o));
}
//最新数据覆盖老数据
infos = list;
System.out.println(“–》吸取到通知,最新服务器信息为:” + infos);
}
});
}
//发送时间查询的请求
public void sendRequest() throws IOException {
//目的服务器地址
final Random random = new Random();
final int i = random.nextInt(infos.size()); //随机选择一个服务器
final String ipPort = infos.get(i);
final String[] arr = ipPort.split(“:”);
//建立socket连接
final Socket socket = new Socket(arr[0], Integer.parseInt(arr[1]));
final OutputStream out = socket.getOutputStream();
final InputStream in = socket.getInputStream();
//发送数据
out.write(“query time”.getBytes());
out.flush();
//吸取返回效果
final byte[] b = new byte[1024];
in.read(b);//读取服务端返回数据
System.out.println(“client端吸取到server:+” + ipPort + “+返回效果:” + new String(b));
//开释资源
in.close();
out.close();
socket.close();
}
public static void main(String[] args) throws InterruptedException {
final Client client = new Client();
client.connectZk(); //监听器逻辑
while (true) {
try {
client.sendRequest(); //发送请求
} catch (IOException e) {
e.printStackTrace();
try {
client.sendRequest();
} catch (IOException e1) {
e1.printStackTrace();
}
}
//每隔几秒中发送一次请求到服务端
Thread.sleep(2000);
}
}
}
分布式锁:
=====
1.什么是锁:
=======


  • 在单机步伐中,当存在多个线程可以同时改变某个变量(可变共享变量)时,为了保证线程安全 (数据不能出现脏数据)就需要对变量或代码块做同步,使其在修改这种变量时能够串⾏执⾏消除并 发修改变量。
  • 对变量大概堆代码码块做同步本质上就是加锁。⽬的就是实现多个线程在⼀个时间同⼀个代码块只 能有⼀个线程可执⾏
2. 分布式锁
========
分布式的环境中会不会出现脏数据的情况呢?雷同单机步伐中线程安全的问题。观察下⾯的例⼦:

上⾯的设计是存在线程安全问题。
问题:
假设Redis ⾥⾯的某个商品库存为 1;此时两个⽤户同时下单,此中⼀个下单请求执⾏到第 3 步,更新 数据库的库存为 0,但是第 4 步还没有执⾏。
⽽另外⼀个⽤户下单执⾏到了第 2 步,发现库存还是 1,就继续执⾏第 3 步。但是商品库存已经为0, 所以如果数据库没有限制就会出现超卖的问题。
解决方案:

公司业务发展迅速,系统应对并发不停提⾼,解决⽅案是要增长⼀台呆板,效果会出现更⼤的问题:


利⽤Zookeeper可以创建暂时带序号节点的特性来实现⼀个分布式锁。
分布式锁的作⽤:在整个系统提供⼀个全局、唯⼀的锁,在分布式系统中每个系统在进⾏相干操作的时 候需要获取到该锁,才气执⾏相应操作。
zk实现分布式锁:
=========
利⽤Zookeeper可以创建暂时带序号节点的特性来实现⼀个分布式锁。
实现思绪:


  • 锁就是zk指定⽬录下序号最⼩的暂时序列节点,多个系统的多个线程都要在此⽬录下创建暂时的顺 序节点,由于Zk会为我们保证节点的顺序性,所以可以利⽤节点的顺序进⾏锁的判断。
  • 每个线程都是先创建暂时顺序节点,然后获取当前⽬录下最⼩的节点(序号),判断最⼩节点是不是 当前节点,如果是那么获取锁成功,如果不是那么获取锁失败。
  • 获取锁失败的线程获取当前节点上⼀个暂时顺序节点,并对对此节点进⾏监听,当该节点删除的时 候(上⼀个线程执⾏结束删除大概是掉线zk删除暂时节点)这个线程会获取到通知,代表获取到了 锁。
流程图:
自我先容一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里不停到现在。
深知大多数Java工程师,想要提拔技能,每每是自己探索成长大概是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易遇到天花板技术停滞不前!
因此网络整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够资助到想自学提拔又不知道该从何学起的朋友,同时减轻各人的负担。



既有适合小白学习的零底子资料,也有适合3年以上经验的小伙伴深入学习提拔的进阶课程,根本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会连续更新!
如果你觉得这些内容对你有资助,可以扫码获取!!(备注Java获取)
最后

如果觉得本文对你有资助的话,不妨给我点个赞,关注一下吧!


《互联网大厂面试真题剖析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
以上经验的小伙伴深入学习提拔的进阶课程,根本涵盖了95%以上Java开发知识点,真正体系化!**
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会连续更新!
如果你觉得这些内容对你有资助,可以扫码获取!!(备注Java获取)
最后

如果觉得本文对你有资助的话,不妨给我点个赞,关注一下吧!
[外链图片转存中…(img-UbZkDcFa-1712929727931)]
[外链图片转存中…(img-ewnQt6dq-1712929727931)]
《互联网大厂面试真题剖析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

花瓣小跑

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表