做pc端网站案例网站开发涉及到缓存吗
做pc端网站案例,网站开发涉及到缓存吗,聊城网站优化案例,乐山高端网站建设1.1 ZooKeeper 是什么
ZooKeeper 是 Apache 的顶级项目。ZooKeeper 为分布式应用提供了高效且可靠的分布式协调服务#xff0c;提供了诸如统一命名服务、配置管理和分布式锁等分布式的基础服务。在解决分布式数据一致性方面#xff0c;ZooKeeper 并没有直接采用 Paxos 算法提供了诸如统一命名服务、配置管理和分布式锁等分布式的基础服务。在解决分布式数据一致性方面ZooKeeper 并没有直接采用 Paxos 算法而是采用了名为 ZAB 的一致性协议。
ZooKeeper 主要用来解决分布式集群中应用系统的一致性问题它能提供基于类似于文件系统的目录节点树方式的数据存储。但是 ZooKeeper 并不是用来专门存储数据的它的作用主要是用来维护和监控存储数据的状态变化。通过监控这些数据状态的变化从而可以达到基于数据的集群管理。
很多大名鼎鼎的框架都基于 ZooKeeper 来实现分布式高可用如Dubbo、Kafka 等。
1.2 ZooKeeper 的特性
ZooKeeper 具有以下特性
**顺序一致性**所有客户端看到的服务端数据模型都是一致的从一个客户端发起的事务请求最终都会严格按照其发起顺序被应用到 ZooKeeper 中。具体的实现可见下文原子广播。**原子性**所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的即整个集群要么都成功应用了某个事务要么都没有应用。实现方式可见下文事务。**单一视图**无论客户端连接的是哪个 Zookeeper 服务器其看到的服务端数据模型都是一致的。**高性能**ZooKeeper 将数据全量存储在内存中所以其性能很高。需要注意的是由于 ZooKeeper 的所有更新和删除都是基于事务的因此 ZooKeeper在读多写少的应用场景中有性能表现较好如果写操作频繁性能会大大下滑。**高可用**ZooKeeper 的高可用是基于副本机制实现的此外 ZooKeeper 支持故障恢复可见下文选举 Leader。
1.3 ZooKeeper 的设计目标
简单的数据模型可以构建集群顺序访问高性能
二、ZooKeeper 核心概念
2.1 数据模型
ZooKeeper 的数据模型是一个树形结构的文件系统。
树中的节点被称为 znode其中根节点为 /每个节点上都会保存自己的数据和节点信息。znode 可以用于存储数据并且有一个与之相关联的 ACL详情可见 ACL。ZooKeeper 的设计目标是实现协调服务而不是真的作为一个文件存储因此 znode 存储数据的大小被限制在 1MB 以内。
**ZooKeeper 的数据访问具有原子性。**其读写操作都是要么全部成功要么全部失败。
znode 通过路径被引用。znode 节点路径必须是绝对路径。
znode 有两种类型
**临时的 EPHEMERAL **户端会话结束时ZooKeeper 就会删除临时的 znode。**持久的PERSISTENT **除非客户端主动执行删除操作否则 ZooKeeper 不会删除持久的 znode。
2.2 节点信息
znode 上有一个顺序标志 SEQUENTIAL 。如果在创建 znode 时设置了顺序标志 SEQUENTIAL 那么 ZooKeeper 会使用计数器为 znode 添加一个单调递增的数值即 zxid。ZooKeeper 正是利用 zxid 实现了严格的顺序访问控制能力。
每个 znode 节点在存储数据的同时都会维护一个叫做 Stat 的数据结构里面存储了关于该节点的全部状态信息。如下 2.3 集群角色
Zookeeper 集群是一个基于主从复制的高可用集群每个服务器承担如下三种角色中的一种。
**Leader**它负责 发起并维护与各 Follwer 及 Observer 间的心跳。所有的写操作必须要通过 Leader 完成再由 Leader 将写操作广播给其它服务器。一个 Zookeeper 集群同一时间只会有一个实际工作的 Leader。**Follower**它会响应 Leader 的心跳。Follower 可直接处理并返回客户端的读请求同时会将写请求转发给 Leader 处理并且负责在 Leader 处理写请求时对请求进行投票。一个 Zookeeper 集群可能同时存在多个 Follower。**Observer**角色与 Follower 类似但是无投票权。
2.4 ACL
ZooKeeper 采用 ACLAccess Control Lists策略来进行权限控制。
每个 znode 创建时都会带有一个 ACL 列表用于决定谁可以对它执行何种操作。
ACL 依赖于 ZooKeeper 的客户端认证机制。ZooKeeper 提供了以下几种认证方式
digest 用户名和密码 来识别客户端**sasl**通过 kerberos 来识别客户端**ip**通过 IP 来识别客户端
ZooKeeper 定义了如下五种权限
**CREATE**允许创建子节点**READ**允许从节点获取数据并列出其子节点WRITE 允许为节点设置数据**DELETE**允许删除子节点ADMIN 允许为节点设置权限。
三、ZooKeeper 工作原理
3.1 读操作
Leader/Follower/Observer 都可直接处理读请求从本地内存中读取数据并返回给客户端即可。
由于处理读请求不需要服务器之间的交互Follower/Observer 越多整体系统的读请求吞吐量越大也即读性能越好。
3.2 写操作
所有的写请求实际上都要交给 Leader 处理。Leader 将写请求以事务形式发给所有 Follower 并等待 ACK一旦收到半数以上 Follower 的 ACK即认为写操作成功。
3.2.1 写 Leader
通过 Leader 进行写操作主要分为五步
客户端向 Leader 发起写请求。Leader 将写请求以事务 Proposal 的形式发给所有 Follower 并等待 ACK。Follower 收到 Leader 的事务 Proposal 后返回 ACK。Leader 得到过半数的 ACKLeader 对自己默认有一个 ACK后向所有的 Follower 和 Observer 发送 Commmit。Leader 将处理结果返回给客户端。
注意
Leader 不需要得到 Observer 的 ACK即 Observer 无投票权。Leader 不需要得到所有 Follower 的 ACK只要收到过半的 ACK 即可同时 Leader 本身对自己有一个 ACK。上图中有 4 个 Follower只需其中两个返回 ACK 即可因为 ( 2 1 ) / ( 4 1 ) 1 / 2 (21) / (41) 1/2 (21)/(41)1/2 。Observer 虽然无投票权但仍须同步 Leader 的数据从而在处理读请求时可以返回尽可能新的数据。
3.2.2 写 Follower/Observer Follower/Observer 均可接受写请求但不能直接处理而需要将写请求转发给 Leader 处理。
除了多了一步请求转发其它流程与直接写 Leader 无任何区别。
3.3 事务
对于来自客户端的每个更新请求ZooKeeper 具备严格的顺序访问控制能力。
为了保证事务的顺序一致性ZooKeeper 采用了递增的事务 id 号zxid来标识事务。
**Leader 服务会为每一个 Follower 服务器分配一个单独的队列然后将事务 Proposal 依次放入队列中并根据 FIFO(先进先出) 的策略进行消息发送。**Follower 服务在接收到 Proposal 后会将其以事务日志的形式写入本地磁盘中并在写入成功后反馈给 Leader 一个 Ack 响应。**当 Leader 接收到超过半数 Follower 的 Ack 响应后就会广播一个 Commit 消息给所有的 Follower 以通知其进行事务提交**之后 Leader 自身也会完成对事务的提交。而每一个 Follower 则在接收到 Commit 消息后完成事务的提交。
所有的提议proposal都在被提出的时候加上了 zxid。zxid 是一个 64 位的数字它的高 32 位是 epoch 用来标识 Leader 关系是否改变每次一个 Leader 被选出来它都会有一个新的 epoch标识当前属于那个 leader 的统治时期。低 32 位用于递增计数。
详细过程如下
Leader 等待 Server 连接Follower 连接 Leader将最大的 zxid 发送给 LeaderLeader 根据 Follower 的 zxid 确定同步点完成同步后通知 follower 已经成为 uptodate 状态Follower 收到 uptodate 消息后又可以重新接受 client 的请求进行服务了。
3.4 观察
客户端注册监听它关心的 znode当 znode 状态发生变化数据变化、子节点增减变化时ZooKeeper 服务会通知客户端。
客户端和服务端保持连接一般有两种形式
客户端向服务端不断轮询服务端向客户端推送状态
Zookeeper 的选择是服务端主动推送状态也就是观察机制 Watch 。
ZooKeeper 的观察机制允许用户在指定节点上针对感兴趣的事件注册监听当事件发生时监听器会被触发并将事件信息推送到客户端。
客户端使用 getData 等接口获取 znode 状态时传入了一个用于处理节点变更的回调那么服务端就会主动向客户端推送节点的变更
从这个方法中传入的 Watcher 对象实现了相应的 process 方法每次对应节点出现了状态的改变WatchManager 都会通过以下的方式调用传入 Watcher 的方法
SetWatcher triggerWatch(String path, EventType type, SetWatcher supress) {
WatchedEvent e new WatchedEvent(type, KeeperState.SyncConnected, path);
SetWatcher watchers;
synchronized (this) { watchers watchTable.remove(path);
}
for (Watcher w : watchers) { w.process(e);
}
returnZookeeper 中的所有数据其实都是由一个名为 DataTree 的数据结构管理的所有的读写数据的请求最终都会改变这颗树的内容在发出读请求时可能会传入 Watcher 注册一个回调函数而写请求就可能会触发相应的回调由 WatchManager 通知客户端数据的变化。
通知机制的实现其实还是比较简单的通过读请求设置 Watcher 监听事件写请求在触发事件时就能将通知发送给指定的客户端。
3.5 会话
ZooKeeper 客户端通过 TCP 长连接连接到 ZooKeeper 服务集群。会话 (Session) 从第一次连接开始就已经建立之后通过心跳检测机制来保持有效的会话状态。通过这个连接客户端可以发送请求并接收响应同时也可以接收到 Watch 事件的通知。
每个 ZooKeeper 客户端配置中都配置了 ZooKeeper 服务器集群列表。启动时客户端会遍历列表去尝试建立连接。如果失败它会尝试连接下一个服务器依次类推。
一旦一台客户端与一台服务器建立连接这台服务器会为这个客户端创建一个新的会话。**每个会话都会有一个超时时间若服务器在超时时间内没有收到任何请求则相应会话被视为过期。**一旦会话过期就无法再重新打开且任何与该会话相关的临时 znode 都会被删除。
通常来说会话应该长期存在而这需要由客户端来保证。客户端可以通过心跳方式ping来保持会话不过期。 ZooKeeper 的会话具有四个属性
**sessionID**会话 ID唯一标识一个会话每次客户端创建新的会话时Zookeeper 都会为其分配一个全局唯一的 sessionID。**TimeOut**会话超时时间客户端在构造 Zookeeper 实例时会配置 sessionTimeout 参数用于指定会话的超时时间Zookeeper 客户端向服务端发送这个超时时间后服务端会根据自己的超时时间限制最终确定会话的超时时间。**TickTime**下次会话超时时间点为了便于 Zookeeper 对会话实行”分桶策略”管理同时为了高效低耗地实现会话的超时检查与清理Zookeeper 会为每个会话标记一个下次会话超时时间点其值大致等于当前时间加上 TimeOut。**isClosing**标记一个会话是否已经被关闭当服务端检测到会话已经超时失效时会将该会话的 isClosing 标记为”已关闭”这样就能确保不再处理来自该会话的新请求了。
Zookeeper 的会话管理主要是通过 SessionTracker 来负责其采用了分桶策略将类似的会话放在同一区块中进行管理进行管理以便 Zookeeper 对会话进行不同区块的隔离处理以及同一区块的统一处理。
四、ZAB 协议
ZooKeeper 并没有直接采用 Paxos 算法而是采用了名为 ZAB 的一致性协议。ZAB 协议不是 Paxos 算法只是比较类似二者在操作上并不相同。
ZAB 协议是 Zookeeper 专门设计的一种支持崩溃恢复的原子广播协议。
ZAB 协议是 ZooKeeper 的数据一致性和高可用解决方案。
ZAB 协议定义了两个可以无限循环的流程
**选举 Leader**用于故障恢复从而保证高可用。**原子广播**用于主从同步从而保证数据一致性。
4.1 选举 Leader
ZooKeeper 的故障恢复
ZooKeeper 集群采用一主称为 Leader多从称为 Follower模式主从节点通过副本机制保证数据一致。 如果 Follower 节点挂了 - ZooKeeper 集群中的每个节点都会单独在内存中维护自身的状态并且各节点之间都保持着通讯只要集群中有半数机器能够正常工作那么整个集群就可以正常提供服务。 如果 Leader 节点挂了 - 如果 Leader 节点挂了系统就不能正常工作了。此时需要通过 ZAB 协议的选举 Leader 机制来进行故障恢复。
ZAB 协议的选举 Leader 机制简单来说就是基于过半选举机制产生新的 Leader之后其他机器将从新的 Leader 上同步状态当有过半机器完成状态同步后就退出选举 Leader 模式进入原子广播模式。
4.1.1 术语
**myid**每个 Zookeeper 服务器都需要在数据文件夹下创建一个名为 myid 的文件该文件包含整个 Zookeeper 集群唯一的 ID整数。
**zxid**类似于 RDBMS 中的事务 ID用于标识一次更新操作的 Proposal ID。为了保证顺序性该 zkid 必须单调递增。因此 Zookeeper 使用一个 64 位的数来表示高 32 位是 Leader 的 epoch从 1 开始每次选出新的 Leaderepoch 加一。低 32 位为该 epoch 内的序号每次 epoch 变化都将低 32 位的序号重置。这样保证了 zkid 的全局递增性。
4.1.2 服务器状态
**LOOKING**不确定 Leader 状态。该状态下的服务器认为当前集群中没有 Leader会发起 Leader 选举。**FOLLOWING**跟随者状态。表明当前服务器角色是 Follower并且它知道 Leader 是谁。**LEADING**领导者状态。表明当前服务器角色是 Leader它会维护与 Follower 间的心跳。**OBSERVING**观察者状态。表明当前服务器角色是 Observer与 Folower 唯一的不同在于不参与选举也不参与集群写操作时的投票。
4.1.3 选票数据结构
每个服务器在进行领导选举时会发送如下关键信息
**logicClock**每个服务器会维护一个自增的整数名为 logicClock它表示这是该服务器发起的第多少轮投票。**state**当前服务器的状态。**self_id**当前服务器的 myid。**self_zxid**当前服务器上所保存的数据的最大 zxid。**vote_id**被推举的服务器的 myid。**vote_zxid**被推举的服务器上所保存的数据的最大 zxid。
4.1.4 投票流程
1自增选举轮次
Zookeeper 规定所有有效的投票都必须在同一轮次中。每个服务器在开始新一轮投票时会先对自己维护的 logicClock 进行自增操作。
2初始化选票
每个服务器在广播自己的选票前会将自己的投票箱清空。该投票箱记录了所收到的选票。例服务器 2 投票给服务器 3服务器 3 投票给服务器 1则服务器 1 的投票箱为(2, 3), (3, 1), (1, 1)。票箱中只会记录每一投票者的最后一票如投票者更新自己的选票则其它服务器收到该新选票后会在自己票箱中更新该服务器的选票。
3发送初始化选票
每个服务器最开始都是通过广播把票投给自己。
4接收外部投票
服务器会尝试从其它服务器获取投票并记入自己的投票箱内。如果无法获取任何外部投票则会确认自己是否与集群中其它服务器保持着有效连接。如果是则再次发送自己的投票如果否则马上与之建立连接。
5判断选举轮次
收到外部投票后首先会根据投票信息中所包含的 logicClock 来进行不同处理
外部投票的 logicClock 大于自己的 logicClock。说明该服务器的选举轮次落后于其它服务器的选举轮次立即清空自己的投票箱并将自己的 logicClock 更新为收到的 logicClock然后再对比自己之前的投票与收到的投票以确定是否需要变更自己的投票最终再次将自己的投票广播出去。外部投票的 logicClock 小于自己的 logicClock。当前服务器直接忽略该投票继续处理下一个投票。外部投票的 logickClock 与自己的相等。当时进行选票 PK。
6选票 PK
选票 PK 是基于(self_id, self_zxid)与(vote_id, vote_zxid)的对比
外部投票的 logicClock 大于自己的 logicClock则将自己的 logicClock 及自己的选票的 logicClock 变更为收到的 logicClock。若 logicClock 一致则对比二者的 vote_zxid若外部投票的 vote_zxid 比较大则将自己的票中的 vote_zxid 与 vote_myid 更新为收到的票中的 vote_zxid 与 vote_myid 并广播出去另外将收到的票及自己更新后的票放入自己的票箱。如果票箱内已存在(self_myid, self_zxid)相同的选票则直接覆盖。若二者 vote_zxid 一致则比较二者的 vote_myid若外部投票的 vote_myid 比较大则将自己的票中的 vote_myid 更新为收到的票中的 vote_myid 并广播出去另外将收到的票及自己更新后的票放入自己的票箱。
7统计选票
如果已经确定有过半服务器认可了自己的投票可能是更新后的投票则终止投票。否则继续接收其它服务器的投票。
8更新服务器状态
投票终止后服务器开始更新自身状态。若过半的票投给了自己则将自己的服务器状态更新为 LEADING否则将自己的状态更新为 FOLLOWING。
通过以上流程分析我们不难看出要使 Leader 获得多数 Server 的支持则 ZooKeeper 集群节点数必须是奇数。且存活的节点数目不得少于 N 1 。
每个 Server 启动后都会重复以上流程。在恢复模式下如果是刚从崩溃状态恢复的或者刚启动的 server 还会从磁盘快照中恢复数据和会话信息zk 会记录事务日志并定期进行快照方便在恢复时进行状态恢复。
4.2 原子广播Atomic Broadcast
ZooKeeper 通过副本机制来实现高可用。
那么ZooKeeper 是如何实现副本机制的呢答案是ZAB 协议的原子广播。 ZAB 协议的原子广播要求
**所有的写请求都会被转发给 LeaderLeader 会以原子广播的方式通知 Follow。当半数以上的 Follow 已经更新状态持久化后Leader 才会提交这个更新然后客户端才会收到一个更新成功的响应。**这有些类似数据库中的两阶段提交协议。
在整个消息的广播过程中Leader 服务器会每个事物请求生成对应的 Proposal并为其分配一个全局唯一的递增的事务 ID(ZXID)之后再对其进行广播。
五、ZooKeeper 应用
ZooKeeper 可以用于发布/订阅、负载均衡、命令服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能 。
5.1 命名服务
在分布式系统中通常需要一个全局唯一的名字如生成全局唯一的订单号等ZooKeeper 可以通过顺序节点的特性来生成全局唯一 ID从而可以对分布式系统提供命名服务。
5.2 配置管理
利用 ZooKeeper 的观察机制可以将其作为一个高可用的配置存储器允许分布式应用的参与者检索和更新配置文件。
5.3 分布式锁
可以通过 ZooKeeper 的临时节点和 Watcher 机制来实现分布式锁。
举例来说有一个分布式系统有三个节点 A、B、C试图通过 ZooKeeper 获取分布式锁。
1访问 /lock 这个目录路径由程序自己决定创建 带序列号的临时节点EPHEMERAL 。
2每个节点尝试获取锁时拿到 /locks节点下的所有子节点id_0000,id_0001,id_0002判断自己创建的节点是不是最小的。 如果是则拿到锁。 释放锁执行完操作后把创建的节点给删掉。 如果不是则监听比自己要小 1 的节点变化。
3释放锁即删除自己创建的节点。
NodeA 删除自己创建的节点 id_0000NodeB 监听到变化发现自己的节点已经是最小节点即可获取到锁。
5.4 集群管理
ZooKeeper 还能解决大多数分布式系统中的问题 如可以通过创建临时节点来建立心跳检测机制。如果分布式系统的某个服务节点宕机了则其持有的会话会超时此时该临时节点会被删除相应的监听事件就会被触发。 分布式系统的每个服务节点还可以将自己的节点状态写入临时节点从而完成状态报告或节点工作进度汇报。 通过数据的订阅和发布功能ZooKeeper 还能对分布式系统进行模块的解耦和任务的调度。 通过监听机制还能对分布式系统的服务节点进行动态上下线从而实现服务的动态扩容。
5.5 选举 Leader 节点
分布式系统一个重要的模式就是主从模式 (Master/Salves)ZooKeeper 可以用于该模式下的 Matser 选举。可以让所有服务节点去竞争性地创建同一个 ZNode由于 ZooKeeper 不能有路径相同的 ZNode必然只有一个服务节点能够创建成功这样该服务节点就可以成为 Master 节点。
5.6 队列管理
ZooKeeper 可以处理两种类型的队列
当一个队列的成员都聚齐时这个队列才可用否则一直等待所有成员到达这种是同步队列。队列按照 FIFO 方式进行入队和出队操作例如实现生产者和消费者模型。
同步队列用 ZooKeeper 实现的实现思路如下
线从而实现服务的动态扩容。
5.5 选举 Leader 节点
分布式系统一个重要的模式就是主从模式 (Master/Salves)ZooKeeper 可以用于该模式下的 Matser 选举。可以让所有服务节点去竞争性地创建同一个 ZNode由于 ZooKeeper 不能有路径相同的 ZNode必然只有一个服务节点能够创建成功这样该服务节点就可以成为 Master 节点。
5.6 队列管理
ZooKeeper 可以处理两种类型的队列
当一个队列的成员都聚齐时这个队列才可用否则一直等待所有成员到达这种是同步队列。队列按照 FIFO 方式进行入队和出队操作例如实现生产者和消费者模型。
同步队列用 ZooKeeper 实现的实现思路如下
创建一个父目录 /synchronizing每个成员都监控标志Set Watch位目录 /synchronizing/start 是否存在然后每个成员都加入这个队列加入队列的方式就是创建 /synchronizing/member_i 的临时目录节点然后每个成员获取 / synchronizing 目录的所有目录节点也就是 member_i。判断 i 的值是否已经是成员的个数如果小于成员个数等待 /synchronizing/start 的出现如果已经相等就创建 /synchronizing/start。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/87171.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!