Zookeeper 3.6.3【详细技术讲解】整

✨博客主页: https://blog.csdn.net/m0_63815035?type=blog

💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识
📢博客专栏: https://blog.csdn.net/m0_63815035/category_11954877.html
📢欢迎点赞 👍 收藏 ⭐留言 📝
📢本文为学习笔记资料,如有侵权,请联系我删除,疏漏之处还请指正🙉
📢大厦之成,非一木之材也;大海之阔,非一流之归也✨


前言

ZooKeeper 是 Apache 软件基金会的一个软件项目,它是一个为分布式应用提供一致性服务的软件,分布式应用程序可以基于zooKeeper实现数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。ZooKeeper 现在是一个独立的顶级项目,曾经是 Hadoop 的一个子项目。

目录

预备知识:

集群将一个任务部署在多个服务器,每个服务器都能独立完成该任务。例如:饭店后厨有三个厨师,他们每个人都会洗菜、切菜和炒菜,即使饭店同时来了很多客人也能轻松应对,这就是集群。

分布式将一个任务拆分成若干个子任务,由若干个服务器分别完成这些子任务,每个服务器只能完成某个特定的子任务。例如:饭店后厨有三个厨师,洗菜、切菜和炒菜三个子任务分别由每个人独立完成,一个人洗菜,一个人切菜,一个人炒菜,这就是分布式。

技术架构演变:

一、单体架构

1.1单体架构的定义和特点

1.单体架构定义:整个项目所有功能都写在一个包中。

2.单体架构特点:架构简单、开发简单、部署简单。

3.单体架构示例:小型管理系统等项目采用单体架构。
缺点:

1.代码重构难:所有代码在一个项目中,修改代码可能影响整个系统。

2.代码史删:项目代码冗余,工具类代码重复。

3.项目升级周期长:项目包大,上传和部署时间长,不适合敏捷开发。

1.2单体架构的部署

1.部署方式:将项目打包成WAR包,部署在Tomcat服务器或Spring Boot内置的Tomcat中。

2.服务器访问:通过IP地址和端口访问部署在服务器上的项目。

3.异地多活:通过在多个数据中心部署服务器,提高系统的可用性。

1.3服务器和数据中心介绍

1.服务器定义:包含CPU、内存和硬盘的计算设备。

2.数据中心定义:互联网数据中心(IDC),包含多个机架和服务器。

3.机架定义:用于安装服务器的设备,包含多个硬盘。

4.上云趋势:中小型公司倾向于使用云服务器,降低运维成本。

二、垂直架构与分布式架构

概念:

垂直架构 :通过将项目拆分为多个服务,实现分布式部署。
分布式架构 :通过多个服务器共同完成一个任务,提高系统性能和可扩展性。
集群 :是指多个服务器做相同的事情,提供分散的压力,单个业务处理时间没有缩短。
分布式 :是指多个服务器共同完成一件事,提高业务处理速度。大型公司倾向于同时采用集群和分布式技术(垂直),以应对高并发和业务需求。

2.1垂直架构(门户系统展示)

1.垂直架构是分布式架构的一种形式。

2.垂直领域是指纯粹的领域,没有其他内容干扰。

3.京东商城可以按照垂直领域进行划分,分为门户系统、商户系统和物流系统。

1.优点:架构简单,压力分散,代码安全,技术选型多。
2.缺点:程序员要求高,技术难点多,如分布式事务和锁的问题。

2.2垂直架构面临的问题和挑战

1.垂直架构面临数据库一致性问题。

2.多个数据库需要处理数据一致性,避免数据冲突。

3.分布式事务和两阶段提交等技术用于解决数据一致性问题。

2.3分布式锁的必要性

1.抢红包功能示例,说明在并发情况下,未加锁的代码会导致优惠券被重复抢夺。

2.加锁的必要性,通过synchronized等同步机制解决并发问题。

2.4分布式锁的实现方式

1.代码同步化:通过synchronized等机制实现代码的同步访问。

2.乐观锁:通过比较并交换(CS)机制,无锁思想,通过版本号解决ABA问题。

2.5外部加锁的实现

1.在外部加锁,使用多进程可见的组件,如ZooKeeper。

2.ZooKeeper的实现原理,满足多进程可见、高可用、互斥性等要求。

2.6乐观锁的实现原理

1.乐观锁的定义,通过版本号解决ABA问题。

2.CAS操作,比较并交换,通过版本号确保数据的一致性。

2.7ABA问题的解决

1.ABA问题的定义,数据被修改后恢复原值。

2.通过版本号解决ABA问题,确保数据的一致性。

三、微服务架构

3.1微服务架构概述

1.微服务架构是将项目功能拆分为多个独立的服务进行开发。

2.每个服务都独立部署、扩展和管理。

3.微服务架构的两大版本:面向服务架构(SOA)和微服务架构。

3.2微服务架构举例

1.以京东商城为例,每个功能模块都作为一个独立的服务开发。

2.服务包括用户模块、搜索模块、购物车模块、订单模块、支付模块等。

3.每个服务都有独立的IP地址和端口。

3.3 微服务架构的特点

1.服务细粒度:每个功能都是一个独立的服务。

2.独立性:服务独立部署、扩展和管理。

3.可伸缩性:每个服务可以独立扩容。

3.4微服务架构的挑战

1.服务器成本:微服务架构需要大量的服务器,增加成本。

2.资源利用:虚拟机和容器技术用于充分利资源。

3.测试复杂性:微服务架构测试困难,需要测试每个服务的交互流程。

3.5微服务架构的优缺点

1.优点:代码分散、代码安全、开发简单。

2.缺点:架构复杂、测试困难、技术要求高。

3.6微服务架构的技术栈

1.客户端:APP、小程序、PC、物联网。

2.DNS域名解析:将域名解析为IP地址。

3.防火墙:检查请求合法性。

4.网关:处理请求路由、身份验证。

5.注册中心:服务发现与注册。

6.服务网关:转发请求、身份验证。

7.负载均衡:分发请求。

8.熔断限流降级:保护服务。

9.数据层:关系数据库、缓存、搜索引擎、MongoDB。

10.日志框架:ELK(Elasticsearch、Logstash、Kibana)。

11.链路追踪:Zipkin或SkyWalking。

12.定时任务:XXL-JOB或Spring Batch。

13.配置中心:Spring Cloud Config或Apollo。

14.监控中心:Prometheus、Grafana。

3.7虚拟化技术与容器化技术

1.虚拟机:重虚拟化,整个操作系统虚拟化。

2.容器化:轻虚拟化,细粒度虚拟化,只包含所需资源。

3.容器技术:Docker,用于创建和运行容器。

4.虚拟化管理:Kubernetes,用于容器项目的发布上线。

3.8微服务架构的生态图

1.客户端:APP、PC、物联网。

2.DNS域名解析。

3.防火墙。

4.网关:Spring Cloud Gateway或Nginx。

5.注册中心:Eureka、Zookeeper或Nacos。

6.监控中心:Prometheus、Grafana。

7.日志框架:ELK。

8.链路追踪:Zipkin或SkyWalking。

9.配置中心:Spring Cloud Config或Apollo。

10.定时任务:XXL-JOB或Spring Batch。

11.数据层:关系数据库、缓存、搜索引擎、MongoDB。

12.开发运维工具:Maven私服、GitLab。

13.容器管理:Docker、Kubernetes。

3.9CI/CD流程在微服务架构中的应用

1.自动化测试:通过CI/CD流程进行自动化测试。

2.持续集成:自动构建、测试代码变更。

3.持续交付:将代码变更交付到测试环境或生产环境。

四、SOA面向服务机构

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心。当服务越来越多

容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。

Ps:从软件设计的角度上来说,ESB 是一个抽象的间接层,提取了服务调用过程中调用与被调用动态交互中的一些共同的东西,减轻了服务调用者的负担。Java编程思想里提到:"所有的软件设计的问题都可以通过增加一个抽象的间接层而得到解决或者得到简化!"简单来说 ES8就是一根管道,用来连接各个服务节点。为了集成不同系统,不同协议的服务,ESB 做了消息的转化解释和路由工作,让不同的服务互联互通。

4.1特点

4.2 优点

4.3缺点

五、CAP原则与BASE理论

5.1集群分布式概念

1.集群:提高单位时间内执行的任务数。

2.分布式:缩短单个任务的执行时间。

3.技术架构演变:从单一应用到微服务架构。

5.2CAP原则与BASE理论

1.CAP原则:数据一致性(C)、可用性(A)、分区容错性(P)。

2.BASE理论:基本可用(BA)、软状态(S)、最终一致性(E)。

3.没有最好的架构,只有最适合的架构。

5.2.1数据一致性

1.数据一致性:保证分布式集群中每个节点的数据一致。

2.一致性是好的架构的标准之一。

5.2.2可用性

1.可用性:确保服务器响应迅速,及时响应请求。

2.好的架构应具备高可用性。

5.2.3分区容错性

1.分区容错性:确保在分布式系统中,即使部分区域出现故障,整个系统仍能正常运行。

2.分区容错性是好的架构的标准之一。


5.3CAP原则总结

1.CAP原则:数据一致性、可用性、分区容错性三者只能选其二。

2.CP:保证数据一致性和分区容错性,但可能牺牲可用性。

3.AP:保证可用性和分区容错性,但可能牺牲数据一致性。

5.4BASE理论介绍

1.BASE理论:基本可用、软状态、最终一致性。

2.基本可用:确保基本服务可用,即使部分服务不可用。

3.软状态:允许数据在一定时间内不一致,但最终会达到一致。


5.5服务降级与熔断

1.服务降级:对非核心服务进行降级处理,以保障基本服务的可用性。

2.服务熔断:当某个服务出现故障时,断开对该服务的调用,以防止故障扩散。

5.6软状态的定义与实现

1.软状态:允许数据在一定时间内不一致,但最终会达到一致。

2.实现软状态的方法:集群中超过二分之一的服务器写入数据即可认为满足软状态。

5.7最终一致性

1.最终一致性:系统不可能一直处于软状态,数据最终会达到一致。

2.实现最终一致性的方法:定时同步或用户访问脏数据时触发同步。

六、数据一致性分类

6.1数据一致性概述

1.数据一致性是分布式系统中讨论的重要话题,涉及数据在多个副本之间的同步和一致性保证。

2.CP架构(强一致性)确保所有请求的写操作同步至所有节点,访问时数据一致。

3.互联网系统如电商秒杀、12306抢票等允许在一段时间内数据不一致,但最终一致。

6.2数据一致性的定义

1.分布式系统通过复制数据提高系统的可靠性和容错性。

2.数据副本存放在不同的机器上,网络或软件故障可能导致部分副本写入成功,部分失败。

3.超过半数副本写入成功才认为写操作有效,否则写入失败。

6.3数据一致性分类

1.强一致性:无论更新操作在哪个副本执行后,所有读操作都要获取更新的数据。

2.弱一致性:用户读到的数据可能不是最新的,但经过一段时间后会变成最新的。

3.最终一致性:用户最终能够访问到特定的数据,数据存储并复制到整个系统超过半数节点。

七、算法(Paxos、ZAB、Raft)

ZooKeeper 并未直接使用原生 Paxos 算法,而是采用了一种简化且优化的分布式一致性协议------ZAB(ZooKeeper Atomic Broadcast, ZooKeeper 原子广播协议),其核心思想借鉴了 Paxos 的精髓,可简单总结为:

核心目标

在分布式集群中,确保所有节点对数据的修改(如创建、更新节点)达成最终一致,即使部分节点故障,仍能正常工作。

核心流程(简化版)

  1. ** Leader 选举
    集群启动或 Leader 节点故障时,所有节点通过投票选举出一个
    Leader**(主导者),其余节点作为Follower(跟随者)。

  2. ** 数据同步 **:

    Leader 会将自身数据同步给所有 Follower,确保集群初始状态一致。

3.** 事务提交(类似 Paxos 的提案-决议流程)**:

  • 客户端发送写请求(如修改数据)到任意节点,该节点会将请求转发给 Leader。
  • Leader 生成一个提案(包含要修改的数据),广播给所有 Follower 进行投票。
  • 若超过半数 Follower 同意(投票通过),Leader 会下达commit(提交) 指令,所有节点执行该修改并持久化。
  • 若未达半数同意,提案被否决,数据不修改。

关键特点

  • 依赖半数以上节点存活(如 3 节点集群允许 1 个故障,5 节点允许 2 个故障),保证可用性。
  • 所有写操作由 Leader 统一协调,确保顺序性和一致性,读操作可由任意节点直接响应(保证高效)。

ZAB 相比原生 Paxos 更简洁,专注于满足 ZooKeeper 对高可用、强一致性和高性能的需求。

7.1Paxos算法的提出者

1.Paxos算法的提出者是莱斯利兰伯特,他在1990年提出了该算法。

2.莱斯利兰伯特在计算机领域的贡献较多,并在2013年获得了图灵奖。

3.图灵奖是计算机界的一个重量级奖项,类似于诺贝尔奖。

7.2分布式一致性算法

1.Paxos算法是一种基于消息传递的分布式一致性算法

2.分布式一致性算法分为共享内存模型消息传递模型

3.共享内存模型:多个节点的数据在同一个地方放着,所有修改和获取都是从这个地方进行。

4.消息传递模型:每个节点维护自己的一份数据,通过消息传递来修改数据。

7.3拜占庭将军问题

1.拜占庭将军问题是莱斯利兰伯特用来描述分布式一致性算法的一个故事。

2.问题背景:古罗马时代的拜占庭城堡,五个小国需要攻打该城堡,需要一致行动。

3.问题挑战:消息传递过程中可能被篡改或拦截,导致不一致性。

4.解决方案:选择一个上将军,负责发送打或撤的消息,或者通过少数服从多数的方式决策。

7.4拜占庭将军问题的前置条件

1.服务节点必须相互信任,确保消息的准确性。

2.信道不可篡改,确保消息在传递过程中不被修改。

3.这些前置条件是实施Paxos算法的基础。

7.5Paxos算法----基本模型

7.5.1帕克萨算法基础模型

1.帕克萨算法描述了一个小岛上的居民通过意愿(议员)决定事务变更的场景。

2.小岛上住着居民,事务变更需要通过意愿(议员)的提议,每个提议有一个PID(事务编号),从零开始正增长。

3.意愿总数确定且不能更改,PID不能倒退,只能正增长。

4.每个提议需要超过半数议员同意才能生效,少数服从多数。

7.5.2帕克萨算法与服务器集群

1.将小岛比喻为服务器集群,居民的写请求即为事务变更请求。

2.议员代表服务器,服务器的总数确定且不能更改,PID为事务变更编号。

3.每个事务变更需要超过半数服务器同意才能生效,即少数服从多数。

7.5.3议员如何处理提议

1.议员只会同意大于当前编号的提议,PID正向增长不能递减。

2.议员收到相同的提议时,若PID小于等于当前编号,则拒绝该提议。

3.议员通过比较PID的大小来决定是否接受提议,PID较大的提议优先被处理。

7.5.4议会的一致性

1.议会的目标是所有议员对提议达成一致,即PID一致。

2.议会不能保证所有议员记事本上的编号总是相同,因为服务器可能会宕机。

3.服务器宕机后,其PID不会增长,导致议会无法保证所有议员编号一致。

7.6帕克萨算法的工作流程

1.帕克萨算法是一种基于消息的分布式一致性算法。

2.算法工作流程包括提议、询问、接受、通知和生效等阶段。

3.提议阶段:议员接收居民的提议,并编号后发送给所有议员。

4.询问阶段:议员发送提议并询问是否接受,收到超过半数的接受回复后发送通知。

5.接受阶段:议员收到询问后,如果同意提议,则回复接受,并将自己的编号改为提议编号。

6.通知阶段:议员收到超过半数的接受回复后,发送通知,通知所有议员无条件接受提议。

7.生效阶段:议员收到通知后,无条件执行提议,并将提议变为正式法令。

7.7Paxou算法冲突的解决

7.8Paxos算法--活锁的问题

7.8.1活锁问题的定义和场景

1.活锁问题定义:程序一直在运行,但无法达到预期结果。

2.场景描述:六台服务器的复制过程中,由于提议无法获得超过半数的接受,导致活锁。

3.具体步骤:客户端发起写请求,提议电费一元一度和两元一度,服务器间相互询问和接受提议,但无法达成一致。

7.8.2活锁与死锁的区别

1.死锁定义:程序阻塞,无法继续执行,需要外部干预。

2.活锁定义:程序一直在运行,但无法达到预期结果。

3.死锁示例:JVM中的类方法a和方法b互相调用,导致死锁。

4.活锁示例:六台服务器间的提议无法获得超过半数的接受,导致活锁。

7.8.3解决活锁问题的方法

1.死锁解决方案:升级锁的力度,减少锁的粒度,避免线程互相等待锁。

2.活锁解决方案:引入随机性或重试机制,打破僵局,使程序能够继续运行。

7.9Paxos算法---有主模式

7.9.1有主模式的引入

1.无主模式的问题:活锁问题发生在无主模式下,即系统中没有唯一的决策者。

2.有主模式的定义:通过选出一个主节点,由该主节点发起所有提议,解决火索问题。

3.有主模式的工作流程:所有节点将提议转发给主节点,主节点维护一个队列,按照先进先出的顺序处理提议。

4.读请求的处理:读请求可以直接响应,无需转发给主节点。

7.9.2有主模式的问题

1.单点故障问题:有主模式下,所有决策都依赖于主节点,主节点的故障可能导致系统瘫痪。

2.主节点的选举和替换:需要设计机制来选举和替换主节点,确保系统的可用性。

7.10Paxos选主方案

7.10.1选主问题的引入

1.选主问题的背景:在分布式系统中,需要一个主节点来协调和管理集群中的操作。

2.选主问题的挑战:如何选择一个合适的主节点,确保其数据完整且处于运行状态。

7.10.2集群初始化选主

1.集群初始化选主:在集群刚启动时,需要选择一个主节点。

2.随机选主算法:通过随机选择服务器作为主节点,适用于集群初始化阶段。

4.10.3集群运行时选主

1.集群运行时选主:在集群运行时,如果主节点宕机,需要重新选择主节点。

2.投票选主算法:通过投票选择主节点,确保选出的主节点数据完整且处于运行状态。

4.10.4无脑投票给最大算法

1.无脑投票给最大算法:在投票选择主节点时,无脑投票给编号最大的服务器。

2.算法的优点:简单且高效,能快速选出主节点。

4.10.5选主算法的总结与问题讨论

1.选主算法的总结:介绍了随机选主和投票选主两种算法,并讨论了它们的优缺点。

2.问题的讨论:讨论了选主算法在集群初始化阶段和运行时阶段的应用,以及可能遇到的问题。

7.11Paxos算法----解决脑裂

7.11.1初步选组确定

1.初步选组已经确定,但这不是最终模型。

2.服务器版本差异问题:新加入的服务器版本永远落后于其他服务器。

3.极端场景:软件用户只读不写,服务器版本差异导致读取服务受影响。

7.11.2网络波动导致的脑裂问题

1.网络波动打散集群,导致选举出多个总统。

2.脑裂问题:集群大脑分裂,出现多个总统节点。

7.11.3解决脑裂问题的过半原则

1.加入过半投票原则,确保新主得到超过半数的票才能成为真正的总统。

2.过半原则解决脑裂问题,减少无效选举过程。

7.11.4Paxos算法总结

1.不能太慢:从随机过渡到投票,无脑投票给最大。

2.主的数据要全,且不能当机。

3.过半原则:根据集群总数决定,必须超过半数的票才能真正成为主。

7.11.5总结paxos算法

7.12ZAB协议与Paxos算法的关系

1.ZAB协议是对Paxos算法的一种优化。

2.ZAB协议简化了Paxos算法的模型,使其更易于理解和实现。

3.ZAB协议保留了Paxos算法的核心特性,包括二阶段询问广播和选主逻辑。

7.12.1ZAB协议对Paxos算法的优化

1.ZAB协议添加了一个新的角色:观察者(Observer)。

2.观察者角色不参与选主和提议的发起,但可以接收广播和转发提议。

3.通过引入观察者角色,减少了询问和广播阶段的服务器参与数量,从而提高了效率。

7.12.2集群角色的分析

1.集群角色包括总统(Leader)、议员(Follower)和观察者(Observer)。

2.总统负责发起提议、发起广播和参与选主。

3.议员负责转发提议给总统、接收广播和参与选主投票。

4.观察者负责转发提议给总统、接收广播和对外提供读服务。

7.12.3观察者角色的作用

1.观察者角色减少了询问和广播阶段的服务器参与数量。

2.通过将部分服务器设置为观察者,缩短了选主和询问广播的时间。

3.观察者角色不参与选主和提议的发起,但可以接收广播和转发提议。

7.12.4Paxos算法与ZAB协议的总结

1.Paxos算法包括总统、议员两种角色。

2.ZAB协议在Paxos算法基础上添加了观察者角色,优化了选主和询问广播的过程。

7.13 ZAP协议

ZooKeeper 的 ZAB(ZooKeeper Atomic Broadcast,原子广播协议) 是其实现分布式一致性的核心协议,可简单总结为:

核心目标

确保分布式集群中所有节点对数据修改(如创建、更新节点)达成一致,同时保证服务的高可用。

核心流程(分阶段)

  1. Leader 选举

    集群启动或原 Leader 故障时,所有节点通过投票选出一个 Leader (主导节点),其余为 Follower(跟随节点)。只有超过半数节点存活时,才能完成选举。

  2. 数据同步

    新 Leader 会将自身数据同步给所有 Follower,确保集群初始状态一致。

  3. 事务广播(核心阶段)

    • 客户端写请求(如修改数据)经任意节点转发给 Leader。
    • Leader 生成提案(含修改内容),广播给所有 Follower 投票。
    • 若超过半数 Follower 同意,Leader 下达提交指令,所有节点执行修改并持久化;否则提案作废。

关键特点

  • 依赖半数以上节点存活(如 3 节点集群允许 1 个故障),保证容错性。
  • 所有写操作由 Leader 统一协调,确保顺序性和强一致性;读操作可直接由任意节点响应,兼顾效率。

ZAB 是对 Paxos 算法的简化与优化,专为 ZooKeeper 的协调场景(如分布式锁、集群管理)设计,平衡了一致性与可用性。

7.13.1ZooKeeper ZAB协议概述

1.ZAB协议是ZooKeeper的核心协议,基于Paxos算法,并添加了额外的角色。

2.ZAB协议起源于雅虎研究院,用于解决分布式系统中的单点故障问题。

3.ZooKeeper通过ZAB协议实现集群内部的数据一致性。

7.13.2ZAB协议的角色

1.ZAB协议包括三种角色:Leader、Follower和Observer。

2.Leader负责整个集群的核心事务请求的调度和处理。

3.Follower参与事务请求的投票和选举投票。

4.Observer不参与事务请求和选主投票,只提供查询服务。

7.13.3ZAB协议的模式

1.ZAB协议包括两种模式:崩溃恢复原子广播

2.崩溃恢复模式用于集群启动或Leader节点网络中断时选择新的Leader。

3.原子广播模式用于Leader节点正常工作时广播事务请求。

7.13.3.1 ZAB协议的事务处理

1.Leader为每个事务请求分配一个全局递增的ID(ZXID)。

2.Leader按照ZXID的顺序对事务进行排序和处理。

3.Follower节点根据Leader的广播更新本地数据。

7.13.4ZAB协议的状态机

1.ZAB协议定义了三个阶段:发现、同步和广播。

2.发现阶段:选举Leader并维护Follower可用列表。

3.同步阶段:Leader与Follower同步数据。

4.广播阶段:Leader广播新的事务请求给Follower。

7.13ZooKeeper的CP架构

1.ZooKeeper是CP架构,优先考虑一致性(Consistency)。

2.ZooKeeper的一致性通过过半数节点达成共识来实现。

3.AP架构则强调访问及响应(Availability),不要求全一致性。

7.14 Raft算法

Raft算法是一种用于分布式系统的共识算法,其核心目标是让多个节点在存在网络分区、节点故障等异常情况下,仍能就某个操作序列达成一致(即"共识"),确保系统的一致性和可用性。它通过清晰的角色划分和阶段化流程,降低了共识算法的复杂度,被广泛应用于etcd、Consul等分布式系统中。

7.14.1、核心概念

7.14.1.1角色划分

Raft中每个节点在任意时刻只能属于以下三种角色之一:

  • Leader(领导者):集群中唯一的"决策者",负责接收客户端请求、向Follower同步日志,并发起"提交"操作。
  • Follower(跟随者):被动接收Leader的消息(日志同步、心跳),不主动发起请求。若超时未收到Leader消息,会转为Candidate。
  • Candidate(候选人):当Follower认为Leader故障时,会转为Candidate并发起Leader选举,争取成为新的Leader。
7.14.1.2 任期(Term)
  • 任期是一个全局递增的整数(类似"时间片"),用于划分Raft的逻辑时间,每个任期内最多有一个Leader。
  • 任期从1开始,每次选举会进入新的任期;若选举失败(如无节点获多数票),则任期递增并重新选举。
  • 节点间通过任期号判断消息有效性(例如,旧任期的消息会被忽略)。

7.14.2 工作流程

Raft的工作流程分为三个核心阶段:Leader选举日志复制安全性保障,三者循环协作以维持共识。

7.14.2.1 Leader选举(如何产生Leader)

当集群启动或现有Leader故障时,会触发Leader选举,流程如下:

  • 触发条件:Follower在"选举超时时间"(通常150-300ms,节点间随机化避免同时选举)内未收到Leader的心跳(空消息,用于证明Leader存活),则转为Candidate。
  • 选举步骤
    1. Candidate将自身任期号+1,向集群中所有其他节点发送"请求投票(RequestVote)"消息,请求投票给自己。
    2. 其他节点收到请求后,根据规则投票(每个任期内最多投1票):
      • 仅当Candidate的日志"至少和自己一样新"(即日志的最后一个任期更大,或任期相同但长度更长)时,才会投票。
    3. Candidate若收到多数节点(超过半数)的投票,则当选为新Leader,并立即向所有节点发送"心跳"消息,宣告自己的Leader身份,阻止其他节点发起选举。
    4. 若未获多数票(如平票),则等待随机时间后,在新的任期内重新发起选举。

7.14.3 Raft总结

Raft算法通过"任期+角色"机制,将共识过程拆解为"选举-日志复制-安全性校验"三个阶段,逻辑清晰且易于实现。其核心思想是:

  1. 用"多数投票"确保Leader的唯一性和合法性;
  2. 用"日志复制+多数确认"确保数据在集群中一致;
  3. 用"日志新旧校验"和"冲突覆盖"规则避免数据错误。

这种设计让Raft在分布式系统中能高效处理节点故障、网络延迟等问题,成为工业界广泛采用的共识算法。

八、存储与监听

8 .1存储模型:

ZooKeeper 的存储模型类似于分布式文件系统 ,但更轻量且专为协调场景设计,核心特点是树形结构节点(Node) 为基本单位。以下是其存储模型的关键要点:

8.1.1. 核心结构:树形层次结构(ZNode Tree)

  • 整体结构类似 Unix 文件系统的目录树,根节点为 /,所有节点都在其下分层组织。

  • 每个节点称为 ZNode,既可以像"文件"一样存储数据,也可以像"目录"一样包含子节点(因此 ZNode 兼具文件和目录的特性)。

  • 示例结构:

    复制代码
    /
    ├─ /app1               # 应用1的根节点
    │  ├─ /app1/config     # 存储应用1的配置数据
    │  └─ /app1/lock       # 分布式锁节点
    └─ /app2               # 应用2的根节点
       └─ /app2/status     # 存储应用2的状态信息

8.1.2. ZNode 的核心属性

每个 ZNode 包含以下关键信息:

  • 路径(Path) :唯一标识,如 /app1/config(必须以 / 开头,且不允许相对路径)。
  • 数据(Data):存储的二进制数据(默认最大 1MB,通常用于存储少量元数据,如配置、状态标记等)。
  • 版本(Version):数据的版本号,每次修改自动递增(用于乐观锁控制,避免并发冲突)。
  • ACL(Access Control List):访问控制列表,限制节点的读写权限(如哪些客户端可以修改节点)。
  • 状态信息(Stat):包含创建时间、修改时间、子节点数量等元数据。

8.1.3. ZNode 的类型(按生命周期划分)

根据是否自动删除,ZNode 分为以下类型:

  • 持久节点(Persistent):客户端创建后,除非主动删除,否则永久存在(如配置节点)。
  • 临时节点(Ephemeral) :客户端会话结束后自动删除(常用于临时锁、服务注册等,如检测节点是否在线)。
    注:临时节点不能有子节点。
  • 持久顺序节点(Persistent Sequential) :持久节点 + 自动追加递增序号(如 /task-0000000001),用于生成全局唯一ID。
  • 临时顺序节点(Ephemeral Sequential):临时节点 + 自动追加递增序号(常用于分布式锁的实现,如公平锁)。

ZooKeeper 的存储模型以树形 ZNode 结构 为核心,通过节点的类型、版本控制和监听机制,高效支持分布式场景下的配置管理、服务发现、分布式锁等协调需求。其设计强调轻量性和一致性,数据存储量通常较小(避免存储大量业务数据),更侧重元数据的可靠同步。

8.1.4.ZooKeeper存储模型概述

1.ZooKeeper的存储模型参考了Linux文件系统,内部是一个KV的文件系统。

2.ZNode是目录的名称和值,类似于Linux中的文件和内容。

8.1.5.ZNode的创建和获取

1.使用create命令创建ZNode,并为其赋值。

2.使用get命令获取ZNode的值。

3.ls命令用于列出ZNode的子节点。

8.1.6.ZooKeeper的文件系统模型

1.ZooKeeper的文件系统模型包括根节点、zookeeper节点、config节点和quota节点。

2.根节点下可以创建多个子节点,如zookeeper和config。

3.config节点用于存储集群的配置信息,包括配额信息。

8.1.7.ZNode的持久性和临时性

1.持久节点:不会被自动删除,即使创建节点的会话断开。

2.临时节点:创建节点的会话断开后,节点会自动删除。

8.1.8.ZNode的顺序性

1.持久顺序节点:通过在节点名后添加序列号来确保全局唯一性。

2.临时顺序节点:与持久顺序节点类似,但会在会话断开时删除。

8.1.9.ZooKeeper的常用命令

1.ls:列出指定节点的子节点。

2.get:获取指定节点的值。

3.set:重新设置节点的值。

4.delete:删除指定节点。

5.create:创建新的节点。

8.2 ZooKeeper的监听机制:

ZooKeeper 的监听机制(Watcher) 是其核心特性之一,用于实现分布式系统中的实时感知(如配置变更、节点状态变化等),是协调服务的关键支撑。其核心思想是:客户端对感兴趣的节点注册监听,当节点发生指定事件时,ZooKeeper 会主动通知客户端,避免客户端轮询带来的性能损耗。

8.2.1Watcher 机制的核心要素

8.2.1.1. 事件触发场景

客户端可以对 ZNode 的以下事件注册监听:

  • 节点数据变化 :节点内容被修改(如 setData 操作)。
  • 节点删除 :节点被删除(如 delete 操作)。
  • 子节点变化 :子节点被创建、删除或数量变化(如 create/delete 子节点)。
  • 节点创建 :针对不存在的节点注册监听,当该节点被创建时触发(如对 /lock 注册监听,当 /lock 被创建时通知)。
8.2.1.2. 监听的生命周期
  • 一次性触发 :Watcher 被触发后自动失效 ,若需持续监听,客户端需在收到通知后重新注册。
    设计原因:避免 ZooKeeper 服务器长期维护大量监听状态,减轻负担。
  • 会话绑定:Watcher 与客户端会话(Session)绑定,若会话过期或断开,所有未触发的 Watcher 自动失效。
8.2.1.3. 通知方式
  • 当事件触发时,ZooKeeper 服务器通过异步回调的方式向客户端发送通知(包含事件类型、节点路径等信息)。
  • 通知是轻量级的,仅告知"发生了事件",不包含事件的详细内容(如数据修改前后的具体值),客户端需主动查询最新数据。

8.2.2Watcher 的工作流程

  1. 注册监听 :客户端通过 API(如 getData(path, watcher, stat)getChildren(path, watcher))对目标节点注册 Watcher。

    • 示例(Java 伪代码):

      java 复制代码
      // 对 /config 节点注册监听,监听数据变化
      zk.getData("/config", new Watcher() {
          @Override
          public void process(WatchedEvent event) {
              // 事件触发时的回调逻辑
              System.out.println("事件类型:" + event.getType() + ",节点:" + event.getPath());
          }
      }, null);
  2. 事件发生 :当目标节点发生注册的事件(如 /config 数据被修改),ZooKeeper 服务器检测到事件。

  3. 发送通知 :服务器将事件信息(事件类型、节点路径等)封装为 WatchedEvent,通过网络异步发送给客户端。

  4. 客户端处理 :客户端收到通知后,触发注册的 Watcher 回调方法,执行自定义逻辑(如重新获取数据、重新注册监听等)。

8.2.3ZooKeeper解决单点故障

1.ZooKeeper解决单点故障的背景:为了解决Hadoop和HBase等系统的单点故障问题,ZooKeeper被设计为提供高可用性和容错性。

2.ZooKeeper的选主算法:利用帕克斯算法实现选主流程,确保在节点故障时能够选举出新的主节点。

3.ZooKeeper的数据一致性:通过二阶段处理实现数据一致性,确保选主过程的数据准确性。

8.2.4ZooKeeper的存储模型和监听机制

1.存储模型:ZooKeeper利用其存储模型来创建和验证节点,确保节点的唯一性和数据的一致性。

2.监听机制:通过监听节点的变化,ZooKeeper能够实时通知监听者节点状态的变化,从而实现分布式系统中的协调工作。

3.分布式锁:ZooKeeper的存储模型和监听机制也应用于分布式锁的实现,确保分布式系统中的锁的正确性和一致性。

九、Zookeeper集群搭建

ZooKeeper 是一个分布式协调服务,常用于分布式系统中的配置管理、服务发现、分布式锁等场景。以下是 ZooKeeper 环境搭建的详细步骤,包括单机模式、伪集群模式和集群模式的部署方法。

9.1.1、环境准备

  1. 依赖软件

  2. 服务器要求(集群模式)

    • 至少 3 台服务器(奇数台,便于选举 Leader)
    • 服务器间网络互通,关闭防火墙或开放 ZooKeeper 端口(默认 2181 客户端端口,2888 集群通信端口,3888 选举端口)

9.1.2、单机模式搭建(适合开发测试)

单机模式是最简单的部署方式,仅需一台服务器。

1. 安装 JDK
bash 复制代码
# 以 CentOS 为例,安装 OpenJDK 1.8
yum install -y java-1.8.0-openjdk-devel

# 验证 Java 环境
java -version  # 输出 java version "1.8.0_xxx" 即成功
2. 安装 ZooKeeper
bash 复制代码
# 下载并解压安装包
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz
tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz -C /opt/
cd /opt/
ln -s apache-zookeeper-3.8.4-bin zookeeper  # 创建软链接,方便后续升级
3. 配置 ZooKeeper
bash 复制代码
# 进入配置目录,复制默认配置文件
cd /opt/zookeeper/conf/
cp zoo_sample.cfg zoo.cfg  # ZooKeeper 启动时默认加载 zoo.cfg

# 编辑配置文件
vim zoo.cfg

配置文件核心参数(单机模式):

properties 复制代码
# 数据存储目录(需手动创建)
dataDir=/opt/zookeeper/data

# 客户端连接端口
clientPort=2181

# 心跳间隔(毫秒)
tickTime=2000

# Leader 初始化同步超时时间(tickTime 的倍数)
initLimit=10

# Leader 与 Follower 同步超时时间(tickTime 的倍数)
syncLimit=5

创建数据目录:

bash 复制代码
mkdir -p /opt/zookeeper/data
4. 启动与验证
bash 复制代码
# 启动 ZooKeeper(后台运行)
/opt/zookeeper/bin/zkServer.sh start

# 查看状态(单机模式显示 Mode: standalone)
/opt/zookeeper/bin/zkServer.sh status

# 连接客户端(本地测试)
/opt/zookeeper/bin/zkCli.sh -server localhost:2181

客户端连接成功后,可执行简单命令验证(如 ls / 查看根节点)。

9.1.2伪集群模式(一台服务器模拟集群,适合测试)

伪集群模式在单台服务器上部署多个 ZooKeeper 实例,通过不同端口区分。

1. 准备目录结构
bash 复制代码
# 创建总目录
mkdir -p /opt/zookeeper-cluster
cd /opt/zookeeper-cluster

# 复制 3 个实例(对应 3 个节点)
cp -r /opt/zookeeper zk1
cp -r /opt/zookeeper zk2
cp -r /opt/zookeeper zk3

# 分别创建数据目录和日志目录
for i in 1 2 3; do
  mkdir -p zk$i/data zk$i/logs
done
2. 配置每个实例

zk1 为例,编辑 zk1/conf/zoo.cfg

properties 复制代码
# 数据目录
dataDir=/opt/zookeeper-cluster/zk1/data
# 日志目录
dataLogDir=/opt/zookeeper-cluster/zk1/logs
# 客户端端口(3 个实例分别为 2181、2182、2183)
clientPort=2181

# 集群节点配置(格式:server.节点ID=IP:通信端口:选举端口)
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

zk2zk3 配置类似,仅需修改 clientPort(2182、2183)、dataDirdataLogDir 路径。

3. 配置节点 ID

每个节点需在数据目录下创建 myid 文件,内容为节点 ID(与 server.X 中的 X 对应):

bash 复制代码
echo 1 > zk1/data/myid
echo 2 > zk2/data/myid
echo 3 > zk3/data/myid
4. 启动集群
bash 复制代码
# 分别启动 3 个节点
/opt/zookeeper-cluster/zk1/bin/zkServer.sh start
/opt/zookeeper-cluster/zk2/bin/zkServer.sh start
/opt/zookeeper-cluster/zk3/bin/zkServer.sh start

# 查看每个节点状态(会显示 Leader/Follower)
/opt/zookeeper-cluster/zk1/bin/zkServer.sh status

9.1.2集群模式(生产环境,多台服务器)

集群模式需多台服务器(如 3 台,IP 分别为 192.168.1.101192.168.1.102192.168.1.103)。

1. 每台服务器安装 ZooKeeper

步骤同单机模式的"安装 JDK"和"安装 ZooKeeper",确保所有服务器的 ZooKeeper 路径一致(如 /opt/zookeeper)。

2. 配置集群

在每台服务器的 zoo.cfg 中添加集群节点配置:

properties 复制代码
dataDir=/opt/zookeeper/data
dataLogDir=/opt/zookeeper/logs
clientPort=2181

# 集群节点(IP 替换为实际服务器 IP)
server.1=192.168.1.101:2888:3888
server.2=192.168.1.102:2888:3888
server.3=192.168.1.103:2888:3888
3. 配置节点 ID

分别在 3 台服务器的 dataDir 下创建 myid

bash 复制代码
# 192.168.1.101 服务器
echo 1 > /opt/zookeeper/data/myid

# 192.168.1.102 服务器
echo 2 > /opt/zookeeper/data/myid

# 192.168.1.103 服务器
echo 3 > /opt/zookeeper/data/myid
4. 启动集群

在每台服务器上执行启动命令:

bash 复制代码
/opt/zookeeper/bin/zkServer.sh start

启动后,通过 zkServer.sh status 查看角色(Leader 或 Follower),集群正常运行时会有一个 Leader 和两个 Follower。

9.1.2常见问题与管理命令

  1. 启动失败排查

    • 查看日志:/opt/zookeeper/logs/zookeeper-xxx.out
    • 检查 myid 是否正确,端口是否被占用(netstat -tulpn | grep 2181)。
  2. 常用命令

    • 停止服务:zkServer.sh stop
    • 重启服务:zkServer.sh restart
    • 客户端连接远程节点:zkCli.sh -server 192.168.1.101:2181

通过以上步骤,可完成 ZooKeeper 的单机、伪集群或生产级集群部署。集群模式下,ZooKeeper 会通过 Raft 算法(ZAB 协议,类似 Raft)保证数据一致性,容忍少数节点故障。

十、附录用到常用脚本

zookeeper群起shell脚本:

bash 复制代码
#!/bin/bash

user=$(whoami)
case $1 in
    "start")
        for i in node01 node02 node03
        do
            echo -e "\e[1;34m==================== $i ZooKeeper 启动 ====================\e[0m"
            ssh $user@$i "/opt/yjx/apache-zookeeper-3.6.3-bin/bin/zkServer.sh start"
        done
        ;;
    "stop")
        for i in node01 node02 node03
        do
            echo -e "\e[1;34m==================== $i ZooKeeper 停止 ====================\e[0m"
            ssh $user@$i "/opt/yjx/apache-zookeeper-3.6.3-bin/bin/zkServer.sh stop"
        done
        ;;
    "status")
        for i in node01 node02 node03
        do
            echo -e "\e[1;34m==================== $i ZooKeeper 状态 ====================\e[0m"
            ssh $user@$i "/opt/yjx/apache-zookeeper-3.6.3-bin/bin/zkServer.sh status"
        done
        ;;
esac

jpsall脚本:

bash 复制代码
#!/bin/bash

user=$(whoami)
# $#:传递给脚本或函数的参数个数
params_count=$#
# 如果没有参数,直接运行 "jps"
if [ $params_count -lt 1 ]
then
    for i in node01 node02 node03
    do
        echo -e "\e[1;34m==================== $i ====================\e[0m"
        ssh $user@$i jps
    done
    exit
fi

# 如果有参数,运行 "jps -参数"
for i in node01 node02 node03
do
    echo -e "\e[1;34m==================== $i ====================\e[0m"
    params=""
    for p in $@
    do
        params+="$p "
    done
    ssh $user@$i "jps $params"
done

rsync脚本

bash 复制代码
#!/bin/bash

# 获取输入参数的个数
param_count=$#
# 如果没有参数,直接退出
if [ $param_count -lt 1 ]
then
    echo -e "\e[1;31mYou must pass in the file name parameter.\e[0m"
    exit
fi

# 如果有参数,遍历参数(文件或目录名称)
for p in $@
do
    echo -e "\e[1;34m==================== $p 开始同步 ====================\e[0m"
    # basename:显示文件路径名的基本文件名,例如 /opt/bd 会显示 bd;/opt/bd/test.txt 会显示 test.txt
    file_name=$(basename $p)
    echo file_name=$file_name

    # 获取文件的上级目录的绝对路径
    # -P:如果切换的目标目录是一个符号链接,则直接切换到符号链接指向的目标目录
    parent_dir=`cd -P $(dirname $p); pwd`
    echo parent_dir=$parent_dir

    # 获取当前用户名称
    user=$(whoami)

    # 循环处理文件
    for i in node01 node02 node03
    do
        echo -e "\e[1;34m==================== $i ====================\e[0m"
        rsync -av --delete $parent_dir/$file_name $user@$i:$parent_dir
    done
done
csharp 复制代码
今天这篇文章就到这里了,大厦之成,非一木之材也;大海之阔,非一流之归也。感谢大家观看本文
相关推荐
zoulingzhi_yjs38 分钟前
haproxy配置详解
linux·云原生
itLaity44 分钟前
基于Kafka实现简单的延时队列
spring boot·分布式·kafka
快乐肚皮1 小时前
ZooKeeper学习专栏(五):Java客户端开发(原生API)详解
学习·zookeeper·java-zookeeper
qq_529835351 小时前
Zookeeper的简单了解
分布式·zookeeper·云原生
smileNicky2 小时前
RabbitMQ有多少种Exchange?
分布式·rabbitmq
你我约定有三2 小时前
RabbitMQ--消息丢失问题及解决
java·开发语言·分布式·后端·rabbitmq·ruby
Java初学者小白2 小时前
秋招Day19 - 分布式 - 分布式事务
java·分布式
是2的10次方啊6 小时前
微信公众号阅读量为什么会不一致?一文读懂分布式系统的那些事儿
分布式
终端行者6 小时前
k8s之Ingress服务接入控制器
云原生·容器·kubernetes