【分布式学习】Zookeeper(ZK)

1,概念

Zookeeper是 Apache Hadoop项目下的一个子项目,是一个开源、分布式应用程序协调服务,为分布式应用提供一致性服务。

1)服务发现框架对比

Nacos Eureka Consul CoreDNS Zookeeper
一致性协议 CP+AP AP CP CP
健康检查 TCP/HTTP/MYSQL/Client Beat Client Beat TCP/HTTP/gRPC/Cmd Keep Alive
负载均衡策略 权重/
metadata/Selector Ribbon Fabio RoundRobin
雪崩保护
自动注销实例 支持 支持 不支持 不支持 支持
访问协议 HTTP/DNS HTTP HTTP/DNS DNS TCP
监听支持 支持 支持 支持 不支持 支持
多数据中心 支持 支持 支持 不支持 不支持
跨注册中心同步 支持 不支持 支持 不支持 不支持
SpringCloud集成 支持 支持 支持 不支持 支持
Dubbo集成 支持 不支持 不支持 不支持 支持
K8S集成 支持 不支持 支持 支持 支持

1>zk

zk服务发现配置复杂,主要是用于分布式协调和同步;而服务注册和发现的频率较高,性能差。

2>Nacos

3>Eureka

zk是CP的:集群故障时不提供服务。
eureka是AP的。

CAP:
C(一致性);
A(可用性);
P(分区容错)。

AP:
当网络分区出现后,为了保证可用性,系统B可以返回旧值,保证系统的可用性。
此时不保证C。

CP:
当网络分区出现后,为了保证一致性,就必须拒绝请求,否则无法保证一致性。
此时不保证A。

4>Consul

2,使用场景

1)配置中心

  1. 存储配置信息;
    例如集群中的机器配置、服务地址配置等。
  2. 统一管理配置信息,同时实现动态加载和更新。

2)集群管理

  1. 统一命名服务
    Zookeeper可以用来实现命名服务,例如将集群中的机器名称和IP地址进行映射,或者将服务的唯一标识和实际地址进行映射。这样,客户端可以通过名称或标识来访问服务,而不需要知道服务的实际地址。
  2. 分布式同步
    zk协调各个节点的同步,确保数据的一致性。
  3. 管理分布式集群
    协调各个节点加入和退出;
  4. 服务注册和发现
    服务注册:服务在zk创建一个临时节点,节点名称:服务名称+版本号;节点数据:服务地址、端口、协议等。如果服务断开,临时节点从zk中删除。
    服务发现与消费:watch服务节点
  5. 负载均衡

3)分布式锁

Zookeeper可以用来实现分布式锁,通过创建一个特殊的节点,各个节点可以竞争同一个锁,从而保证分布式系统中的一致性。

1>原理

  1. 在zk创建一个持久结点:ParentLock;
  2. client1想要获得锁时,在ParentLock下创建一个临时顺序结点:
  3. 如果这个临时顺序结点顺序第一,则获得锁。
    执行完同步代码后释放锁:断开zk连接,临时结点会被删除。
  4. 如果这个临时顺序结点顺序非第一,则等待锁。
    此时往前一个顺序结点注册Watcher,监听该结点是否存在。
    若前一个结点被移除,则重新执行3、4去尝试获得锁。

2>优缺点

  1. 优点:预防死锁
    由于临时结点的特性:客户端断开就会被删除,可以有效避免服务器宕机导致的死锁问题。
  2. 缺点:性能低、网络抖动导致并发问题。
    由于zk锁需要动态创建、销毁结点来维持锁,比缓存服务性能差很多。
    网络抖动导致客户端连接断开,从而导致锁丢失。==》zk有重试机制很少发生。

3>实现

zk的第三方库Curator客户端,封装了一个可重入锁服务。

Curator:
Java/JVM客户端库,用于zookeeper,一个分布式协调服务。
主要功能:

  1. 分布式锁;
  2. 服务注册与发现;
  3. 分布式队列:可以在多个进程或线程之间进行消息传递;

4)分布式队列

Zookeeper可以用来实现分布式队列,通过创建一个特殊的节点,各个节点可以加入或离开队列,同时队列中的节点可以按照一定的顺序进行排序。

3,数据结构

树形目录结构:

1)ZNode(节点)

  1. 保存少量数据(1MB)、节点状态信息。
  2. 每个节点可以拥有子节点。
    临时节点除外。
节点类型 说明 描述
PERSISTENT 持久节点 节点创建后,会一直存在,需要有删除操作进行删除;
PERSISTENT_SEQUENTIAL 持久顺序节点 持久结点的基础上,zk在节点名后自动追加数字后缀(单调增长,Integer.MAX);
EPHEMERAL 临时节点 客户端会话失效或连接关闭后,该节点会被自动删除;
临时节点不能创建子节点,否则报错:NoChildrenForEphemeralsException;
EPHEMERAL_SEQUENTIAL 临时顺序节点 临时节点,创建时有数字后缀;
  1. 每个ZNode都有唯一路径标识。
  2. 不支持部分读写,仅支持一次性完整读写。

2)ACL(Access Control Lists,权限控制)

每个znode被创建时都会带有一个ACL列表,用于决定谁可以对它执行何种操作。

3)Watcher

每个ZNode可以配置Watcher:

  1. 监听节点中数据变化;
  2. 监听子目录变化。

可以设置观察的操作:exists,getChildren,getData;
可以触发观察的操作:create,delete,setData.

4,底层原理

1)角色

1>leader(领导者)

负责进行投票的发起和决议,更新系统状态。
为客户端提供读写服务。

2>follower(跟随者)

用于接收客户端请求并响应客户端返回结果,在选举中参与投票;
为客户端提供服务。

3>observer(观察者)

扩展了系统,提高读取速度。

  1. 接受客户端连接,将请求转发给leader;
  2. 不参与投票,只同步leader状态;

4>client(客户端)

请求发起方。

2)CP

ZK是CP分布式系统。

ZK的主要职责:保证数据(配置数据、状态数据)在多个服务直接的同步一致性。
如果ZK结点失联(节点断开、网络分割故障)会直接剔除管理范围,即使这些节点正常,到达这些节点的服务请求都会被丢掉。

3)Leader选举

sid(Server id):服务器ID。用来唯一标识一台ZooKeeper集群中的机器,每台机器不能重复,和myid一致。sid越大,选举权重越大。
Zxid:事务ID。用来标识一次服务器状态的变更,值越大说明数据越新,选举中权重越大。
Epoch:逻辑时钟(投票次数)。同一轮投票Epoch相同,每轮投完Epoch增加。

Server状态:选举状态。
LOOKING:竞选状态。
FOLLOWING:随从状态;同步leader状态,参与投票。
OBSERVING:观察状态;同步leader状态,不参与投票。
LEADING:领导者状态。

1>场景

  1. 服务器初始化启动;
  2. 服务器运行期间leader故障;
    非Observer服务器都会将自己的服务器状态变更为looing,开始进入leader选举。

2>选举原则

zookeeper默认使用快速选举:

  1. 向集群中的其他zookeeper建立连接,并且只有myid比对方大的连接才会被接受(也就是每2台只会有1个连接,避免连接浪费)
  2. 每台zookeeper默认先投自己,然后向集群广播自己的选票
  3. 收到对方的选票时,按权重由高到低依次比较:epoch(选举轮数)、zxid(事务id)、myid(服务器id),较大者胜出,改票并广播
  4. 如果收到的选票中有某个节点超过集群半数(>=n/2+1),则胜出当选为leader,其他节点为follower

4)脑裂

分布式系统由于故障被分为多个独立的子系统;这些子系统互相无法通信,独立运行,同时认为自己是整个系统的主节点;
脑裂导致整个系统失去一致性和可用性。

1>场景

zk靠过半机制、自增epoch机制不会发生脑裂。

  1. 网络故障
    部分节点无法与其它节点通信。
    预防:法定人数/多数机制(Quorum):半数投票才能选举leader。这样局部网络就不会产生新的leader,直接停止服务。==》zk对外提供服务的最小结点数量:m = n / 2 + 1(n为集群数量)。小于半数结点,集群将不可用。
  2. 主节点宕机
    其它节点重新选取出了leader,但是之前的leader又恢复了。
    预防:每次投票epoch都会自增,如果旧的leader复活,由于epoch不同,Follower会拒绝所有旧Leader发来的请求。

2>集群故障后自动恢复机制

  1. 识别集群分裂
    某些结点失联(心跳包),识别到集群分裂问题;
  2. 选举新的leader
  3. 数据同步
    选举结束后,zk使用”原子广播“机制同步所有结点数据。
  4. 恢复正常状态
    集群恢复正常状态。

3>手动恢复

  1. 寻找最新结点,其它结点数据可删除,后期会自动恢复。

5,常用命令

安装目录/usr/hdp/2.3.0.0-2557/zookeeper/bin下:

1)服务端常用命令

命令 说明
./zkServer.sh start 启动ZooKeeper服务
./zkServer.sh status 查看ZooKeeper服务状态
./zkServer.sh stop 停止ZooKeeper服务
./zkServer.sh restart 重启ZooKeeper服务

2)客户端常用命令

说明 命令 备注
连接ZooKeeper服务端 ./zkCli.sh -server ip:port
断开连接 quit
查看命令帮助 help
显示指定目录下节点 ls 目录
创建节点 create /节点path value
获取节点值 get /节点path
设置节点 set /节点path value
删除单个节点 delete /节点path
删除带有子节点的节点 deleteall/节点path
创建临时节点 create -e /节点path value
创建顺序节点 create -s /节点path value
查询节点详细信息 get /节点path czxid:节点被创建的事务ID
ctime:创建时间
mzxid:最后一次被更新的事务ID
mtime:修改时间
pzxid:子节点列表最后一次被更新的事务ID
cversion:子节点的版本号
dataversion:数据版本号
aclversion:权限版本号
dataLength:节点存储的数据长度
numChildren:当前节点的子节点个数
查看指定结点权限 getAcl path
给已有节点赋予权限 setAcl path acl

6,zk扩容

  1. 集群数量应该为奇数。
    原因:n/2+1投票才能保证zk集群的一致性。
    如果集群有5个节点,3>5\2,最多允许2个节点不可用。如果集群有6个节点,4>6\2,最多允许2个节点不可用。也就是说当集群节点数n为偶数时,其可用性与n-1是一样的,那我们何必多浪费一台机器呢?
  2. 扩容后机器重启顺序:按照myid从小到大启动,最后启动leader节点。
    zk只允许myid大的节点连接到myid小的节点。
  3. 数据目录:/home/zookeeper/data,备份:cp -r data data.bak;安装目录/home/zookeeper/software,目录不变,configure文件可以统一管理。
  4. 登录zookeeper 用户进行扩容。
  5. 集群扩容之后,替换所有需要用到zk的地方,将旧的所有server地址替换为所有server地址。

1)单机扩容

序号 节点名称 myid 说明
1 {OLD_SERVER} 1 旧的节点
2 {NEW_SERVER1} 2
3 {NEW_SERVER2} 3
  1. 将{OLD_SERVER} 的目录/home/zookeeper/software下的zookeeper目录打tgz包;在新机器的同目录下解压安装包
  2. 集群配置:
    新机器中,vi /home/zookeeper/software/zookeeper/conf/zoo.cfg,修改server配置项:
    删除 server.x=:xxxxxxxx:xxxx:xxxx;文件后面追加:
#其中,1 2 3表示zk的id;后续配置会用到
 server.1={ODL_SERVER}:2688:3788
 server.2={NEW_SERVER1}:2688:3788
 server.3={NEW_SERVER2}:2688:3788

调整dataDir配置为/home/zookeeper/data

  1. 数据目录
    所有节点进入/home/zookeeper/data目录,echo "2" > myid,其中2为上文提到的zk的id。
  2. 将新机器的zoo.cfg文件copy到原机器,保持配置文件一致。
  3. 重启zk,此时会有短暂的服务停止,关联的kafka等也会停止服务。所有结点启动成功后服务恢复正常。
##重启旧机器(一定先重启旧机器,保持集群的稳定状态)
cd /home/zookeeper/software/zookeeper/bin
./zkServer.sh restart
##启动新机器
cd /home/zookeeper/software/zookeeper/bin
./zkServer.sh start
  1. 扩容后集群校验
    旧机器:./zkServer.sh status可以看到有1个leader,2个follower。

2)集群扩容

假设3台机器扩容到5台:

  1. 新机器上解压老机器的zookeeper文件;
  2. 将老机器的zoo.cfg文件复制到新机器;并在新机器的zoo.cfg文件后追加:(先不要动老机器)
#其中,4 5表示zk的id;后续配置会用到
 server.4={ODL_SERVER}:2688:3788
 server.5={NEW_SERVER1}:2688:3788
  1. 在新机器的data目录,新建myid文件并写入zk的id。参加单机集群扩容。
  2. 将新机器的zoo.cfg文件copy到原机器,保持配置文件一致。
  3. 集群启动(zk会停止服务,也可能丢数据)
    先停止follower状态的zk节点:zkServer.sh stop
    然后停止其它zk结点;(这样就不会产生新的leader)
    先启动老结点的zk:zkServer.sh start;确保一台机器启动成功后,再重启下一台机器。
    再启动新节点的zk服务
  4. 集群状态检测
    zkServer.sh status 其中有一个leader,其它为follower状态。

你可能感兴趣的:(linux与大数据组件,分布式,zookeeper)