【分布式学习】Zookeeper(ZK)

1,概念

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

1)对比Eureka

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

CAP:
C(一致性);
A(可用性);
P(分区容错):分布式系统部分结点异常依然可以提供服务。
对于一个分布式系统,P是基本要求;只能在CA之间做权衡,同时通过其它办法提升P.

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

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

2,使用场景

1)配置中心

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

2)集群管理

  1. 统一命名服务
    Zookeeper可以用来实现命名服务,例如将集群中的机器名称和IP地址进行映射,或者将服务的唯一标识和实际地址进行映射。这样,客户端可以通过名称或标识来访问服务,而不需要知道服务的实际地址。
  2. 分布式同步
    zk协调各个节点的同步,确保数据的一致性。
  3. 管理分布式集群
    协调各个节点加入和退出;
  4. 负载均衡

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

5)服务注册和发现

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

  1. 服务注册:服务在zk创建一个临时节点。
    节点名称:服务名称+版本号;
    节点数据:服务地址、端口、协议等。如果服务断开,临时节点从zk中删除。
  2. 服务发现与消费:watch服务节点

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(领导者)

  1. 负责进行投票的发起和决议,更新系统状态。
  2. 为客户端提供读写服务。
  3. 无leader时zk会停止服务。

2>follower(跟随者)

  1. 用于接收客户端请求并响应客户端返回结果,在选举中参与投票;
  2. 为客户端提供服务。
  3. 可被选举为leader
  4. follower节点越多,集群丢失数据的风险越低,但是,leader选举过程也要越长,写性能越慢。

3>observer(观察者)

  1. 接受客户端连接,将请求转发给leader;
  2. 不参与投票,只同步leader状态;不能成为leader。
  3. 扩展了系统,提高读取速度。
    不影响写性能的情况下,扩展zookeeper集群,提供读的服务

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 /节点pathczxid:节点被创建的事务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状态。

3)增加observer节点

3个节点的kafka增加2个observer节点:

  1. 每个结点zoo.cfg追加:
server.4=hdp25.bigdata.zll.qianxin-inc.cn:4777:4666:observer
server.5=hdp25.bigdata.zll.qianxin-inc.cn:5777:5666:observer

对于新增节点,还要加上参数:peerType=observer

  1. 启动zk
    关闭:先关闭follow再关闭leader;
    启动:先重启follower,再重启leader,最后重启新增的observer
  2. 集群检测
zkServer.sh status

server1、2、3为leader和follower,server4、5为observer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值