Zookeeper介绍

介绍

不要用zookeeper存放数据!

zookeeper日志存放在磁盘,数据存放在内存而不是磁盘

 

zookeeper中的简单的api

create

创建节点

delete

删除节点

exists

判断节点是否存在

get data

获取节点数据

set data

设置节点数据

get children

获取子节点列表

sync

分布式锁

zookeeper设计目标

zookeeper两大特点

可靠性

主机挂掉后能够快速恢复(选定)Leader

扩展性

通过主机(Leader)、观察者(Observer)、追随者(follower)实现拓展。主机可读可写,并负责把数据同步到所有节点,观察者与追随者只可以读取信息不可写入(写入部分全部转嫁到主机)。主机挂掉后,剩下的追随者(follower)选出id最大的那个成为新的主机(leader)。注:观察者(Observer)不参与选举。

读写分离

极度压榨cpu和io获取最高速的读取性能,通过Observer放大这项特性

ZooKeeper很简单

ZooKeeper允许分布式进程通过共享的分层名称空间相互协调,该命名空间的组织方式类似于标准文件系统。名称空间由数据寄存器(在ZooKeeper看来,称为znode)组成,它们类似于文件和目录。与设计用于存储的典型文件系统不同,ZooKeeper数据保留在内存中,这意味着ZooKeeper可以实现高吞吐量和低延迟数。

ZooKeeper实施对高性能,高可用性,严格排序的访问给予了高度重视

ZooKeeper的性能方面意味着它可以在大型的分布式系统中使用。可靠性方面使它不会成为单点故障。严格的排序意味着可以在客户端上实现复杂的同步原语。

ZooKeeper已复制。像它协调的分布式进程一样,ZooKeeper本身也可以在称为集合的一组主机上进行复制。

Leader=master,客户端能随意读取某个zookeeper节点的数据,但所有的写的操作必须转至Leader节点完成

组成ZooKeeper服务的服务器都必须彼此了解。它们维护内存中的状态图像,以及持久存储中的事务日志和快照。只要大多数服务器可用,ZooKeeper服务将可用。

客户端连接到单个ZooKeeper服务器。客户端维护一个TCP连接,通过该连接发送请求,获取响应,获取监视事件并发送心跳。如果与服务器的TCP连接断开,则客户端将连接到其他服务器。

zookeeper如何实现高可用

zookeeper集群运行有两种状态——可用(Leader主机存活)、不可用(Leader主机挂了)。存活中的zookeepeer节点中,过半投票选出新的主机。

过半的判断为

zoo.cnf配置中的server.idxxx。行数/2+1。

如何推选出新的Leader(主机)

所有剩余存活节点中,id最大的为新的主机

server.#{id}=#{host}:#{port1}:#{port2}

 

实测图

当前追随者失败和恢复

当前失败和其它追随者的恢复

领导者的失败

两个追随者的失败和回复

有一个领导者的失败

当一个Leader(领导者)挂掉后,短时间内zookeeper集群吞吐量下降。然后迅速竞选(该时间为200ms)出一个新的Leader(领导者),使得集群重新恢复成可用模式。

ZooKeeper已订购

ZooKeeper用一个反映所有ZooKeeper事务顺序的数字标记每个更新。后续操作可以使用该命令来实现更高级别的抽象,例如同步原语。

ZooKeeper速度很快

在“读取为主”的工作负载中,它特别快。ZooKeeper应用程序可在数千台计算机上运行,并且在读取比写入更常见的情况下以10:1的比率运行时效果最佳。

zookeeper数据模型

 

/为父节点

/app1、/app2为第二层子节点

/app1/p_1、/app1/p_2、/app1_p_3是/app1子节点的数据,其中数据存储格式为[key-value]

注意

zookeeper节点只能存储1m的数据

节点和短暂节点

与标准文件系统不同,ZooKeeper命名空间中的每个节点都可以具有与其关联的数据以及子节点。就像拥有一个文件系统一样,该文件系统也允许文件成为目录。(ZooKeeper旨在存储协调数据:状态信息,配置,位置信息等,因此存储在每个节点上的数据通常很小,在字节到千字节范围内。)我们使用术语znode来明确表示我们在谈论ZooKeeper数据节点。

Znodes维护一个统计信息结构,其中包括用于数据更改,ACL更改和时间戳的版本号,以允许进行缓存验证和协调更新。znode的数据每次更改时,版本号都会增加。例如,每当客户端检索数据时,它也接收数据的版本。

原子地读取和写入存储在名称空间中每个znode上的数据。读取将获取与znode关联的所有数据字节,而写入将替换所有数据。每个节点都有一个访问控制列表(ACL),用于限制谁可以执行操作。

临时节点

ZooKeeper还具有短暂节点的概念。临时节点依托于与客户端的session,当zk与客户端的session消失时,临时节点将被清除。

使用场景

分布式锁

当zk与客户端session消失时,临时节点自动清除,不需要再维护该锁的数据,客户端能够重新竞争获取资源

注册与发现服务

每个服务用临时节点的方式存储自身的信息,当服务不可用的时候,session就会断开,节点数据自动清除

 

节点变化可产生的事件

  • create
  • delete
  • update
  • children

 

zookeeper提供的保证

顺序一致性(最终一致性)

zookeepeer整个集群中,leader能够确保的是按照从客户端接收的集群中的顺序执行命令

写入操作保证最终一致性——ZAB协议(Zookeeper实现的paxos算法的方式)

client向follower发送修改数据请求,使用到的技术

原子性

此次修改数据请求只有俩状态,成功或者失败,没有中间态。Leader为每个follower节点的连接创建并维护一个队列,每个写入请求和follower的操作结果都会存入队列。Leader只有在收到过半队列的数据修改成功的消息时才把修改后的数据写入自己的数据节点中。

广播

向所有消息队列插入修改数据的消息,但不能确保所有follower节点都能收到消息

client想follower发送修改请求的步骤

  1. client向follower(A)发送写入请求
  2. follower转接给leader
  3. leader同意后,生成唯一事务id并落盘
  4. 对每个follower(A、B)创建并维护一个队列(总共两个队列,A/B),向队列发送写入日志的消息,follower把日志落盘。follower写入日志成功后,只有flowwer(A)向队列A发送写入成功的消息,Leader收到队列A的消息后,由于Leader和Follower(A)加起来写入成功的已经过半了(总共三个),此时Leader判断该操作已经成功。Follower如果还存活的话,会不断向Leader请求最新的数据,不用担心数据不一致的问题
  5. Follower(A)写入完成后,向队列(A)发送ok,leader收到后,此次修改操作基本完成
  6. 给follower(A)返回ok,再返回给client

如果有新的客户端连接follower(B),为了确保数据是最新的可以选择sync命令,follower会向leader请求同步所有数据00000

 

原子性

zookeeper整个集群中,一段更新(写入)的执行结果要么是全部成功要么全部失败,不存在部分成功部分失败的状态

可靠性

当主机确定要更新数据后,会请求多个follower查看是否能更新数据,只有过半同意更新后才会更新数据,而当剩余存活的follower不够设定值的一半,集群将"不可用",整个集群不能进行write操作而只能read(读取)。一个zookeeper实例的数据更新后,其它的实例能够通过持久化机制同步数据,数据一致性。

Leader挂掉后,剩余的follower节点竞选出一个新的Leader

Leader候选者条件

  • 事务id最高
  • 节点id最大

zookeeper集群选举Leader的机制

  • 选举端口号在选举期间保持两两通信(长链接)
  • 只要任何人发起投票,每个Leader候选人都会投自己一票
  • 推选制:先比较zid,最大的当选。如果zid都一样,则比较节点id(配置文件先写的)

 

单个系统映像

无论客户端查看zookeeper集群的哪一台服务器,都能看到最新的网络服务视图。假设有A、B、C、D这四个主机存活,无论客户端访问哪个zookeeper机器,都能查看到A、B、C、D的这四台zookeeper

及时性

zookeeper由于速度非常快,能够保证在一定时间范围内,所有客户端接收到的数据都是最新的

Zookeeper的主服务器的作用

统一配置管理

通过节点下的一兆大小的数据进行统一数据管理

分组管理

通过path进行分组管理

统一命名

sequential(序列化)

同步(分布式锁)

通过临时节点完成分布式锁

通过sequential创建唯一节点(节点名不同),zookeeper所有节点都依托父节点。它是一个队列式的事务锁

 

paxos(分布式一致性协议/算法)

目前唯一的分布式一致性算法

描述场景

有一个小岛(paxos),岛内有若干的议员,议员的总数是固定的,每一个提案都有一个唯一(幂等性)的编号(id),此编号不可改变并且自增。每一次会议都会通过n个提案,每一个议员手上有一个笔记本,里面记录了所有已经决议过的提案编号(id)并且不断更新,每一次会议中决议的提案编号都必须大于(不能是小于等于)议员手上笔记本中记录的提案编号,否则不予通过并且告知其它议员此提案已通过。

 

假设,在一个会议上,所有议员的笔记本上的编号都为0,有一个人(A)发起了一个提案——将水费设置为1元/度,A看了下自己的笔记本,上面记录的id是1,就把新的提案id设置为1(笔记本上最大的编号+1),把此提案的id分享给所有议员,过半议员回复已记录此id。然后发起投票,过半数议员同意通过此提案,提案通过并生效。

此时,又有一个人(B)发起提案——电费1元/度,B没有同步A之前发送的提案id,B看了下自己的笔记本,笔记本上的编号为0,就把电费提案的编号设置为1,并把此提案的id分享给所有议员,其余议员在检查手中笔记本的之后,发现笔记本已经有了编号为1的提案,立刻驳回申请并告知所有的议员编号为1的提案已经审核过,不能重复审批,只能更新修改编号为1的提案

 

冲突解决方式

假设有三个议员——A、B、C。A和B同时分别发起一个投票,C先收到A的投票申请,并且通过了。然后收到B的投票申请,C查看记录的提案编号的时候发现已有重复的,就立刻驳回B的提案,并告知所有人,编号1的提案只能修改删除不能新增。B为了让自己的提案获得表决,向A或者C打听更新编号1的提案的内容,然后噼里啪啦一顿修改,修改完后,发起投票——编号1的提案修改为xxxx,A同意了此提案的修改,B提出的提案修改申请被审核通过。

总而言之,就是先到先得。谁的投票申请先通过,谁就能获得该编号提案的插入权

zookeeper和paxos算法的对号入座

  • 小岛——Zookeeper Server Cluster(Zookeeper集群)
  • 议员——Zookeeper Server (Zookeeper节点)
  • 提案——Zookeeper的修改、更新、删除操作
  • 生效提案——具体node下的数据
  • 提案编号——Zookeeper Transaction id(Zookeeper事务id)

但是,这里有一个问题

paxos没有议长的概念,每个会议的参会人员(议员)都是平等的,那么这会有一个问题——有可能所有人同时发起一个提案,提案编号全部相同,那么这就会形成活锁,也就是每人投自己一票,然后到了其它议员时,发现该提案编号和自己要提出的编号冲突,理所当然地拒绝。那么,所有提案都失败了。

为了解决这个问题,议长,也就是Leader诞生了,所有的提案都必须由议长提出,议长也同时是议员,能投票选举,也会查看提案编号的唯一性。

具体场景

场景一(查询)

有一个人民向议员用提案编号询问某个提案,议员查看了自己的笔记本,嗯,有这个提案。就去翻现存提案的法典并告知他结果,同时声明,我这个法典不一定是最新的,如果你要最新的话,等我找总统sync后告诉你最新版本的提案

场景二(修改)

有一个人民(张三)向某个议员(李四)请求借一万元,议员表示:我没这权限,不能借给你,我帮你转接给议长吧。议长收到申请后,把此提案编号写为记事本上最大编号+1,并向议会申请通过此提案编号。该提案编号通过后,议长发起该提案的表决。过半议员同意,表决通过,把结果发送给议长。议长把小岛的公用资金减去一万元,用于借钱给张三,后把库存情况同步给所有的议员。李四收到提案通过的消息后,从国库实际取出一万块交给张三。

其中有四个步骤

  • 张三(client)向李四议员(follower)提出修改数据的提议。议员(follower)把此提议转借给议长(Leader)。
  • 议长给该提案编号并且表决是否可记录。
  • 可以记录此提案编号后,表决提案是否通过。提案通过后,修改数据并同步给所有议员后
  • 把结果返回给张三

场景三(Leader死了)

当届总统突然挂了,部分(或者全部)议员突然无法联系总统,各自发表声明,由于无法联系总统,不接受任何的业务请求,政府停摆。直到竞选出新的总统为止。

 

每种颜色、类型的线条为不同的zookeeper节点的数量,如:红色实线为三个节点,绿色虚线为5个节点。。。等等。

Y轴为qps数,x轴为读取的请求的百分比。

从上图可得知,在总的读写请求中,读取占比越少,节点数越少的性能越高。在包含80%读取请求的测试报告可得知,5、7、9、13个节点的zookeeper集群的qps增长速度远大于三个节点(红实线)。

角色

主机(Leader)

拥有zookeeper的所有功能,能够读写,主要负责写入数据以及把本节点的数据同步到所有节点上

观察者(observer)

负责读取,所有写入操作都交由leader负责。不参与Leader选举。观察者(observer)是放大zookeeper的读能力

追随者(follower)

负责读取,所有写入操作都交由Leader负责。当Leader挂掉后,由剩下所有存活的追随者(follower)竞选出新的Leader,新的Leader则是剩下的所有存活的追随者中id最高的那个。主机(Leader)挂掉后,追随者竞选新的主机(Leader)期间,其中一个追随者脑裂(选出大于一个Leader)则关掉自己,等到新的主机(Leader)选出来后再开启自己。follower只有和Leader建立连接后(或者它自己当Leader),才是可用状态,否则是不可用。

服务注册与发现

假设有服务A、服务B以及一个分布式的zookeeper集群,并且zookeeper集群是可用的。服务A与服务B有某种关联,B服务要调用服务。

A服务用临时节点(由session维护)的方式向zookeeper存储自己的信息(create -c /path/service xxx),由于是临时节点,节点存活由session维护,session断开节点将被清空,所以不需要额外处理清除不可用的服务器信息。服务B要调用服务A的接口,此时他会访问zookeeper获取服务A的相关信息(get /path/service)。如果服务A可用则会调用接口

因为是分布式服务,服务间是需要心跳检测的,服务的心跳检测有两种路线

  1. 服务B获取服务A后,自己验证心跳
  2. 服务B通过watch命令获取服务A的信息。zookeeper数据节点(znode)有变化时,会触发事件(create/update/delete等),触发事件后,会主动回调(callback)服务B,告知数据节点(znode)改变后的结果

节点的权限

[zk: localhost:2182(CONNECTED) 26] getAcl /

'world,'anyone

: cdrwa

  • world对应的就是 scheme(权限模式)
  • anyone对应的就是 id(授权对象)
  • cdrwa对应的就是 permission(权限)

权限模式

world=权限模式对应的用户

ip=权限模式对应的ip地址

auth=通过authentication验证的拥有权限(可以用kerberos获取authencation,也可以使用username/password)

digest=通过username:BASE64(SHA1(password))获取权限,使用它之前必须先通过username:password形式获取authentication

授权对象

权限授予的实体,通常为ip或者用户。anyone为所有人都拥有此权限

权限

  • create:c 数据节点的创建权限、允许授权对象在该数据节点下创建子节点。
  • delete:d 子节点的删除权限、允许授权对象删除该数据节点的子节点
  • read:r 数据节点的读取权限、允许授权对象对该数据节点读取数据内容和获取子节点列表信息
  • write:w 数据节点的更新权限、允许授权对象对数据节点的数据内容进行更新
  • admin:a 数据节点的管理权限、允许授权对象对该数据节点进行 ACL 相关的设置操作
  • cdrwa 拥有所有权限(create、delete、read、write、admin)

 

 

 

使用

下载地址

https://zookeeper.apache.org/releases.html

zookeeper配置详解

zookeeper默认配置文件为zoo.cfg

# The number of milliseconds of each tick

# 向其它zookeeper节点发送心跳的间隔(单位:毫秒)

tickTime=2000

# The number of ticks that the initial

# synchronization phase can take

# 初始盐值。当有新的zookeepeer从节点建立连接的时候,Leader允许等待新的新的节点的连接时间最长为tickTime*initLimit(单位:毫秒)。超时即为失败

initLimit=10

# The number of ticks that can pass between

# sending a request and getting an acknowledgement

# 初始盐值。主节点写入数据时,允许从节点的同步超时时间最长为syncLimit*tickTime(单位:毫秒)。超时即为失败

syncLimit=5

# the directory where the snapshot is stored.

# do not use /tmp for storage, /tmp here is just

# example sakes.

# zookeepeer持久化目录

dataDir=/tmp/zookeeper

# the port at which the clients will connect

# zookeeper监听端口

clientPort=2181

# the maximum number of client connections.

# increase this if you need to handle more clients

# 当前zookeepeer允许客户端最大的连接数

#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

# 启用后,ZooKeeper自动清除功能会将autopurge.snapRetainCount最新快照和相应的事务日志分别保留在dataDir和dataLogDir中,并删除其余部分。默认值为3。最小值为3

#autopurge.snapRetainCount=3

# Purge task interval in hours

# Set to "0" to disable auto purge feature

# 必须触发清除任务的时间间隔(以小时为单位)。设置为正整数(1或更大)以启用自动清除。预设为0

#autopurge.purgeInterval=1

# 监控的其余的节点的地址,格式为——server.#{id}=#{ip}:{node1}:{node2}。node2=竞选主机用的端口号|node1=与其他zookeepeer节点通讯(除了竞选主机)的端口号。剩余存活节点中,id最大的(不包括observer)为新的leader。

server.1=192.168.2.3:2887:3887

server.2=192.168.2.2:2888:3888

server.3=192.168.1.1:2889:3889

# 最后面带observer的不参与zookeeper主机选举!

server.4=192.168.1.1:2890:3890:observer

 

## Metrics Providers

 

# https://prometheus.io Metrics Exporter

# 设置为“ org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider”以启用Prometheus.io导出器

#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider

# Prometheus.io导出器将启动Jetty服务器并绑定到该端口,默认为7000

#metricsProvider.httpPort=7000

# 如果将此属性设置为true,则Prometheus.io将导出有关JVM的有用度量。默认值为true

#metricsProvider.exportJvmInfo=true

server端相关命令

zkServer.sh -[command]

start

后台启动

start-foreground

前台启动

stop

停止

version

才查看版本号

restart

重启

status

查看状态(也可用于查看本机是否为zk集群的Leader)

查看命令

zkServer.sh help

如何查看Leader

./zkServer.sh status

如果本机是leader的话则显示

[root@VM_0_8_centos bin]# ./zkServer.sh status

ZooKeeper JMX enabled by default

Using config: /mnt/zookeeper-3.7-2182/bin/../conf/zoo.cfg

Client port found: 2182. Client address: localhost. Client SSL: false.

Mode: leader

client相关命令

./zkClient #默认连接本机:localhost:2181

连接其他zk节点

./zkCli.sh -server localhost:2182

zookeeper客户端内部相关命令

ls [-s] [-w] [-R] path

查看zookeeper内部的指定路径下的节点

create [-s] [-e] [-c] [-t ttl] path [data] [acl]

在根目录下创建节点(不包含数据):create /test。

-e 创建临时节点

-s 通过sequential创建唯一性节点

get [-s] [-w] path

获取节点的数据(注:只能获取数据不能获取子节点)

-s 显示节点的统计数据,如

说明

cZxid=创建/test这个节点的事务id

ctime=创建时间

mZxid=修改/test这个节点的事务id

mtime=修改时间

pZxid=当前节点下,创建最小的节点的事务id

cversion=节点版本号

dataVersion=数据版本号

ephemeralOwner=临时节点的归属

dataLength=数据长度

numChildren=自己点数量

aclVersion=权限的版本号

getAcl [-s] path

获取路径下的权限

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值