(2020-3-15)Zookeeper学习之Zookeeper概览以及部署
Posted Mr. Dreamer Z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(2020-3-15)Zookeeper学习之Zookeeper概览以及部署相关的知识,希望对你有一定的参考价值。
Zookeeper学习之Zookeeper概览以及部署
1.初识Zookeeper
1.1 什么是zookeeper
zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。
它又被叫做动物管理员,是因为我们在工作中用到的很多产品都是动物标志,比如tomcat,Hadoop等。zookeeper的诞生正是为了来进行分布式管理、协调各服务,因此zookeeper是分布式的基石。
1.2 zookeeper的特点
-
zookeeper是由一个领导者(leader),多个跟随者(follower)组成的集群。
-
集群中只要有一半以上节点存活的话,zookeeper就能正常运行。(优点是节约资源)
-
全局数据的一致性:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的。
-
更新请求顺序执行,来自同一个client的更新请求按其发送顺序依次执行。
-
数据更新原子性:一次数据更新要么成功,要么失败。 实时性:在一定时间范围内,client能读取到最新数据。
1.3 zookeeper的数据结构
zookeeper数据模型的结构和Unix文件系统很类似,整体可以看作是一棵树,每个节点称作一个ZNode。每一个ZNode默认能够存储1MB的数据,每一个ZNode都可以通过其路径唯一标识。
2. zookeeper的应用场景
zookeeper基本都是应用在分布式场景下。提供的服务包括:统一命令服务,统一配置管理服务,统一集群管理服务,服务器节点动态上下线,软负载均衡等。
2.1 统一命令服务
在分布式环境下,经常需要对应用/服务进行统一命名,便于识别。比如说:IP不容易记住,而域名容易记住
这样,就可以通常服务名直接访问。
2.2 统一管理配置
在分布式环境下,配置文件同步非常常见:
- 一般要求在一个集群中,所有节点的配置信息是一致的。比如kafka
- 对配置文件修改之后,需要能够快速同步到各个节点上
zookeeper就可以做这样的事情:
- 可将配置文件写入zookeeper上一个ZNode。
- 各个客户端服务器监听这个ZNode。
- 一旦ZNode中的数据被修改,zookeeper将通知各个客户端服务器
2.3 统一集群管理
分布式环境中,实时掌握每个节点的状态是必要的。可以根据节点的状态进行一些调整。
zookeeper可以实现实时监控节点状态的变化:
- 将节点信息写入zookeeper上的一个ZNode。
- 监听这个ZNode可获取它的实时状态变化。
2.4 服务器动态上下线
服务端实时洞察到服务器上下线的变化。
其余还是那个原理:
- 将在线的服务注册到一个ZNode节点上并创建对应的值,创建的时候选择zookeeper自带的暂时节点Mode。
- 由于这个服务下线之后,zookeeper会自动删除该节点的值。所以,创建直接监听即可。
下面会以代码的形式讲解~
2.5 软负载均衡
在zookeeper中记录每台服务器的访问数,能访问最少的服务器去处理最新的客户端请求。
3.zookeeper内部原理
3.1 选举机制
半数机制:集群中半数以上的机器存货,集群可用。所以zookeeper适合安装奇数台服务器。
zookeeper虽然在配置文件中并没有指定Master和Slave。但是zookeeper工作时,是有一个节点为leader,其他节点为Follower。Leader是通过内部选举机制临时产生的。
下面简单的举一个例子来说明一下:
如图,有5台服务器部署了zookeeper进行集群。按照刚才说的,zookeeper最好部署奇数台服务。然后开始进行选举。
如上图所示,人性都是自私的,第一台服务器server1直接就选自己了,然后发投票信息。由于此时,其他服务器还没有启动,所以它收不到反馈的消息。server1处于Looking(选举状态)。
如上图,此时,server2启动了。刚刚也说了,人性是自私的,它还是投给自己。同时,与之前的server1交换结果,由于server2的编号大于server1,所以server2胜出。server1变成小弟,它把票重新投给server2。but,由于此时投票数据没有大于半数,所以两个服务器依然处理选举状态—Looking。(这里大家可以想成编号大的,级别更高)
如上图,server3启动,还是给自己投票。同时和之前启动的server1,server2交换信息。刚刚也说了,由于server3的编号是最大的,所以server1和server2将票投给server3。又因为,此时server3的票数刚好大于半数了(总共5票),所以server3成为Leader,server1和server2成为小弟Follower。
后面server4和server5陆续启动,按理说,它们应该和之前的操作情况一样,得到之前所有的票数。但是,由于server3已经胜出了,server3已经得到了半数以上的票数,它已经变成老大了。所以server4和server5都变成小弟。
3.2 节点类型
持久节点:客户端和服务端断开后,创建的节点不删除。
短暂节点:客户端和服务端断开后,创建的节点自动删除。
3.3 zookeeper的角色
zookeeper有三种角色,leader,follower,observer。
- Leader:作为整个zookeeper集群的主节点,负责相应所有对zookeeper状态变更的请求。它会将每个状态更新请求进行排序和编号,比便保证整个集群内部消息处理的FIFO,写操作都走leader。
- Follower:除了相应本服务器的读请求之外,它还有处理leader的提议,并且在leader提交该提议时在本地也进行提交。leader和follower构成ZooKeeper集群的法定人数,也就是说,只有他们才参与新leader的选举、响应leader的提议。
- Observer:如果ZooKeeper集群的读取负载很高,或者客户端多到跨机房,可以设置一些observer服务器,以提高读取的吞吐量。Observer和Follower比较相似,只有一些小区别:首先observer不属于法定人数,即不参加选举也不响应提议;其次是observer不需要将事务持久化到磁盘,一旦observer被重启,需要从leader重新同步整个名字空间。
4. zookeeper伪集群部署
由于只有一台服务器,那就搞一个伪集群吧(3台)
4.1 包下载
进入Zookeeper官网进行最新稳定包下载(本次实验版本为 3.6.0),地址为:http://zookeeper.apache.org/releases.html#download
4.2 包解压
执行命令进行包解压:tar zxvf zookeeper-3.6.0.tar.gz, 并更名为zookeeper-server1。
4.3 配置修改
进入Zookeeper根目录中的conf目录下输入以下命令复制配置文件 (注意:Zookeeper默认会使用配置文件名为zoo.cfg的配置文件)
4.4 配置文件说明
进入配置文件,可以看到
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/root/apache-zookeeper-3.6.2/zookeeper-server2/zkData
dataLogDir=/root/apache-zookeeper-3.6.2/zookeeper-server2/logs
# the port at which the clients will connect
clientPort=2182
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
# server.1=ip:port1(服务端通讯端口):port2(服务之间选举端口)
server.1=localhost:2287:3386
server.2=localhost:2288:3387
server.3=localhost:2289:3388
## Metrics Providers
#
# https://prometheus.io Metrics Exporter
#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
#metricsProvider.httpPort=7000
#metricsProvider.exportJvmInfo=true
配置文件说明如下:
- tickTime:Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳。tickTime以毫秒为单位,默认2000。
- syncLimit:Leader和follower之间的通讯时长 最长不能超过initLimt*ticktime
- initLimt:接受客户端链接zk初始化的最长等待心跳时长 initLimt*ticktime
- dataDir:Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。
- dataLogDir:日志文件
- clientPort:客户端链接服务端端口号
- Server.A=B:C:D A:第几号服务器;B:服务IP;C:代表Leader和follower通讯端口;D:备用选leader端口
4.5 点我开始详细操作
将之前的配置文件粘贴到对应的zoo.cfg文件中,请填写自己的data路径和log路径。
4.5.1 修改zookeeper文件名
在此之前,我们在对应的路径下创建一个zookeeper的文件夹,用于存放我们需要的3个zookeeper包。
mkdir apache-zookeeper-3.6.2
4.5.2 复制对应的文件夹
进入之前安装的zookeeper文件夹下面,然后将之前的zookeeper丢到它下面,然后改名 。
mv apache-zookeeper /root/apache-zookeeper-3.6.2
mv apache-zookeeper zookeeper-server1
接着,拷贝两份zookeeper-server1
cp -a zookeeper-server1 zookeeper-server2
cp -a zookeeper-server1 zookeeper-server3
之后可以看到已经创建成功
4.5.3 修改对应的配置文件
创建成功之后,修改对应文件下面的配置文件。conf下面的zoo.cfg文件:
将整个地方的路径和你创建的文件夹名对应起来:zookeeper-serverX
4.5.4 zookeeper启动
进入对应bin目录下分别执行以下命令启动Zookeeper:
./zkServer.sh start ../conf/zoo.cfg
然后执行 ./zkServer.sh status 命令查看集群状态,如下图:
按照顺序展示出来的zookeeper-server,可以发现zookeeper-server2成为了Leader,这也正好对应起来了我们刚刚说的半数机制。
4.5.5 zookeeper连接客户端
进入bin目录下,
./zkCli.sh
OK,大功告成!!!
4.5.6 zookeeper伪集群踩坑
我在安装的时候,出现了一些问题,导致没办法启动。
- 随意修改zoo.cfg的名称,导致启动时找不到。网上有很多教程上面修改了zoo.cfg的名称,改成了zoo1.cfg。不要去改,就使用zoo.cfg。zookeeper会默认使用叫zoo.cfg的配置文件。
- dataDir和dataLogDir配置有问题:这个地方一定要配置自己全路径。
- 由于data和logs文件中有version文件夹,导致无法启动:这个问题我在网上找了很久才发现。如果不能启动,那么请进入自己的data或者logs文件删除对应的version文件夹。
5. zookeeper简单代码示例
服务端:
public class DistributeServer
public static void main(String[] args) throws IOException, KeeperException, InterruptedException
DistributeServer server = new DistributeServer();
//1.连接zookeeper集群
server.getConnect();
//2.注册节点
server.register("zoo1"); //设置对应服务器的主题名称
//3.业务逻辑处理
server.bussiness();
private void bussiness() throws InterruptedException
Thread.sleep(Long.MAX_VALUE);
private void register(String hostName) throws KeeperException, InterruptedException
String path = zkClient.create("/servers/server", hostName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);//暂时的是因为服务器下线之后要删除对应的节点
System.out.println(hostName+" is online");
private String connectingString = "xxx:2181,xxx:2182,xxx:2183";//集群地址,改成你自己服务器的地址。
private int sessionTimeout = 2000;
private ZooKeeper zkClient;
private void getConnect() throws IOException
zkClient = new ZooKeeper(connectingString, sessionTimeout, new Watcher()
@Override
public void process(WatchedEvent watchedEvent)
//监听。如果程序不结束会一直监听你配置的ip和对应路径
);
客户端:
public class DistributeClient
public static void main(String[] args) throws IOException, KeeperException, InterruptedException
DistributeClient client = new DistributeClient();
//获取zookeeper连接
client.getConnect();
//注册监听
client.getChild();
//业务逻辑处理
client.business();
private void business() throws InterruptedException
Thread.sleep(Long.MAX_VALUE);
private void getChild() throws KeeperException, InterruptedException
List<String> children = zk.getChildren("/servers", true);
//存储服务器节点主机名称集合
ArrayList<Object> arrayList = new ArrayList<>();
for (String child : children)
byte[] data = zk.getData("/servers/" + child, true, null);
arrayList.add(new String(data));
//将所有在线主机名称打印到控制台
System.out.println(arrayList);
private String connectingString = "";//TODO 集群地址
private int sessionTime = 2000;//超时设置
private ZooKeeper zk;
private void getConnect() throws IOException
zk = new ZooKeeper(connectingString, sessionTime, new Watcher()
@SneakyThrows
@Override
public void process(WatchedEvent watchedEvent)
//监听。如果程序不结束会一直监听你配置的ip和对应路径
getChild();
);
OK。搞定
怕就输一辈子!!!先做起来再说
以上是关于(2020-3-15)Zookeeper学习之Zookeeper概览以及部署的主要内容,如果未能解决你的问题,请参考以下文章