文章目录

  • 前言
  • 介绍
    • 简介
    • Zookeeper持久化机制
    • Zookeeper特性
    • 安装与部署
  • 节点znode介绍
    • Zookeeper如何保存数据
    • znode节点信息
    • znode结构
    • znode类型
  • Zookeeper怎么实现分布式锁
    • zk中锁的种类
    • zk中如何上读锁
    • zk中如何上写锁
    • 羊群效应(惊群效应)
  • Watch机制
  • 权限设置
  • zookeeper集群
    • 集群角色介绍
    • 集群搭建
      • 创建4个节点的文件夹
      • 创建myid文件,并设值
      • 新增4个zoo.cfg配置文件
      • 启动4台zookeeper服务
      • 连接Zookeeeper集群
  • ZAB协议
    • 什么是ZAB协议
    • ZAB协议定义的四种节点状态
    • Leader的选举
    • Leader奔溃,新Leader的选举
  • 主从同步
  • 相关指令
    • 创建节点
    • 查询节点
    • 删除节点
    • 修改节点
  • 代码
    • Go使用Zookeeper
  • 参考资料

前言

  • 仅为个人学习笔记,欢饮指错纠正
  • 欢迎一起交流学习探讨
  • 建议直接看参考文献B站视频

介绍

简介

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,主要服务于分布式系统,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理

使用分布式系统就无法避免对节点管理的问题(需要实时感知节点的状态、对节点进行统一管理等等),而由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了。

Zookeeper持久化机制

Zookeeper的数据是运行在内存中,Zookeeper提供了两种持久化机制

  1. 事务日志:Zookeeper把执行的命令以日志形式保存在dataLogDir指定的路径文件中(如果没有指定dataLogDir,则按dataDir指定的路径)

  2. 数据快照:Zookeeper会在一定的时间间隔内做一次内存数据的快照,把该时刻的内存数据保存在快照文件中

  3. Zookeeper通过两种形式的持久化,在恢复时先恢复快照文件中的数据到内存中,再用日志文件中的数据增量恢复,这样恢复的速度更快

Zookeeper特性

  • 顺序一致性,从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到Zookeeper中去。

  • 原子性,所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,即整个集群要么都成功应用了某个事务,要么都没有应用。

  • 单一视图,无论客户端连接的是哪个 Zookeeper 服务器,其看到的服务端数据模型都是一致的。

  • 可靠性,一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会一直被保留,除非有另一个事务对其进行了变更。

  • 实时性,Zookeeper 保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。

安装与部署

【注意】 由于Zookeeper是java编写的,所以必须保证虚拟机上有java环境,否则无法启动

  1. 官网下载地址:https://zookeeper.apache.org/releases.html
  2. 解压:sudo tar -zxvf apache-zookeeper-3.7.0-bin.tar.gz
  3. 删除压缩包 sudo rm -rf apache-zookeeper-3.7.0-bin.tar.gz
  4. zoo.cfg配置文件说明
# zookeepe时间配置中的基本单位(毫秒)
tickTime=2000# 允许follower初始化连接到leader最大时长,它表示tickTime时间倍数,即initLimit*tickTime
initLimit=10# 允许follower与leader数据同步最大时长,它表示tickTime时间倍数
syncLimit=5# zookeeper数据存储目录及日志保存目录(如果没有指明dataLogDir,则日志也会保存在这个文件中)
dataDir=/usr/local/zookeeper/zkdata# 对客户端提供的端口号
clientPort=2181# 单个客户端与zookeeper最大并发连接数
maxClientCnxns=60# 保存的数据快照数量,之外的将会被清除
autopurge.snapRetainCount=3# 自动触发清除任务时间间隔,小时为单位。默认为0,表示不自动清除
autopurge.purgeInterval=1
  1. 启动Zookeeper: ./zkServer.sh start ../conf/zoo.cfg

  2. 使用Zookeeper Cli: ./zkCli.sh

  3. 停止Zookeeper: ./zkServer.sh stop ../conf/zoo.cfg

节点znode介绍

Zookeeper如何保存数据

Zookeeper中的数据是保存在节点上的,节点就是znode,多个znode之间构成一棵树的目录结构

znode节点信息

  • cZxid: 创建节点的事务ID
  • mZxid: 修改节点的事务ID
  • pZxid:添加和删除节点的事务ID
  • ctime: 节点创建时间
  • mtime: 节点最近修改时间
  • dataVersion: 节点内数据的版本,没更细一次数据,版本会+1
  • aclVersion: 此节点的权限版本
  • ephemeralOwner: 如果当前节点是临时节点,该值是当前节点所有者的session id,如果节点不是临时节点,则该值为0
  • dataLength: 节点内数据的长度
  • numChildren: 该节点的子节点个数

znode结构

Zookeeper中的znode,包含了四个部分

  • data: 保存数据
  • stat: 描述当前znode的元数据
  • child: 当前节点的子节点
  • acl: 权限,定义了什么样的用户能够进行怎样的操作
    • c: create 创建权限,允许在该节点下创建子节点
    • w: write 更新权限,运气更新该节点的数据
    • r: read 读取权限,运气读取该节点内容以及子节点的列表信息
    • d: delete 删除权限,允许删除该节点的子节点
    • a: admin 管理者权限,允许对该节点进行acl权限设置

znode类型

  1. 持久节点:创建出的节点,在会话结束后依然存在,保存数据

  2. 持久序号节点:创建出的节点,根据先后顺序,会在节点之后带上一个数值,越后执行数值越大,适用于分布式锁的应用场景-单调递增

  3. 临时节点:临时节点在会话结束后,自动被删除的,通过这个特性,Zookeeper可以实现服务注册与发现的效果,Zookeeper客户端持续和Zookeeper服务器请求会话,续约session id的时间,如果会话断开,服务器就会删除没有续约的session id对应的临时节点

  4. 临时序号节点:跟持久序号节点相同,适用于临时的分布式锁

  5. Container节点(3.5.3版本新增):容器节点,当容器中没有任何子节点,该容器节点会被Zookeeper定期删除(60s)

  6. TTL节点:可以指定节点的到期时间,到期后被Zookeeper定时删除,只能通过系统配置zookeeper.extendedTypesEnabled=true开启

Zookeeper怎么实现分布式锁

zk中锁的种类

  • 读锁:大家都可以读,要想上读锁的前提,之前的锁没有写锁
  • 写锁:只有得到写锁的才能写,想要上写锁的前提是,之前没任何锁

zk中如何上读锁

  • 创建临时序号节点,节点的数据是read,表示是读锁
  • 获得当前zk中比自己小的所有节点
  • 判断最小节点是否是读锁
    • 如果不是读锁的话,则上锁失败,为最小节点设置监听。阻塞等待,zk的watch机制会当最小节点发生变化时通知当前节点,于是再执行第二步的流程
    • 如果是读锁的话,则上锁成功

zk中如何上写锁

  • 创建一个临时序号节点,节点的数据是write,表示写锁
  • 获得zk中所有的子节点
  • 判断自己是否是最小的节点
    • 如果是,则上写锁成功
    • 如果不是,说明前面还有锁,则上锁失败,监听最小节点有变化,则返回第二步

羊群效应(惊群效应)

  • 如果用上述的上锁方式,只要有节点发生变化,就会触发其他节点的监听事件,这 样的话对zk压力非常大,–羊群效应。可以调整成链式监听,解决这个问题

Watch机制

注册在特定znode上的触发器,当这个znode发生改变,也就是调用了create,delete,setData方法的时候,将会触发znode上注册的对应时间,请求watch的客户端会接收到异步通知

  1. 创建节点 create /test1
  2. 监听节点内容变化 get -w /test1
  3. 监听节点目录变化 ls -w /test1
  4. 监听节点目录下所有变化 ls -R -w /test1

权限设置

  1. 添加权限 addauth digest xiaoming:123456
  2. 创建权限节点 create /test1 abc auth:xiaoming:123456:cdwra

zookeeper集群

集群角色介绍

  • Leader: 处理集群的所有事务请求,急群中只有一个Leader
  • Follower: 只能处理读请求,参与Leader选举
  • Observer: 只能处理读请求,提升集群读的性能,但不能参与Leader选举

集群搭建

搭建4个节点,其中一个节点为observer

创建4个节点的文件夹

在/usr/local/zookeeper/zkdata创建以下四个文件

/usr/local/zookeeper/zkdata/zk1
/usr/local/zookeeper/zkdata/zk2
/usr/local/zookeeper/zkdata/zk3
/usr/local/zookeeper/zkdata/zk4

创建myid文件,并设值

在zk1-zk4分别每个文件创建一个myid文件,并设值1234,ID不可重复,否则集群建立失败,该文件必须得有

新增4个zoo.cfg配置文件

# zookeepe时间配置中的基本单位(毫秒)
tickTime=2000# 允许follower初始化连接到leader最大时长,它表示tickTime时间倍数,即initLimit*tickTime
initLimit=10# 允许follower与leader数据同步最大时长,它表示tickTime时间倍数
syncLimit=5# zookeeper数据存储目录及日志保存目录(如果没有指明dataLogDir,则日志也会保存在这个文件中)
dataDir=/usr/local/zookeeper/zkdata# 对客户端提供的端口号(zk1,zk2,zk3,zk4分别对应2181,2182,2183,2184)
clientPort=2181# 单个客户端与zookeeper最大并发连接数
maxClientCnxns=60# 保存的数据快照数量,之外的将会被清除
autopurge.snapRetainCount=3# 自动触发清除任务时间间隔,小时为单位。默认为0,表示不自动清除
autopurge.purgeInterval=1# 服务器集群各配置
# 第1个端口,服务器间通信,数据同步端口
# 第2个端口,服务器间通信,Leader选举端口
# 最后跟着服务器身份描述
server.1=127.0.0.1:2001:3001
server.2=127.0.0.1:2002:3002
server.3=127.0.0.1:2003:3003
server.4=127.0.0.1:2004:3004:observer

启动4台zookeeper服务

./zkServer.sh start ../conf/zoo1.cfg
./zkServer.sh start ../conf/zoo2.cfg
./zkServer.sh start ../conf/zoo3.cfg
./zkServer.sh start ../conf/zoo4.cfg

连接Zookeeeper集群

集群地址用逗号隔开

./zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183

ZAB协议

什么是ZAB协议

zookeeper作为非常重要的分布式协调组件,需要进行集群部署,集群中会以一主多从的协议进行部署。zookeeper为了保证数据的一致性,使用了ZAB(Zookeeper Atomic Broadcast)协议,这个协议解决了zookeeper的奔溃恢复和主从数据同步的问题

ZAB协议定义的四种节点状态

  • Looking 选举状态
  • Following Follower节点(从)节点所处状态
  • Leading Leader节点(主节点)所处状态
  • Observing 观察者节点所处状态

Leader的选举

第一轮选举

  1. 启动zk1,zk1进入looking状态
  2. 启动zk2,zk2进入looking状态
  3. zk1生成一张自己的选票,将票发给zk2,同时接收到zk2的票
  4. zk2生成一张自己的选票,将票发给zk1,同时接收到zk1的票
  5. zk1和zk2拿到2个票之后,对比票信息,先比zxid,zxid比较大的进投票箱(zxid越多说明更新数据比较多,因为选zxid比较大的)
  6. 如果zxid一样,再比较myid,myid比较大的进投票箱

第二轮选举

  1. zk1把第一轮选的票数更大的投给对方zk2
  2. zk2把第一轮选的票数更大的投给对方zk1
  3. 投票箱中票数超过集群半数,确定该节点为Leader,选举结束
  4. 此时启动zk3,zk3发现集群中已经选出Leader,于是将自己作为Follower

Leader奔溃,新Leader的选举

  1. Leader会和Follower之间有socket连接,Leader周期性不断向Follower发送心跳ping
  2. 如果Leader此时奔溃,Follower接收不到socket信息,Follower进入looking状态,follower之间重新进行选举流程,此时集群不能对外提供服务

主从同步

二阶段提交

  1. 客户端向Leader节点写数据
  2. Leader节点先把数据写到自己的数据文件中,并给自己返回一个ACK
  3. Leader把数据发送给Follower
  4. Follower把数据写到本地数据文件中
  5. Follower返回ACK给Leader
  6. Leader收到半数以上的ACK后向Follower发送commit,同时将数据写入内存中
  7. Follower收到commit后将数据文件中的数据写到内存中

相关指令

创建节点

  • 创建节点 create /test1
  • 创建节点 create /test1/sub1
  • 创建节点并存入数据 create /test2 abc
  • 创建持久序号节点 create -s /test2
  • 创建临时节点 create -e /test2
  • 创建临时序号节点 create -e -s /test2
  • 创建容器节点 create -c /test2
  • 创建权限节点 create /test1 abc auth:xiaoming:123456:cdwra

查询节点

  • 查询节点数据 get /test2
  • 查询节点详细信息 get -s /test2
  • 查询节点下所有节点 ls -R /test2

删除节点

  • 删除节点 delete /test2
  • 删除节点 delete /test2/sub1
  • 删除节点(如果有子节点) deleteall /test2
  • 删除节点(根据节点版本号) delete -v 1 /test2

修改节点

  • 修改节点 set /test2 adasdas

代码

Go使用Zookeeper

  • 使用包:github.com/samuel/go-zookeeper/zk
  • 代码块
package mainimport ("fmt""github.com/samuel/go-zookeeper/zk""time"
)func main() {//连接地址hosts := []string{"127.0.0.1:2181"}//nodepath := "/watch_get"// 连接zkconn, _, err := zk.Connect(hosts, time.Second*5)defer conn.Close()if err != nil {fmt.Printf("zookeeper connect is faield. err:%v\n", err)return}//创建节点var data = []byte("test value")acls := zk.WorldACL(zk.PermAll)nodePath, err := conn.Create(path, data, zk.FlagEphemeral, acls)if err != nil {fmt.Printf("zookeeper create node is faield. err:%v\n", err)return}//获得节点信息nodeValue, sate, err := conn.Get(path)if err != nil {fmt.Printf("zookeeper get node is faield. err:%v\n", err)return}fmt.Printf("nodeValue:%v, nodeSate:%+v", string(nodeValue), sate)//设置节点信息_, err = conn.Set(nodePath, []byte("hello zookeeper"), sate.Version)if err != nil {fmt.Printf("zookeeper set node is faield. err:%v\n", err)return}//获得节点信息nodeValue, sate, err = conn.Get(path)if err != nil {fmt.Printf("zookeeper get node is faield. err:%v\n", err)return}fmt.Printf("----nodeValue:%v, nodeSate:%+v", string(nodeValue), sate)//删除节点err = conn.Delete(nodePath, sate.Version)if err != nil {fmt.Printf("zookeeper delete node is faield: %v\n", err)return}//监听节点创建/删除/修改go watchExistsW(conn, path)//监听节点数据变化go watchGetW(conn, path)//监听节点孩子变化go childrenW(conn, path)for {select {default:}}}/*
watchExistsW
@Desc 监听节点创建/删除/修改
*/
func watchExistsW(conn *zk.Conn, path string) {for {b, sate, e, err := conn.ExistsW(path)if err != nil {fmt.Printf("watchExistsW is failed. err:%s\n", err.Error())return}event := <-efmt.Println("监听到节点变化")fmt.Println("b: ", b)fmt.Println("sate: ", sate)fmt.Println("path: ", event.Path)fmt.Println("type: ", event.Type.String())fmt.Println("state: ", event.State.String())fmt.Println("---------------------------")}
}/*
watchExistsW
@Desc 监听节点创建/删除/修改
*/
func watchGetW(conn *zk.Conn, path string) {for {b, sate, e, err := conn.GetW(path)if err != nil {fmt.Printf("watchGetW is failed. err:%s\n", err.Error())return}event := <-efmt.Println("监听到节点数据修改")fmt.Println("value: ", string(b))fmt.Println("sate: ", sate)fmt.Println("path: ", event.Path)fmt.Println("type: ", event.Type.String())fmt.Println("state: ", event.State.String())fmt.Println("---------------------------")}
}/*
childrenW
@Desc 监听节点创建/删除/修改
*/
func childrenW(conn *zk.Conn, path string) {for {b, sate, e, err := conn.ChildrenW(path)if err != nil {fmt.Printf("watchGetW is failed. err:%s\n", err.Error())return}event := <-efmt.Println("监听到节点children变化")fmt.Println("children: ", b)fmt.Println("sate: ", sate)fmt.Println("path: ", event.Path)fmt.Println("type: ", event.Type.String())fmt.Println("state: ", event.State.String())fmt.Println("---------------------------")}
}

参考资料

  • B站:https://www.bilibili.com/video/BV1Ph411n7Ep?p=1

Zookeeper理解与集群搭建相关推荐

  1. 基于zookeeper的solrCloud集群搭建

    转自:https://blog.csdn.net/yougoule/article/details/78445759  基于原文对实践遇到的问题稍作补充 1.安装及搭建相关环境 1.1环境准备 cen ...

  2. 【运维技术】Zookeeper单机以及集群搭建教程

    Zookeeper单机以及集群搭建教程 单机搭建 单机安装以及启动 安装zookeeper的前提是必须有java环境 # 选择目录进行下载安装 cd /app # 下载zk,可以去官方网站下载,自己上 ...

  3. zookeeper单机和集群搭建过程详细步骤

    文章目录: ▶ 单机环境搭建 ▶ 设置zookeeper为开机服务 ▶ 集群环境搭建 单机环境搭建 要求: 依赖Java环境 单机搭建过程: 进入到/opt目录下,创建zookeeper 文件夹 cd ...

  4. zookeeper伪分布式集群搭建

    zookeeper集群搭建注意点: 配置数据文件myid1/2/3对应server.1/2/3 通过zkCli.sh -server [ip]:[port]检测集群是否配置成功. 第一步:首先我们将我 ...

  5. zookeeper 和 kafka 集群搭建

    Kafka初识 1.Kafka使用背景 在我们大量使用分布式数据库.分布式计算集群的时候,是否会遇到这样的一些问题: 我们想分析下用户行为(pageviews),以便我们设计出更好的广告位 我想对用户 ...

  6. 阿里云ECS服务器部署HADOOP集群(三):ZooKeeper 完全分布式集群搭建

    本篇将在阿里云ECS服务器部署HADOOP集群(一):Hadoop完全分布式集群环境搭建的基础上搭建,多添加了一个 datanode 节点 . 1 节点环境介绍: 1.1 环境介绍: 服务器:三台阿里 ...

  7. Zookeeper的Centos集群搭建

    一.Centos 集群搭建 服务器 端口 10.30.1.16 2181 2881 3881 10.30.1.37 2181 2881 3881 10.30.1.38 2181 2881 3881 1 ...

  8. 大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 图文详解

    引言 在之前的大数据学习系列中,搭建了Hadoop+Spark+HBase+Hive 环境以及一些测试.其实要说的话,我开始学习大数据的时候,搭建的就是集群,并不是单机模式和伪分布式.至于为什么先写单 ...

  9. zookeeper 单机和集群搭建(windows环境+linux环境)

    文章目录 一.单机操作 1. 下载 2. 解压 3. 修改配置文件 4. 启动 二.集群操作 2.1. zoo.cfg添加集群配置 2.2. 在3台zk数据目录下面创建myid文件 2.3. 分别启动 ...

最新文章

  1. mysql innodb 从 ibd 文件恢复表数据
  2. Java中正则Matcher类的matches()、lookAt()和find()的差别
  3. 朱江洪功成身退 朱董配解体谁主格力(图)
  4. python可以管理操作系统吗_python之路——操作系统的发展史
  5. oracle中的fetchsize,oracle setFetchsize() 优化查询速度
  6. bootstrap之项目一的填坑
  7. HTTP-Runoob:教程
  8. F28335中断系统
  9. 中文名颜色大全,妈妈再也不担心我找不着好颜色了.
  10. 游戏服务器为什么要选择高防服务器
  11. Dev C++环境中使用OpenGL
  12. select函数到底该怎么用?
  13. 00后会不会改变软件测试行业现状?
  14. 《追风筝的人》- [美] 卡勒德·胡赛尼
  15. 交易猫源码完整搭建教程
  16. NOIp2016 题解
  17. 王者荣耀小游戏(发给你的好兄弟(大怨种)^-^)
  18. 魔兽70服修复比较好的服务器,魔兽世界tbc选哪个服务器
  19. 从今天开始,每天稳定博客,学习网络安全
  20. 实用技巧分享——用Python解压复杂zip文件

热门文章

  1. brew link php56报错,在 Mac下安装 Swoole 和 SwooleDistributed 3.X 出现的问题整理
  2. 数值计算方法与c语言工程函数库 pdf,数值计算方法和算法.PDF
  3. 运动选什么蓝牙耳机好?防水耐用的蓝牙耳机推荐
  4. Emscripten 编译器(emcc) 命令总结
  5. 腾讯云全站加速CDN有哪些优势?适用于哪些场景?
  6. 平均数、中位数、众数的特点及应用场合
  7. 人脸识别保存在mysql_人脸识别后的数据存储在哪里?
  8. Eclectic Tips Tricks for Mac OS
  9. 让IE不自动打开Excel文件而是下载excel文件
  10. update 追加某个字段的内容和mysql数据库怎么判断查奇偶数