深入ZooKeeper——ZooKeeper的概念和基础

由于Kafka和Duboo都需要在ZooKeeper的基础上运行,所以我们先学习ZooKeeper。

ZooKeeper改变了什么

ZooKeeper的设计更专注于任务协作,并不提供任何锁的接口或通用存储数据接口。同时,ZooKeeper没有给开发人员强加任何特殊的同步原语,使用起来非常灵活。
整个ZooKeeper的服务器集群管理着应用协作的关键数据。ZooKeeper不适合用作海量数据存储。对于需要存储海量的应用数据的情况,我们有很多备选方案,比如说数据库和分布式文件系统等。
ZooKeeper中实现了一组核心操作,通过这些可以实现很多常见分布式应用的任务。你知道有多少应用服务采用主节点方式或进程响应跟踪方式?虽然ZooKeeper并没有为你实现这些任务,也没有为应用实现主节点选举,或者进程存活与否的跟踪的功能,但是,ZooKeeper提供了实现这些任务的工具,对于实现什么样的协同任务,由开发人员自己决定。

分布式定义
分布式系统是同时跨越多个物理主机,独立运行的多个软件组件所组成的系统。
我们采用分布式去设计系统有很多原因,分布式系统能够利用多处理器的运算能力来运行组件,比如并行复制任务。一个系统也许由于战略原因,需要分布在不同地点,比如一个应用由多个不同地点的服务器提供服务。

分布式系统中的进程通信有两种选择:直接通过网络进行信息交换或读写某些共享存储

ZooKeeper使用共享存储模型来实现应用间的协作和同步原语。

在真实的系统中,我们需要特别注意以下问题:

  • 消息延迟。比如网络拥堵。
  • 处理器性能。比如操作系统的调度和超载,这个造成的结果是处理器性能下降,最终导致消息延迟。
  • 时钟偏移。比如确定某一时间系统中发生了哪些事件,由于处理器时钟不可靠而带来的错误决策。

关于这些问题的一个重要结果是,在实际情况中,我们很难判断一个进程是崩溃了还是某些因素导致了延时。没有收到一个进程发送的消息,可能是该进程已经崩溃,或是最新消息发生了网络延迟,或是其他情况导致进程延迟,或者是进程时钟发生了偏移。我们无法确定一个被称为异步(asynchronous)的系统中的这些区别。

ZooKeeper的精确设计简化了这些问题的处理,ZooKeeper并不是完全消除这些问题,而是将这些问题在应用服务层面上完全透明化,使得这些问题更容易处理。

主从系统

在这里插入图片描述
一般在这种架构中,主节点进程负责跟踪从节点状态和任务的有效性,并分配任务到从节点。对ZooKeeper来说,这个架构风格具有代表性,阐述了大多数流行的任务,如选举主节点跟踪有效的从节点维护应用元数据
要实现主-从模式的系统,我们必须解决以下三个关键问题:

  • 主节点崩溃
    如果主节点发送错误并失效,系统将无法分配新的任务或重新分配已失败的任务。
  • 从节点崩溃
    如果从节点崩溃,已分配的任务将无法完成。
  • 通信故障
    如果主节点和从节点之间无法进行信息交换,从节点将无法得知新任务分配给它。

主节点失效
主节点失效时,我们需要有一个备份主节点(backup master)。当主要主节点(primary master)崩溃时,备份主节点接管主要主节点的角色,进行故障转移,然而,这并不是简单开始处理进入主节点的请求。新的主要主节点需要能够恢复到旧的主要主节点崩溃时的状态。对于主节点状态的可恢复性,我们不能依靠从已经崩溃的主节点来获取这些信息,而需要从其他地方获取,也就是通过ZooKeeper来获取

状态恢复并不是唯一的重要问题。假如主节点有效,备份主节点却认为主节点已经崩溃。这种错误的假设可能发生在以下情况,例如主节点负载很高,导致消息任意延迟。备份主节点将会接管成为主节点的角色,执行所有必需的程序,最终可能以主节点的角色开始执行,成为第二个主要主节点。。更糟的是,如果一些从节点无法与主要主节点通信,如由于网络分区(network partition)错误导致,这些从节点可能会停止与主要主节点的通信,而与第二个主要主节点建立主-从关系。

我们一般称之为脑裂(split-brain):系统中两个或者多个部分开始独立工作,导致整体行为不一致性。我们需要找出一种方法来处理主节点失效的情况,关键是我们需要避免发生脑裂的情况

从节点失效
客户端向主节点提交任务,之后主节点将任务派发到有效的从节点中。从节点接收到派发的任务,执行完这些任务后会向主节点报告执行状态。主节点下一步会将执行结果通知给客户端。

如果从节点崩溃了,所有已派发给这个从节点且尚未完成的任务需要重新派发。其中首要需求是让主节点具有检测从节点的崩溃的能力。主节点必须能够检测到从节点的崩溃,并确定哪些从节点是否有效以便派发崩溃节点的任务。一个从节点崩溃时,从节点也许执行了部分任务,也许全部执行完,但没有报告结果。如果整个运算过程产生了其他作用,我们还有必要执行某些恢复过程来清除之前的状态。

通信故障
如果一个从节点与主节点的网络连接断开,比如网络分区(network partition)导致,重新分配一个任务可能会导致两个从节点执行相同的任务。如果一个任务允许多次执行,我们在进行任务再分配时可以不用验证第一个从节点是否完成了该任务。如果一个任务不允许,那么我们的应用需要适应多个从节点执行相同任务的可能性。

对任务加锁并不能保证一个任务执行多次,比如以下场景中描述的
情况:
1.主节点M1派发任务T1给从节点W1。
2.W1为任务T1获取锁,执行任务,然后释放锁。
3.M1怀疑W1已经崩溃,所以再次派发任务T1给从节点W2。
4.W2为任务T1获取锁,执行任务,然后释放锁。

通信故障导致的另一个重要问题是对锁等同步原语的影响。
因为节点可能崩溃,而系统也可能网络分区(network partition),锁机制也会阻止任务的继续执行。因此ZooKeeper也需要实现处理这些情况的机制。

首先,客户端可以告诉ZooKeeper某些数据的状态是临时状态(ephemeral)。
其次,同时ZooKeeper需要客户端定时发送是否存活的。
通知,如果一个客户端未能及时发送通知,那么所有从属于这个客户端的临时状态的数据将全部被删除。

任务总结

根据之前描述的这些,我们可以得到以下主-从架构的需求:

  • 主节点选举 :使得主节点可以给从节点分配任务。
  • 崩溃检测:主节点必须具有检测从节点崩溃或失去连接的能力。
  • 组成员关系管理:主节点必须具有知道哪一个从节点可以执行任务的能力。
  • 元数据管理:主节点和从节点必须具有通过某种可靠的方式来保存分配状态和执行状态的能力。

分布式协作的难点

在独立主机上运行的应用与分布式应用发生的故障存在显著的区别:
如果是独立主机上运行多个进程,一个进程执行的失败,其他进程可以通过操作系统获得这个故障,操作系统提供了健壮的多进程消息通信的保障。
在分布式环境中这一切发生了改变。如果一个主机或进程发生故障,其他主机继续运行,并会接管发生故障的进程,为了能够处理故障进程,这些仍在运行的进程必须能够检测到这个故障,无论是消息丢失或发生了时间偏移。
不得不指出,完美的解决方案是不存在的

猜你喜欢

转载自blog.csdn.net/No_Game_No_Life_/article/details/84062554