请简述选举机制(面试题)
1.半数机制:集群中半数以上的机器存活,集群可用,所以zookeeper适合安装奇数台服务器
2.zookeeper虽然在配置文件中没有指定Master,Slave,但是zookeeper,工作时,是有有个节点为Leaber,其他则为Follwer,Leader,是通过内部的选举机制临时产生的,
3.zookeeper选举流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cuWKnqJ1-1621866342253)(…/TypoarWrokPath/images/1618658450074.png)]
1.服务器1启动,此时只有它的服务器启动了,他发出的报文没有任何响应,所以他的选举状态一直是Looking状态
2.服务器2启动,它与最开始的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意所有服务器1,2都保持Looking状态,
3.服务器3启动,根据前面的分析,服务器3成为服务器1,2,3中的老大,与上面不同的是此时有三台服务器选举了它,所以它成为了这次选举的Leader
4.服务器4 启动根据前面的理论按照道理说应该服务器4是最大的但是由于前面的选举数已经超一半选服务器3,所以服务器4是能是顺从
5.服务器五和服务器4一样顺从前前面的选举
zookeeper的监听原理是什么?(面试题)
1.监听原理
1.首先要有一个main线程
2.在main线程中创建客户端,这时就会创建两个线程,一个负责网络连接通信 (connect),一个负责监听.
3.通过connect线程注册的监听事件发送给zookeeper
4.zookeeper的注册监听器列表中将注册的监听事件添加到列表中
5.zookeeper监听到数据有变化,就会将这个消息发送给listener线程
6.listener线程内部调用了process()方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VCMjO0yh-1621866342255)(…/TypoarWrokPath/images/1618682657936.png)]
2.常见的监听
1.监听节点数据的变化 [get path[watch]]
2.监听子节点增减的变化[ls path[watch]]
zookeeper的部署方式有哪几种?集群中的角色有哪些?,集群最少需要几台?
1.部署方式: 单机模式、集群模式
2.角色: leader和follower
3.集群最少需要集群数: 3台
zookeeper的常用命令
1.ls / 查看节点 ls 路径
2.create /node “lhh” 创建永久节点 在根目录下node 注意一定要带数据
3.create -e -s /node “lhh” 创建临时节点 并且带序号,序号不重复
3.get /node 查看数据 get 路径
4.delete /node 删除节点 delete 路径
5.set /node “lhh1” 修改节点数据 set 路径
6.rmr /node/node 递归删除 rmr 路径
1.概述
Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。
2.zookeeper工作机制
Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RDUDKe8Q-1621866342261)(…/TypoarWrokPath/images/1618684153039.png)]
3.zookeeper的特点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RfEkJUs5-1621866342264)(…/TypoarWrokPath/images/1618684393167.png)]
- Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。2)集群中只要有半数以上节点存活, Zookeeper集群就能正常服务。
3)全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的
4)更新请求顺序进行,来自同一个Client的更新请求按其发送顺序依次执行。
5)数据更新原子性,一次数据更新要么成功,要么失败。
6)实时性,在一定时间范围内,Client能读到最新数据。
4.zookeeper的数据结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n3Jvrg5j-1621866342265)(…/TypoarWrokPath/images/1618685123000.png)]
ZooKeeper数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode。每一个 ZNode默认能够存储lMB的数据,每个ZNode都可以通过其路径唯一标识。
5.zookeeper的应用场景
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等
6.zookeeper写数据流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QkPtxeAH-1621866342266)(…/TypoarWrokPath/images/1618685324363.png)]
1.client向zookeeper的server上写数据,发送一个写的请求
2.如果server不是leader,那么server1会把接收到的请求进一步转发给leade,因为每个zookeeper的server里面有一个是 leader,这个leader会将写请求广播给各个server,比如server1和server2,各个server写成功后就会通知leader
3.当leader收到大多数server数据写入成功了,那么说明数据写成功了,如果这个里三个节点的话,只要有两个节点数据写 成功了,那么认为数据写成功了,写成功之后leader就会告诉server数据写入成功
4.server会进一步通知client数据写成功了,这时就认为写操作成功.
7.zookeeper的负载均衡
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4BdnXqro-1621866342267)(…/TypoarWrokPath/images/1618686661604.png)]
8.服务器动态上下线
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xUouzGsM-1621866342268)(…/TypoarWrokPath/images/1618686709481.png)]
9.统一集群管理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dEvg7hpm-1621866342269)(…/TypoarWrokPath/images/1618686826259.png)]
10.统一配置管理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cF8WpFYP-1621866342270)(…/TypoarWrokPath/images/1618686898269.png)]
11.统一命名服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XKWO1RPh-1621866342271)(…/TypoarWrokPath/images/1618686885092.png)]
12.zookeeperApi操作
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
/**
* @program: lhh
* @description:
* @author: 华仔
* @create: 2021-04-17 21:55
*/
public class ZookeeperApi {
//监听哪些zookeeper集群
private String connecString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
//会话的超时时间单位毫秒
private int sessionTimeout = 2000;
//Watcher 监听器
//zookeeper客户端对象
private ZooKeeper zkclit;
@Before //初始化
public void init() throws IOException {
zkclit = new ZooKeeper(connecString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
}
});
}
@Before //初始化用于获取子节点并监控数据节点的变化 getDataandWatch()方法
public void init() throws IOException {
zkclit = new ZooKeeper(connecString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("**********************strat******************");
List<String> children = null;
try {
children = zkclit.getChildren("/", true);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (String child : children) {
System.out.println("child-->"+child);
}
System.out.println("*************end***********************************");
}
});
}
//1.创建节点
@Test
public void createNode() throws KeeperException, InterruptedException {
/**
* 参数1:path
* 参数2:携带的数据
* 参数acl :需要记住 Ids
*/
String path = zkclit.create("/atguigu", "dahaige".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("path-->"+path);
}
//获取子节点并监控数据节点的变化
@Test
public void getDataandWatch() throws KeeperException, InterruptedException {
List<String> children = zkclit.getChildren("/", true);
for (String child : children) {
System.out.println("child-->"+child);
}
Thread.sleep(Long.MAX_VALUE);
}
//拍断节点是否存在
@Test
public void exist() throws KeeperException, InterruptedException {
//第一个参数路径,第二个参数是否监听
Stat exists = zkclit.exists("/atguigu", false);
System.out.println(exists !=null ? "节点存在":"节点不存在");
}
}
13.监听服务器节点动态上下线案例
1.服务端
package com.lhh;
import org.apache.zookeeper.*;
import java.io.IOException;
/**
* @program: lhh
* @description:
* @author: 华仔
* @create: 2021-04-17 23:56
*/
public class DistributeServer {
public static void main(String[] args) {
DistributeServer server = new DistributeServer();
//1.连接服务器zookeeper集群
server.getConnect();
//2. 注册节点
server.regist("hadoop105");
//3.业务逻辑处理
server.business();
}
private void business() {
try {
//睡眠为了不程序不直接停止,保持一直在线
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void regist(String hostname) {
try {
//创建节点
String path= zooKeeper.create("/servers/servers",hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//监听哪些zookeeper集群
private String connecString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
//会话的超时时间单位毫秒
private int sessionTimeout = 2000;
private ZooKeeper zooKeeper;
private void getConnect() {
try {
//获取zookeeper对象
zooKeeper = new ZooKeeper(connecString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.客户端
package com.lhh;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @program: lhh
* @description:
* @author: 华仔
* @create: 2021-04-18 00:13
*/
public class DistributeClient {
public static void main(String[] args) {
DistributeClient client = new DistributeClient();
//1.获取zookeeper集群连接
client.getConnect();
//2.注册监听
client.getChlidren();
//业务逻辑代码
client.business();
}
private void business() {
try {
//睡眠为了不程序不直接停止,保持一直在线
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void getChlidren() {
try {
//获取/servers节点下面的所有子节点,并且监听
List<String> children = zooKeeper.getChildren("/servers", true);
//存储服务器节点主机名称集合
ArrayList<String> hosts = new ArrayList<String>();
for (String child : children) {
//获取/servers/下面所有节点的所有数据,
byte[] data = zooKeeper.getData("/servers/" + child, false, null);
hosts.add(new String(data));
}
//打印
System.out.println("hosts-->"+hosts);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
private int sessionTimeout = 2000;
private ZooKeeper zooKeeper;
private void getConnect() {
try {
zooKeeper =new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
//在调用一次为了所有的监听只会行一次
getChlidren();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
zooKeeper =new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
//在调用一次为了所有的监听只会行一次
getChlidren();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}