Big Data框架--Zookeeper笔记

Zookeeper 常被用于分布式协调服务(即服务或元数据注册等场景,如 Dubbo、Kafka:将生产者或元数据信息注册到 Zookeeper 集群上,以便分布式系统其他参与者及时看到,因为 Zookeeper 实现了类似 Paxos 的 Zab 协议,解决了分布式数据一致性问题)、分布式锁等用途


CAP理论


一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项

Consistency 一致性

一致性指 all nodes see the same data at the same time,即所有节点在同一时间的数据完全一致。

一致性是因为多个数据拷贝下并发读写才有的问题,因此理解时一定要注意结合考虑多个数据拷贝下并发读写的场景。

对于一致性,可以分为从客户端和服务端两个不同的视角。

  • 客户端

    从客户端来看,一致性主要指的是多并发访问时更新过的数据如何获取的问题

  • 服务端

    从服务端来看,则是更新如何分布到整个系统,以保证数据最终一致。

对于一致性,可以分为强 / 弱 / 顺序一致性三类

从客户端角度,多进程并发访问时,更新过的数据在不同进程如何获取的不同策略,决定了不同的一致性。

  • 强一致性

    对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。当更新操作完成之后,任何多个后续进程或者线程的访问都会返回最新的更新过的值。这种是对用户最友好的,就是用户上一次写什么,下一次就保证能读到什么。当更新操作完成之后,任何多个后续进程或者线程的访问都会返回最新的更新过的值。这种是对用户最友好的,就是用户上一次写什么,下一次就保证能读到什么。

  • 弱一致性

    系统并不保证进程或者线程的访问都会返回最新的更新过的值。系统在数据写入成功之后,不承诺立即可以读到最新写入的值,也不会具体的承诺多久之后可以读到。但会尽可能保证在某个时间级别(比如秒级别)之后,可以让数据达到一致性状态。

    • 最终一致性

      如果经过一段时间后要求能访问到更新后的数据,则是最终一致性。包括:

      • 因果一致性(Casual Consistency)。如果进程 A 通知进程 B 它已更新了一个数据项,那么进程 B 的后续访问将返回更新后的值,且一次写入将保证取代前一次写入。与进程 A 无因果关系的进程 C 的访问,遵守一般的最终一致性规则。
      • “读己之所写(read-your-writes) 一致性。当进程 A 自己更新一个数据项之后,它总是访问到更新过的值,绝不会看到旧值。这是因果一致性模型的一个特例。
      • 会话(Session)一致性。这是上一个模型的实用版本,它把访问存储系统的进程放到会话的上下文中。只要会话还存在,系统就保证 “读己之所写” 一致性。如果由于某些失败情形令会话终止,就要建立新的会话,而且系统的保证不会延续到新的会话。
      • 单调(Monotonic)读一致性。如果进程已经看到过数据对象的某个值,那么任何后续访问都不会返回在那个值之前的值。
      • 单调写一致性。系统保证来自同一个进程的写操作顺序执行。要是系统不能保证这种程度的一致性,就非常难以编程了。
  • 顺序一致性

    • 任何一次读都能读到某个数据的最近一次写的数据。
    • 系统的所有进程的顺序一致,而且是合理的。即不需要和全局时钟下的顺序一致,错的话一起错,对的话一起对。

共识:

共识问题中所有的节点要最终达成共识,由于最终目标是所有节点都要达成一致,所以根本不存在一致性强弱之分。

例如,Paxos 是共识(Consensus)算法而不是强一致性(Consistency)协议。共识算法没有一致性级别的区分。

Availability 可用性

可用性指 Reads and writes always succeed,即服务在正常响应时间内一直可用。

好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。可用性通常情况下可用性和分布式数据冗余,负载均衡等有着很大的关联。

Partition Tolerance 分区容错性

分区容错性指 the system continues to operate despite arbitrary message loss or failure of part of the system,即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务。

CAP 权衡

无法满足CAP理论的情况:

  • CA without P:如果不要求 P(不允许分区),则 C(强一致性)和 A(可用性)是可以保证的。但其实分区不是你想不想的问题,而是始终会存在,因此 CA 的系统更多的是允许分区后各子系统依然保持 CA。
  • CP without A:如果不要求 A(可用),相当于每个请求都需要在 Server 之间强一致,而 P(分区)会导致同步时间无限延长,如此 CP 也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
  • AP wihtout C:要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。现在众多的 NoSQL 都属于此类。

AP

对于多数大型互联网应用的场景,主机众多、部署分散,而且现在的集群规模越来越大,所以节点故障、网络故障是常态,而且要保证服务可用性达到 N 个 9,即保证 P 和 A,舍弃 C(退而求其次保证最终一致性)。虽然某些地方会影响客户体验,但没达到造成用户流程的严重程度。

CA

对于涉及到钱财这样不能有一丝让步的场景,C 必须保证**。网络发生故障宁可停止服务,这是保证 CA,舍弃 P。貌似这几年国内银行业发生了不下 10 起事故,但影响面不大,报道也不多,广大群众知道的少。还有一种是保证 CP,舍弃 A。例如网络故障事只读不写。

CP

分布式数据库、缓存 redis、注册中心 zookeeper,只要是分布式存储数据的软件,都必须首先满足数据强一致性。其次分布式,肯定满足集群。可用性可以暂时失去。


ZooKeeper的CAP原则


简述

  • 一致性 C

Zookeeper 是强一致性系统,同步数据很快。但是在不用 sync() 操作的前提下无法保证各节点的数据完全一致。zookeeper 为了保证一致性使用了基于 paxos 协议且为 zookeeper 量身定做的 zab 协议。

  • 可用性 A(高可用性和响应能力)

Zookeeper 数据存储在内存中,且各个节点都可以相应读请求,具有好的响应性能。Zookeeper 保证了可用性, 数据总是可用的, 没有锁. 并且有一大半的节点所拥有的数据是最新的, 实时的。

  • 分区容忍性 P
    • 节点多了会导致写数据延时非常大(需要半数以上 follower 写完提交), 因为需要多个节点同步.
    • 节点多了 Leader 选举非常耗时, 就会放大网络的问题. 可以通过引入 observer 节点缓解这个问题.

ZooKeeper的顺序一致性

the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program.

ZooKeeper通过实现分布式锁来实现最终的一致性

实际上,Zookeeper的一致性更复杂一些,Zookeeper的读操作是sequential consistency的,Zookeeper的写操作是linearizability的。

为什么Zookeeper要实现sequential consistency?Zookeeper最核心的功能是用来做coordination service,也就是用来做分布式锁服务,在分布式的环境下,Zookeeper本身怎么做到“天然正确”?没有其他的synchronization机制保证Zookeeper是正确的,所以只要Zookeeper实现了sequential consistency,那它自身就可以保证正确性,从而对外提供锁服务。

ZooKeeper如何取舍CAP的

为了协调 CA(一致性和可用性),用户可以自己选择是否使用 Sync() 操作。使用则保证所有节点强一致,但是这个操作同步数据会有一定的延迟时间。反过来若不是必须保证强一致性的场景,可不使用 sync,虽然 zookeeper 同步的数据很快,但是此时是没有办法保证各个节点的数据一定是一致的,这一点用户要注意。实际的开发中就要开发者根据实际场景来做取舍了,看更关注一致性还是可用性。

为了协调 CP(一致性和扩展性),用户可以自己选择是否添加 obsever 以及添加个数,observer 是 3.3.0 以后版本新增角色,它不会参加选举和投票过程,目的就是提高集群扩展性。因为 follower 的数量不能过多,follower 需要参加选举和投票,过多的话选举的收敛速度会非常慢,写数据时的投票过程也会很久。observer 的增加可以提高可用性和扩展性,集群可接受 client 请求的点多了,可用性自然会提高,但是一致性的问题依然存在,这时又回到了上面 CA 的取舍问题上。

ZooKeeper的CAP一般实践

  1. zookeeper 本身是集群,作用和目的就是为了高可用——即 leader 挂了,自动选举新的 leader。

  2. 但是 leader 节点只有一个,并且对外提供服务的也只有这一个 Leader 节点,所以很明显不是高可用,因为 leader 挂了之后,选举有时间差几十秒,这段时间差之内就是不可用!

  3. zookeeper 不是高可用,而是数据一致性和集群,即 CP。

    即任何时刻对 ZooKeeper 的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性。但是它不能保证每次服务请求的可用性,也就是在极端环境下,ZooKeeper 可能会丢弃一些请求,消费者程序需要重新请求才能获得结果。ZooKeeper 是分布式协调服务,它的职责是保证数据在其管辖下的所有服务之间保持同步、一致。


ZAB 协议


介绍

ZAB(ZooKeeper Atomic Broadcast 原子广播) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。

ZAB 协议两种基本的模式:崩溃恢复和消息广播

ZAB 协议包括两种基本的模式,分别是 崩溃恢复和消息广播。当整个服务框架在启动过程中,或是当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB 协议就会进人恢复模式并选举产生新的 Leader 服务器。当选举产生了新的 Leader 服务器,同时集群中已经有过半的机器与该 Leader 服务器完成了状态同步之后,ZAB 协议就会退出恢复模式。其中,所谓的状态同步是指数据同步,用来保证集群中存在过半的机器能够和 Leader 服务器的数据状态保持一致

当集群中已经有过半的 Follower 服务器完成了和 Leader 服务器的状态同步,那么整个服务框架就可以进人消息广播模式了。 当一台同样遵守 ZAB 协议的服务器启动后加人到集群中时,如果此时集群中已经存在一个 Leader 服务器在负责进行消息广播,那么新加人的服务器就会自觉地进人数据恢复模式:找到 Leader 所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。正如上文介绍中所说的,ZooKeeper 设计成只允许唯一的一个 Leader 服务器来进行事务请求的处理。Leader 服务器在接收到客户端的事务请求后,会生成对应的事务提案并发起一轮广播协议;而如果集群中的其他机器接收到客户端的事务请求,那么这些非 Leader 服务器会首先将这个事务请求转发给 Leader 服务器。


ZooKeeper 特点


  • 顺序一致性: 从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。
  • 原子性: 所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。
  • 单一系统映像 : 无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的。
  • 可靠性: 一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖。

Zookeeper 在大数据系统中的常见应用


HDFS/YARN

  • HA 机制 (分布式锁的应用):Master 挂掉之后迅速切换到 slave 节点。

Hbase

  • HA 机制 :类似 HDFS/YARN。
  • 配置管理 :client 需要读写 hbase 的数据首先都是连到 ZK 读取 root 表,获得 meta 表所在的 region,最后找到数据所在位置。
  • 任务发布:regionserver 挂了一台,master 需要重新分配 region,会把任务放在 zookeeper 等 regionserver 来获取

Kafka

  • 配置管理:broker 会在 zookeeper 注册并保持相关的元数据(topic,partition 信息等)更新
  • 任务分配:给 topic 分配 partitions 和 replication

Zookeeper 有哪些操作特性


数据结构

ZooKeeper 命名空间中的 Znode,兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。 每个 Znode 由 3 部分组成:

  • stat 状态信息:描述该 Znode 的版本, 权限等信息
  • data:与该 Znode 关联的数据 (配置文件信息、状态信息、汇集位置),数据大小至多 1M
  • children:该 Znode 下的子节点

ZooKeeper 中的每个节点存储的数据要被原子性的操作。也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的 ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。

watch 机制

ZooKeeper 可以为所有的读操作设置 watch,包括:exists()、getChildren() 及 getData()。当节点状态发生改变时 (Znode 的增、删、改) 将会触发 watch 所对应的操作。当 watch 被触发时,ZooKeeper 将会向客户端发送且仅发送一条通知,因为 watch 只能被触发一次,这样可以减少网络流量。

  • 数据 watch(data watches):getData 和 exists 负责设置数据 watch
  • 孩子 watch(child watches):getChildren 负责设置孩子 watch

节点类型

ZooKeeper 中的节点有两种,分别为临时节点和永久节点 (还可再分为有序无序)。节点的类型在创建时即被确定,并且不能改变。

  • 临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话 (Session) 结束,临时节点将被自动删除,当然可以也可以手动删除。虽然每个临时的 Znode 都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。另外,ZooKeeper 的临时节点不允许拥有子节点。(分布式队列)
  • 永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。

Zookeeper如何实现原理


HA 机制

  • 创建两个或多个有序临时节点,永远把最小值当做 master
  • 创建临时节点的为 master,多个 slave 会 watch 这个节点

配置管理

存储集群元数据提供给 client 使用,体现在比如需要对 HBase 和 Kafka 操作时,都会直接连到 zookeeper,zookeeper 记录了数据存储的位置,存活的节点等元数据信息。

任务发布

Master 要监视 / works 和 / tasks 两个永久节点,以便能感知到由哪些 slave 当前可用,当前有新任务需要分配。 分配过程:在 / assign 下创建当前可用的 workA,找到需要分配的 taskA,创建 / assign/workA/taskA

0%