这可能是最简单易懂的 ZooKeeper 笔记
分布式架构
cap 与 base 理论
cap 定理:
一个分布式系统不可能同时满足一致性 (c:consistency)、可用性(a:availability)和分区容错性(p:partition tolerance)这三个基本要求,最多只能同时满足其中的两项。
我们需要明确一点,对于一个分布式系统而言,分区容错性是一个最基本的要求,既然是一个分布式系统,那么分布式系统中的组件必然需要被部署到不同的节点,否则也就无所谓分布式系统了。因此我们一般把精力花在如何根据业务特点在 c 和 a 之间寻求平衡。
base 理论:
base 是 basically available (基本可用),soft state (软状态)和 eventually consistent (最终一致性) 三个短语的简写,base 是对 cap 中一致性和可用性权衡的结果,其核心思想是即使无法做到强一致性,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。
一致性协议
- 2 pc
- 3 pc
- paxos 算法
初识 zookeeper
zookeeper 介绍
zookeeper 是一个开源的分布式的(多台机器一起工作),为分布式应用提供协调服务的 apache 项目。
zookeeper 工作机制
zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,zookeeper 就将负责通知已经在 zookeeper 上注册的那些观察者做出相应的反应。
例子:
服务端启动时去注册信息(创建的都是临时节点);客户端获取当前在线服务器列表,并注册监听;当服务器节点下线,服务器节点下线事件通知客户端,客户端重新去获取服务器列表,并注册监听。
zookeeper = 文件系统 + 通知机制
zookeeper 特点
- 一个 领导者(leader),多个跟随者(follower)组成的集群
- 集群中只要有半数以上节点存活,zookeeper集群就能正常服务。因此服务器最好设奇数台。
- 全局数据一致性:每台服务器保存一份相同的数据副本,client 无论连接到哪个 server,数据都是一致性的。
- 更新请求顺序进行,来自同一个 client 的更新请求按其发送顺序依次执行。
- 数据更新原子性,一次数据更新要么成功,要么失败。典型的事务原子性。
- 实时性,在一定时间范围内,client 能读取到最新的数据。
zookeeper 数据结构
zk 数据模型的结构整体上可以看作一棵树,每个节点称作一个 znode。每个 znode 默认能够存储 1mb 的数据,每个 znode 都是通过其路径唯一标识的
zookeeper 应用场景
zk 提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
统一命名服务
在分布式环境下,经常需要对应用/服务进行统一命名,便于识别
例如:ip 地址难记,但是域名好记。如下图,将 www.baidu.com 这个域名与旗下的三个 服务器 ip 地址对应起来,当访问 www.baidu.com 的时候自动从三个 ip 地址中选一个进行访问。
统一配置管理
- 分布式环境下,配置文件同步非常常见。
- 一般要求一个集群中,所有节点的配置信息是一致的,比如 kafka 集群。
- 对配置文件修改后,希望能够快速同步到各个节点上。
- 配置管理可交给 zookeeper 实现。
- 可以将配置信息写入 zookeeper 上的一个 znode。
- 各个客户端服务器监听这个 znode。
- 一旦 znode 中的数据被修改,zookeeper 将通知各个客户端服务器。
统一集群管理
- 分布式环境中,实时掌握每个节点的状态是必要的。
- 可根据节点实时状态做出一些调整。
- zookeeper 可以实现实时监控节点状态变化
- 可以将节点信息写入 zookeeper 上的一个 znode。
- 监听这个 znode 可获取它的实时状态变化。
服务上下线
客户端能够实时洞察到服务器上下线的变化。服务端启动时去注册信息(创建的都是临时节点);客户端获取当前在线服务器列表,并注册监听;当服务器节点下线,服务器节点下线事件通知客户端,客户端重新去获取服务器列表,并注册监听。
软负载均衡
在 zookeeper 中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求。
zookeeper 内部原理
选举机制
- 半数机制:集群中半数以上的机器存活,集群可用。所以 zookeeper 适合安装奇数台服务器
- zookeeper 在没有 master 和 slave,但是 zookeeper 工作时是分为 leader 和 follower 的。leader 只有一个,是通过内部选举机制临时产生的。
例子:
假设有五台服务器组成的 zookeeper 集群,他们的 id 从 1-5,同时它们都是刚刚启动的。假设这些服务器依序启动:
- 服务器 1 启动,现在只有它自己一台服务器,它发出去的报文没有任何响应,因此它的选举状态一直是 looking 状态。
- 服务器 2 启动,它与最开始启动的服务器 1 进行通信。这时候 1 自己有自己一票,还投了 id 大的服务器,即 2 一票,2 有自己的一票和 1 的一票,共两票。因此 id 值大的 服务器 2 胜出,但是没有达到超过半数以上的服务器都同意选举它(由于这个例子有 5 台服务器,因此需要3台同意,即拥有 3 票)。所以服务器 1、2 还是继续保持 looking 状态。
- 服务器 3 启动,过程和 2 相同,因此 3 有 三票,2 有 2 票,1 有 1 票,服务器 3 三票超过一半,成功成为 leader 。
- 服务器 4 ,由于 3 已经是 leader 因此它只能作为 follower。
- 服务器 5 也类似,只能作为 follower。
节点类型
- 持久(persistent):客户端和服务器端断开连接后,创建的节点不删除
- 持久化目录节点:客户端与 zookeeper 断开连接后,该节点依旧存在
- 持久化顺序编号目录节点:客户端与 zookeeper 断开连接后,该节点依旧存在,只是 zookeeper 给该节点名称进行顺序编号。
- 短暂(ephemeral):客户端和服务器端断开连接后,创建的节点自己删除(服务器上下线)
- 临时目录节点:客户端与 zookeeper 断开连接后,该节点被删除。
- 客户端与 zookeeper 断开连接后,该节点被删除,只是 zookeeper 给该节点名称进行顺序编号。
说明:创建 znode 时设置顺序标识,znode 名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护。在分布式系统中,顺序号可用被用于为所有的事件进行全局排序,这样客户端可用通过顺序号来推断事件的顺序。
监听器原理
- 监听器原理
- 首先有个 main 线程
- 在 main 线程中启动 zookeeper 客户端,这时会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listenner)。
- 通过 connect 线程将注册的监听事件发送给 zookeeper。
- 在 zookeeper 的注册监听器列表中将注册的监听事件添加到列表中。
- zookeeper 监听到由数据或者路径发生变化,就会将这个消息发送给 listenner 线程。
- listenner 线程内部调用了 process()方法。
- 常用的监听
- 监听节点数据的变化:get path[watch]
- 监听子节点增减的变化:ls path[watch]
写数据流程
- 假设client 向 zookeeper 上的 server 1 写数据,发送一个写请求。
- 如果 server 1 不是 leader,那么 server 1 会把接受到的请求进一步发送给 leader,因为每个 zookeeper 的服务器集群里面有一个 是 leader,这个 leader 会将所有写请求广播给各个 server。各个 server 写成功后就会通知 leader
- 当 leader 收到大多数 server 数据写成功了,那么就说明数据写成功了,如果有三台服务器,只要有两台写成功了,那么就认为数据写成功了,写成功后,leader 告诉 server 1 数据写成功了。
- server 1 会进一步通知 client 数据写成功了,这时就会认为整个写操作成功。
自我小结
zookeeper 是一个采用 zab 作为数据一致性协议的分布式数据一致性协调框架。zookeeper 可以作为分布式配置管理,集群服务,数据发布/订阅,服务注册/发现,分布式锁等的实现。其内部采用 znode 节点维护一系列数据,当数据改变的时候可以通过 watche 机制告诉客户端。当 zookeeper 作为分布式消息系统的管理,如 kafka 的管理时,可以将所有 kafka 服务器,即所有的 broker 的信息写入 zookeeper 节点中,当加服务器时只要在节点下加入一个临时子节点,服务器宕机或下线时临时子节点将会自动删除。很容易实现服务器的集群管理。不光如此,zookeeper也可以用来维护 topic 主题和 producer 和consumer 等的信息。当 zookeeper 作为分布式服务框架的注册中心时,可以将服务注册到 zookeeper 节点上,每个服务对应一个节点,子节点就是所有提供了该服务的机器的地址。每当有一个服务提供者启动的时候都会网对应的服务节点下创建自己的临时节点,存放自己的地址信息。消费者需要某个服务的时候只需要到对应的服务节点中随便取一个子节点然后使用该服务就行了。监控中心可以很容易的通过现有的节点监控信息。
zookeeper 集群中会自动选举一个 leader 服务器负责事务的操作,其余的 follower服务器可以处理非事务操作、参与 leader 服务器的投票等。而 observer 服务器只能处理非事务的操作,但是不能参与任何投票。
总之,zookeeper 常用来维护各种分布式应用的一个状态,使得分布式应用本身无状态,只需要向 zookeeper 注册自己的状态,当需要某种状态的时候直接去 zookeeper 上取就行了。当自己关注的消息发生变化时,zookeeper 会通过 watche 进行通知,自己再进行对应的处理即可。
上一篇: c++11分享
下一篇: 再来五道剑指offer题目