一、介绍 概述 Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。多作为集群提供服务的中间件.
Zookeeper从设计模式角度来理解,是一个基于观察者模式 设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生了变化,Zookeeper就负责通知 已经在Zookeeper上注册的那些观察者做出相应的反应.
分布式系统: 分布式系统指由很多台计算机组成的一个整体。
这个整体一致对外,并且处理同一请求,系统对内透明,对外不透明。
内部的每台计算机都可以相互通信,例如使用RPC 或者是WebService。客户端向一个分布式系统发送的一次请求到接受到响应,有可能会经历多台计算机。
Zookeeper = 文件系统 + 通知机制
特点 中心化集群,但是中心化集群易出现单点故障。
数据结构
应用场景 提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
二、安装及操作 需要提前安装JDK
两种部署方式:本地模式(standalone),分布式模式
分布式安装部署
版本:zookeeper-3.4.10
1、规划
将在hadoop102、hadoop103和hadoop104三个节点上部署Zookeeper。
2、解压安装
三台服务器分别解压:tar -zxvf zookeeper-3.4.10.tar.gz
解压后生成zookeeper-3.4.10目录
3、配置服务器编号
在文件中添加与server对应的编号:比如hadoop02添加2;
在hadoop103、hadoop104上修改myid文件中内容为3、4
4、修改配置文件
dataDir=/opt/module/zookeeper-3.4.10/zkData
#######################cluster##########################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888
【配置参数解读】server.A=B:C:D
A是一个数字,表示这个是第几号服务器【myid】;
zk启动时读取myid文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。
B是这个服务器的ip地址;
C是这个服务器与集群中的Leader服务器交换信息的端口2888 ;【副本】
D是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口3888 。【选举信息】
【扩展】2181 ,客户端访问端口
5、相关操作
1 2 3 4 5 6 7 8 9 10 11 12 [ys@hadoop102 zookeeper-3.4.10]# bin/zkServer.sh status JMX enabled by default Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg Mode: follower [ys@hadoop103 zookeeper-3.4.10]# bin/zkServer.sh status JMX enabled by default Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg Mode: leader [ys@hadoop104 zookeeper-3.4.5]# bin/zkServer.sh status JMX enabled by default Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg Mode: follower
客户端命令行操作 启动客户端:bin/zkCli.sh
命令基本语法
功能描述
help
显示所有操作命令
ls path [watch]
使用 ls 命令来查看当前znode中所包含的内容
ls2 path [watch]
(详细信息)查看当前节点数据并能看到更新次数等数据
create
普通创建 -s 含有序列 -e 临时(重启或者超时消失)
get path [watch]
获得节点的值
set
设置节点的具体值
stat
查看节点状态
delete
删除节点
rmr
递归删除节点
三、内部原理【重点】 选举机制【重点】
半数机制:
集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。
内部投票选举:
Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。
【举例】五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。这些服务器依序启动,则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 因为一共5台服务器,只有超过半数以上,即最少启动3台服务器,集群才能正常工作。 (1)服务器1启动,发起一次选举。 服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成; 服务器1状态保持为LOOKING; (2)服务器2启动,再发起一次选举。 服务器1和2分别投自己一票,此时服务器1发现服务器2的id比自己大,更改选票投给服务器2; 此时服务器1票数0票,服务器2票数2票,不够半数以上(3票),选举无法完成; 服务器1,2状态保持LOOKING; (3)服务器3启动,发起一次选举。 与上面过程一样,服务器1和2先投自己一票,然后因为服务器3id最大,两者更改选票投给为服务器3; 此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数(3票),服务器3当选Leader。 服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING; (4)服务器4启动,发起一次选举。 此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。 此时服务器4服从多数,更改选票信息为服务器3; 服务器4并更改状态为FOLLOWING; (5)服务器5启动,同4一样投票给3,此时服务器3一共5票,服务器5为0票; 服务器5并更改状态为FOLLOWING; 最终Leader是服务器3,状态为LEADING; 其余服务器是Follower,状态为FOLLOWING。
参考文章: https://blog.csdn.net/weixin_43291055/article/details/95451357
选举机制文章推荐:
https://www.cnblogs.com/shuaiandjun/p/9383655.html
https://blog.csdn.net/wyqwilliam/article/details/83537139
节点类型
监听器原理【重点】
写数据流程
【案例】监听服务器节点动态上下线/zk工作机制
API操作: 1、maven依赖
1 2 3 4 5 6 <dependency > <groupId > org.apache.zookeeper</groupId > <artifactId > zookeeper</artifactId > <version > 3.4.10</version > </dependency >
2、集群上创建/servers节点
1 2 [zk: localhost:2181(CONNECTED) 10] create /servers "servers" Created /servers
3、服务器端向Zookeeper注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import java.io.IOException;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.ZooDefs.Ids;public class DistributeServer { private static String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181" ; private static int sessionTimeout = 2000 ; private ZooKeeper zk = null ; private String parentNode = "/servers" ; public void getConnect () throws IOException { zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() { @Override public void process (WatchedEvent event) { } }); } public void registServer (String hostname) throws Exception { String create = zk.create(parentNode + "/server" , hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println(hostname +" is online " + create); } public void business (String hostname) throws Exception { System.out.println(hostname+" is working ..." ); Thread.sleep(Long.MAX_VALUE); } public static void main (String[] args) throws Exception { DistributeServer server = new DistributeServer(); server.getConnect(); server.registServer(args[0 ]); server.business(args[0 ]); } }
4、客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 import java.io.IOException;import java.util.ArrayList;import java.util.List;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;public class DistributeClient { private static String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181" ; private static int sessionTimeout = 2000 ; private ZooKeeper zk = null ; private String parentNode = "/servers" ; public void getConnect () throws IOException { zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() { @Override public void process (WatchedEvent event) { try { getServerList(); } catch (Exception e) { e.printStackTrace(); } } }); } public void getServerList () throws Exception { List<String> children = zk.getChildren(parentNode, true ); ArrayList<String> servers = new ArrayList<>(); for (String child : children) { byte [] data = zk.getData(parentNode + "/" + child, false , null ); servers.add(new String(data)); } System.out.println(servers); } public void business () throws Exception { System.out.println("client is working ..." ); Thread.sleep(Long.MAX_VALUE); } public static void main (String[] args) throws Exception { DistributeClient client = new DistributeClient(); client.getConnect(); client.getServerList(); client.business(); } }
四、其他 注意点: 1、zk常用端口号:
2181,客户端访问端口 2888,zk内部信息通讯(数据) 3888,zk选举专用
2、zk不能越级创建节点;
且创建节点一般要带有数据(除非数据是null),否则创建会失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [zk: localhost:2181(CONNECTED) 1] create /ys/sss "666" Node does not exist: /ys/sss [zk: localhost:2181(CONNECTED) 2] create /ys "666" Created /ys ... [zk: localhost:2181(CONNECTED) 16] create /ss null Created /ys [zk: localhost:2181(CONNECTED) 17] ls / [cluster, configs, controller, brokers, zookeeper, overseer, admin, isr_change_notification, controller_epoch, druid, aliases.json, live_nodes, collections, overseer_elect, spark, clusterstate.json, consumers, 【ss】, latest_producer_id_block, config, hbase, kylin] [zk: localhost:2181(CONNECTED) 18] ls /ss [] [zk: localhost:2181(CONNECTED) 19] get /ss null ...
常考面试题