本文是学习Zookeeper时做的知识点整理。

1 理论篇

1.1 Zookeeper是什么?

标准回答:

Zookeeper是一个分布式服务框架,是Apache Hadoop的一个子项目,它主要用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

非标准回答:

Zookeeper是一个拥有文件系统特点的、运行在内存的分布式数据库。

1.2 Zookeeper是数据库

Zookeeper本质上是一个数据库,支持数据的增删改查。

Zookeeper的基本数据格式是键值对:key-value。

[zk: localhost:2181(CONNECTED) 0] create /k1 v1               //创建"/k1",值为"v1"
Created /k1
[zk: localhost:2181(CONNECTED) 1] ls /                               //查看以"/"开头的所有数据
[k1, zookeeper]
[zk: localhost:2181(CONNECTED) 2] get /k1                         //获取"/k1"的值
v1
[zk: localhost:2181(CONNECTED) 3] set /k1 value1             //设"/k1"的值为"value1"
[zk: localhost:2181(CONNECTED) 4] get /k1                        //获取"/k1"的值
value1
[zk: localhost:2181(CONNECTED) 5] delete /k1                   //删除"/k1"
[zk: localhost:2181(CONNECTED) 6] ls /                              //查看以"/"开头的所有数据
[zookeeper]

1.3 Zookeeper拥有文件系统特点

Zookeeper是一个拥有文件系统特点的数据库。

Zookeeper数据模型的结构与Unix文件系统的结构相似,整体上可以看作是一棵树,树上每个节点称作一个znode,每个znode都可以用路径唯一标识。每个znode默认能够存储1MB的数据。

在Unix文件系统中,一切皆文件,在Zookeeper中也是如此。

Zookeeper服务器运行在Zookeeper集群上:每启动一台服务器,就在Zookeeper文件系统的/servers目录下创建一个子目录,在这个子目录中存放该服务器的所有数据;每停用一台服务器,就在/servers目录下将该服务器对应的子目录删除。

使用Zookeeper客户端可以对Zookeeper服务器上的数据进行读写,如果某台服务器挂掉,该服务器对应子目录从文件系统中被删除,客户端将无法再对该服务器上的数据进行读写。

1.4 Zookeeper运行在内存

一切内存数据库,都绕不开数据持久化问题。

众所周知,请求分为读请求和写请求,只有写请求会引起后台数据的变化。我们将写请求称作事务性请求,将读请求称作非事务性请求。

所有Zookeeper集群处理过的事务性请求信息都会被记录在Zookeeper的事务日志中,每台服务器在每次启动时都会读取本地的事务日志,将日志记录的所有事务重新执行,恢复上次关闭时的数据。

换言之,只要事务日志在,数据就在。

1.5 Zookeeper是分布式服务

1.5.1 CAP定理和BASE理论

CAP定理:一个分布式系统不可能同时满足一致性[Consistency],可用性[Availability],和分区容错性[Partition tolerance]这三个基本要求,最多只能同时满足其中的两项。

C:Consistency,一致性。

数据在多个副本之间是否能够保持一致的特性。

系统的一个数据更新成功之后,如果所有用户都能够读取到最新的值,该系统就被认为具有强一致性。

A:Availability,可用性。

系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。

P:Partition tolerance,分区容错性。

分布式系统在遇到任何网络分区故障的时候,仍然对外提供满足一致性和可用性的服务。

在分布式系统中,分区容错性是必须实现的,所以我们只能在一致性和可用性之间进行权衡。

对一致性的让步:

很多web实时系统对读一致性的要求很低,有些场合对写一致性的要求也不高,允许实现最终一致性。

对可用性的让步:

对很多web应用来说,并不需要特别高的实时性。比如发布者发布一条消息后,过几秒甚至十几秒,订阅者才看到这条动态,也是完全可以接受的。

BASE理论是对CAP中一致性和可用性的权衡的结果。

BASE是基本可用[Basically Available]、软状态[Soft state]、最终一致[Eventually consistent]三个术语的缩写。

BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。

1.5.2 ZAB协议

ZAB协议的全称是Zookeeper Atomic Broadcast(Zookeeper原子广播)。Zookeeper通过ZAB协议来保证分布式事务的最终一致性。

ZAB协议定义了事务性请求的处理方式:

1. 所有的事务性请求必须由一台全局唯一的服务器来协调处理,这台服务器被称为leader服务器,其它服务器称为它的follower服务器。

2. leader服务器负责将客户端发送过来的事务请求转换成事务,并分发给集群中所有的follower服务器。

3. 每台follower服务器收到事务后会给leader服务器返回一个ack请求。在ZAB协议中,当leader收到超过半数的follower的ack请求后,leader会再次向所有的follower服务器发送commit消息,要求提交事务。

其中的关键信息有:

全局唯一的leader服务器——Zookeeper集群的领导选举机制。

超过半数的follower的ack请求——过半机制。

leader分发事务-follower返回ack请求-leader发送commit消息——事务的两阶段提交。

1.5.3 领导选举机制

一个Zookeeper集群只能有一个leader服务器,这个leader服务器是由所有服务器投票选举出来的。

领导者选举发生的情形:

集群启动时,所有服务器进行领导者选举。

leader服务器挂掉时,剩余服务器重新选出新的领导者。

集群中超过一半的follower挂掉后(剩余服务器不再满足过半原则),这个集群不再有对外提供服务的能力,这时会进行领导者选举,目的仅仅是不再对外提供服务。

Zookeeper选举细节:

1. 每台服务器都持有一张选票,选票信息包括myid(服务器的唯一id)、支持的服务器的myid、事务日志中记录的最新一条事务的zxid(zxid是事务的唯一id,zxid越大表示对数据进行修改的时间越靠后)等。

2. 一开始,每台服务器支持的服务器都是自己。

3. 服务器之间会进行通信,并进行选票pk,参与选票pk的服务器会比较持有选票中的最新一条事务的zxid,zxid比较大的一方赢下pk(没有zxid或zxid相同时比较myid),输的一方改票跟投(将持有选票中支持的服务器的myid、最新一条事务的zxid改成与赢的一方一致)。

4. 选票pk不断进行,直到超过半数的选票支持某一台服务器时,该服务器成为leader,其它参与选举的服务器成为它的follower。

领导选举时,获得超过半数选票支持的服务器会率先成为leader,其它的选举参与者会自动变成它的follower。

如果某一台服务器的最新一条事务的zxid大于选举出来的leader的最新一条事务的zxid,那么这台服务器会进行事务回滚,使得最新一条事务的zxid与leader保持一致。

产生【某台服务器的最新一条事务的zxid大于选举出来的leader的最新一条事务的zxid】情况的原因可能是:上次集群关闭时,某条事务在以前的leader服务器上已经执行,但数据改动并没有同步到超过半数的follower服务器上。我们认为这条事务是无效的。

1.5.4 过半机制

假如若干台服务器组成了Zookeeper集群,因为一些原因(可能是断网),集群分裂成两个部分。如果两个部分分别选出一个leader服务器,两边会分别去处理客户端请求,但由于两边无法进行数据同步,整个集群会陷入混乱。这就是脑裂问题。

过半机制避免了脑裂问题的产生。

假如由若干台服务器组成了Zookeeper集群,因为一些原因,集群分裂成两个部分。(即使分裂,集群仍然包括两部分所有的服务器)

两部分服务器数目不等。服务器数目较多的部分,某台机器获得过半选票支持,成为领导者;另一部分的任一台机器最多获得的支持票数不会超过集群总服务器数目的一半,因此不会产生领导者。

两部分服务器数目相等。任一台服务器最多只能获得集群总服务器数目的一半数目的支持票,两边都不会产生领导者。

1.5.5 事务的两阶段提交

当客户端向leader服务器提交事务性请求时:

1. leader服务器将事务性请求信息写入事务日志。

2. leader服务器将事务分发给集群中所有的follower服务器。

3. 每台follower服务器收到事务后,将事务写入事务日志,并返回一个ack请求给leader服务器。

4. 当leader服务器收到超过半数的服务器发来的ack请求后(leader服务器也会给自己返回一个ack请求),提交事务。

5. 事务执行,leader服务器数据发生变化。

6. 所有follower服务器同步数据变化。

当客户端向follower服务器提交事务性请求时,follower服务器会先将这个请求转发给leader服务器,接下来leader服务器处理请求的步骤同上。

1.5.6 观察者Observer

在一个Zookeeper集群中,除了leader服务器和follower服务器,还可以有observer服务器。

observer服务器不参与领导者选举,也不算入过半机制。

observer服务器不接收leader服务器广播的事务,仅同步leader服务器的数据变化。

在集群中增加observer服务器的目的是提升处理非事务性请求的效率,即增加读请求的吞吐量。

2 实战篇

2.1 Zookeeper集群搭建(伪分布式)

2.1.1 准备工作

1. 使用VMware至少创建3台Linux虚拟机,并且建议使用Xshell进行管理。

2. 因为Zookeeper是需要jdk来编译的,所以我们要先在每台虚拟机上安装jdk。

3. 关闭每台虚拟机的防火墙。

查看防火墙状态:systemctl status firewalld.service

临时关闭:systemctl stop firewalld.service

开机禁用(重启生效):systemctl disable firewalld.service

准备工作完成。

2.1.2 集群搭建

1. 下载Zookeeper。

Zookeeper官网地址:Apache ZooKeeper

2. 把Zookeeper安装包拷贝到参与集群搭建的每台虚拟机上。

(建议放在/opt/路径下)

可以使用WinSCP、FileZilla等工具来完成。

3. 在每台虚拟机上解压Zookeeper。

解压指令:tar -zxvf 安装包名称 -C 指定解压目录

不指定解压目录则解压到当前目录。

4. 在每台虚拟机上配置服务器编号。

打开Zookeeper安装目录,创建目录zkData:mkdir zkData

在zkData目录下创建一个myid文件:touch myid

编辑每台虚拟机的myid文件,第一台虚拟机写入1,第二台虚拟机写入2,第三台虚拟机写入3,依此类推。(myid作为Zookeeper集群中每个节点的唯一标识,必须保证各不相同)

5. 在每台虚拟机上修改配置文件。

首先进入Zookeeper安装目录下的conf目录。

然后执行命令:mv zoo_sample.cfg zoo.cfg

执行这一条命令的原因是:要启动Zookeeper需要一个配置文件zoo.cfg,而Zookeeper只提供了一个示例文件zoo_sample.cfg,它不能直接拿来使用。

然后修改zoo.cfg:vim zoo.cfg

将dataDir改为Zookeeper安装路径下的zkData目录:

(按i键进入insert模式进行编辑,编辑完成后按Esc键退出insert模式,输入:wq保存退出)

在文件末尾增加如下配置:

####################cluster####################

server.[myid1]=[ip地址1]:2888:3888

server.[myid2]=[ip地址2]:2888:3888

server.[myid3]=[ip地址3]:2888:3888

server.[myid]:表示这是第几号服务器;

2888:这个服务器与集群中的leader服务器交换信息的端口。

3888:这个服务器与集群中其它服务器在选举时相互通信的端口。

6. 集群启动。

启动每台虚拟机上的Zookeeper服务。

进入Zookeeper安装目录下的bin/目录,执行:

Zookeeper服务启动命令:./zkServer.sh start

查看节点状态命令:./zkServer.sh status

Zookeeper服务停止命令:./zkServer.sh stop

Zookeeper服务重启命令:./zkServer.sh start

集群搭建完成。

2.1.3 zoo.cfg参数解读

在Zookeeper安装目录下的bin目录下,执行:

vim zoo.cfg

查看配置文件zoo.cfg。

tickTime:系统的相对单位时间,默认为2秒。

initLimit:初始通信时限,follower和leader之间初始连接时能容忍的最大延迟时间,默认为10个tickTime。

syncLimit:同步通信时限,follower和leader之间请求和应答时能容忍的最大延迟时间,默认为5个tickTime。

dataDir:数据存放目录。

clientPort:客户端端口号。

2.2 Zookeeper客户端

2.2.1 启动客户端

在Zookeeper安装目录下的bin目录下,执行:

Zookeeper客户端启动命令:./zkCli.sh

2.2.2 客户端命令行操作

ls path        查看当前节点包含内容

ls2 path        查看当前节点包含内容详细信息

create        创建

在使用create命令创建新节点时,节点名称必须以"/"开头

get path        获得节点的值

set        设置节点的值

stat        查看节点状态

delete        删除节点

rmr        递归删除节点

2.2.3 退出客户端

quit        退出客户端

2.3 Zookeeper API

2.3.1 Eclipse环境搭建

1. 创建一个Maven工程。

2. 添加pom文件。

<dependencies>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
        </dependency>

<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.8.2</version>
        </dependency>

<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
        </dependency>
  </dependencies>

3. 添加配置文件log4j.properties。

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

2.3.2 创建Zookeeper客户端

1. 启动Zookeeper集群。

2. 创建Zookeeper客户端程序。

import java.io.IOException;import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Test;public class ZookeeperClient {private String connectString = "192.168.74.3:2181,192.168.74.4:2181,192.168.74.5:2181";private int sessionTimeout = 2000;//单位:毫秒private ZooKeeper zkClient;@Testpublic void init() throws IOException {zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {public void process(WatchedEvent event) {}});}
}

3. 使用JUnit尝试运行不报错,客户端创建成功。

2.3.3 Zookeeper API

1. 创建子节点。

使用客户端程序创建节点 /key1000。

import java.io.IOException;import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;public class ZookeeperClient {private String connectString = "192.168.74.3:2181,192.168.74.4:2181,192.168.74.5:2181";private int sessionTimeout = 2000;private ZooKeeper zkClient;@Before //保证先于@Test方法运行public void init() throws IOException {zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {public void process(WatchedEvent event) {}});}@Testpublic void createNode() throws KeeperException, InterruptedException{zkClient.create("/key1000", "value1000".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}
}

运行代码,节点/key1000被添加到集群中。

2. 获取子结点。

"/"路径下当前节点:

使用客户端程序获取"/"路径下所有节点。

import java.io.IOException;
import java.util.List;import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;public class ZookeeperClient {private String connectString = "192.168.74.3:2181,192.168.74.4:2181,192.168.74.5:2181";private int sessionTimeout = 2000;private ZooKeeper zkClient;@Beforepublic void init() throws IOException{zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {public void process(WatchedEvent event) {}});}@Testpublic void getData() throws KeeperException, InterruptedException{List<String> children;children = zkClient.getChildren("/", false);for (String child : children) {System.out.println(child);}}
}

运行结果:

3. 监听子结点。

Zookeeper监听器原理(观察者模式):

1. 在main线程中创建Zookeeper客户端时,会同时创建两个线程,一个是负责网络连接通信的connet线程,一个是负责监听的listener线程。

2. connect线程会将想要注册的监听事件发送给Zookeeper服务器,然后Zookeeper服务器将该监听事件添加到注册监听事件列表中。

3. 当已注册监听事件发生时,Zookeeper服务器会将这个消息发送给listener线程。

4. listener线程调用客户端内部的process()方法。

"/"路径下当前节点:

1. 使用客户端程序监听"/"路径下面节点变化信息。

import java.io.IOException;
import java.util.List;import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;public class ZookeeperClient {private String connectString = "192.168.74.3:2181,192.168.74.4:2181,192.168.74.5:2181";private int sessionTimeout = 2000;private ZooKeeper zkClient;@Beforepublic void init() throws IOException{zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {public void process(WatchedEvent event) {System.out.println("--------------------");List<String> children;try {children = zkClient.getChildren("/", true); //truefor (String child : children) {System.out.println(child);}} catch (KeeperException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}});}@Testpublic void sleep() throws InterruptedException{Thread.sleep(Long.MAX_VALUE); //保证程序持续运行}
}

运行结果:

2. 向"/"目录中创建新节点 /key4000。

3. 从"/"目录中删除节点 /key3000。

讨伐Zookeeper相关推荐

  1. 常用的高性能 KV 存储 Redis、Memcached、etcd、Zookeeper 区别

    1. 什么是 KV 存储 KV 是 Key-Value 的缩写,KV 存储也叫键值对存储.简单来说,它是利用 Key 做索引来实现数据的存储.修改.查询和删除功能. 常用的高性能 KV 存储主要有 R ...

  2. kafka+zookeeper搭建步骤kafka问题

    kafka+zookeeper搭建步骤 帅气的名称被占用关注 0.1392018.12.04 13:48:00字数 1,007阅读 88 vmware 安装centOS7 克隆虚拟为:三台 本地你的I ...

  3. ZooKeeper简单使用

    ZooKeeper简单使用 ZooKeeper简单使用 1.ZooKeeper简介 2.ZooKeeper能做什么 3.ZooKeeper核心 3.1.ZooKeeper安装 3.2.ZooKeepe ...

  4. 2021年大数据ZooKeeper(六):ZooKeeper选举机制

    目录 ​​​​​​ZooKeeper选举机制 概念 全新集群选举 非全新集群选举 ZooKeeper选举机制 zookeeper默认的算法是FastLeaderElection,采用投票数大于半数则胜 ...

  5. 2021年大数据ZooKeeper(五):ZooKeeper Java API操作

    目录 ZooKeeper Java API操作 引入maven坐标 节点的操作 ZooKeeper Java API操作 这里操作Zookeeper的JavaAPI使用的是一套zookeeper客户端 ...

  6. 2021年大数据ZooKeeper(四):ZooKeeper的shell操作

    目录 ZooKeeper的shell操作 客户端连接 shell基本操作 操作命令 操作实例 节点属性 ​​​​​​​ZooKeeper Watcher(监听机制) ​​​​​​​Watch机制特点 ...

  7. 2021年大数据ZooKeeper(三):Zookeeper数据模型和节点类型

    目录 Apache ZooKeeper Zookeeper数据模型 Zookeeper节点类型 Apache ZooKeeper Zookeeper数据模型 图中的每个节点称为一个Znode. 每个Z ...

  8. 2021年大数据ZooKeeper(二):ZooKeeper集群搭建

    目录 ZooKeeper集群搭建 第一步:下载zookeeeper的压缩包,下载网址如下 第二步:解压 第三步:修改配置文件 第四步:添加myid配置 ​​​​​​​第五步:安装包分发并修改myid的 ...

  9. 2021年大数据ZooKeeper(一):ZooKeeper基本知识

    目录 Zookeeper基本知识 ZooKeeper概述 ZooKeeper特性 ZooKeeper集群角色 Leader: Follower: Observer: Zookeeper基本知识 Zoo ...

最新文章

  1. 【转】 linux iio子系统
  2. 代码同步工具_可以多重连接的数据库管理工具
  3. Linux Kconfig及Makefile学习
  4. BZOJ2087 : [Poi2010]Sheep
  5. SpringMVC请求处理流程、springMVC工作流程
  6. Ubuntu连接SSHHow to: Connect SSH, SFTP and FTP Servers using Nautilus ubuntu 13.04
  7. 2015计算机考研重点,2015考研计算机复习:数据结构重点归纳_跨考网
  8. 自学前端,需要学习哪些知识点?学多久可以入职前端工程师?
  9. SSL和数字证书服务慨述(4)
  10. 7-12 求给定精度的简单交错序列部分和 (15 分)
  11. spring的自动装配(default-autowire=byName)
  12. paip.版本控件svn删除文件或目录后的恢复
  13. 精仿互站huzhan开源源码交易平台 TP框架 多用户虚拟品交易商城 可二开 支持PHP5.3-5.6
  14. Qt数据库应用3-数据打印到pdf
  15. 使用word进行图片的有序命名
  16. 树莓派连接电脑(两种方法)
  17. truncate和delete的区别
  18. SQL查询语句分步详解——多字段分组查询
  19. 计算机专业教语文,中职计算机专业语文信息化教学应用
  20. 学院后勤保修系统php源码,适用于学校后勤报修的微信报修系统

热门文章

  1. jquery后代选择器 和子选择器区别
  2. 用思维导图快速学语法
  3. 如何用七牛云上传音乐生成外链
  4. ADO,ADO.NET
  5. 易扩展,易复用,封装axios
  6. 淘宝运营 高客单价的特点、推广引流方式
  7. MacOS使用minicom工具配置华为交换机
  8. Atitit 手机号码选号 规范 流程 attilax总结 v2 r99.docx
  9. 基于FPGA的EMAC模块和FIFO模块
  10. win7系统如何查看自己电脑IP