zookeeper

[ZooKeeper之一] ZooKeeper简介

2020-04-19  本文已影响0人  小胡_鸭

  相对于开发在一台计算机上运行的单个程序,如何让一个应用中多个独立的程序协同工作是一件非常困难的事。程序员需要花费大量的精力聚焦在如何协同多个程序上,往往导致不能更好地思考和实现应用逻辑,或者对协同逻辑关注不够,最后开发出一个简单脆弱的主协调器,导致不可靠的单一失效点。

  ZooKeeper 是一个用于分布式系统协调的很好的工具,设计理念保证了其健壮性,API使用简单,支持多种语言的客户端库,使得开发人员可以更多专注应用本身的逻辑,而不是协同工作上。另外 ZooKeeper 的服务组件运行在一组专用服务器智商,保证了高容错性和可扩展性。

一、ZooKeeper 的使命

  说起 ZooKeeper,很多人会脱口而出:注册中心、配置中心。但实际上这只是 ZooKeeper 的为人熟知的应用场景而已,并不能描述其本质,ZooKeeper 的本质是分布式系统协调工具,它具体能做什么可能要依赖开发者的想象力。注册中心、配置中心与 ZooKeeper 的关系,就好像是拧螺丝和螺丝刀的关系,螺丝刀除了拧螺丝,还可以用于各种家电设备的组装和维修,可以用来撬开东西,某种极端情况下用来做武器也未必不可,所以无法详尽地说明它能用来做什么,但应该对其本质有清晰的认识。

  ZooKeeper 常用在分布式系统的协作中。什么是分布式系统?物理上看,有多台服务器组成一个集群;应用上看,是一个由多个子应用共同构成的应用系统。在分布式系统中,经常需要协作多台机器、多个进程、多个子应用来完成任务。

  协作通常意味着需要多个进程共同处理某些事情,一些进程采取某些行动使得其他进程可以继续工作。比如,在经典的主-从(master-worker)模式中,主节点负责任务分配调度,从节点负责接收主节点分配的任务,当从节点空闲时,会通知主节点它可以接受任务,于是主节点分配任务给从节点。

协作

  协作也可以是竞争,比如有一项任务可以在多个节点上执行,但是只能被执行一次,为了防止重复执行,就需要竞争抢锁;或者主从模式中,为了避免主节点单点故障,会有多个备用主节点,当主节点宕机或者无法连接时,备用节点会选举出新的主节点,而选举的过程需要实现互斥排他锁,也就是分布式锁,而 ZooKeeper 可以轻而易举实现。

竞争



  从本质上看,分布式系统多进程协同跟单一计算机上多进程协同区别不大。在多线程环境下有用的同步原语在分布式系统下同样有效。重要的区别在于,分布式系统中的不同计算机之间不共享除了网络之外的其他信息。虽然许多消息传递算法可以实现同步原语,但是使用一个提供某种有序共享的组件往往更加简便,这就是 ZooKeeper 所采用的方式。

  ZooKeeper 本身不实现同步原语,但其共享存储可以轻而易举实现分布式锁,进而实现更多功能。更重要的是共享存储中存储的元数据是一个进程通知其他进程需要做什么的一种常用方式,存储什么数据,如何使用数据取决于开发者,非常灵活。

1、ZooKeeper 跟其他分布式协同组件的区别

  ZooKeeper 之前有很多分布式系统采用分布式锁管理器或分布式数据库来实现协作,而 ZooKeeper 另辟蹊径,不提供任何锁的接口或通用数据存储接口,专注与任务协作,使用灵活,降低分布式协作的难度。

2、ZooKeeper 不适用的场景

  任何技术都有其擅长的领域和弱点,ZooKeeper 不是万能的,只能用于存储服务器集群应用协作的关键数据,不能用于存储大量数据。对于海量数据存储的场景,数据库和分布式文件系统更合适。在使用 ZooKeeper 时,一定要秉持协调数据跟应用数据隔离的原则,因为不同应用在一致性和持久性上有不同的需求。

3、通过 ZooKeeper 构建分布式系统

  分布式系统是同时跨越多个物理主机,独立运行的多个软件组件锁组成的系统。有利于实现 “三高” 目标(高并发、高可用、高扩展),而 ZooKeeper 是独立于分布式系统的一个协调组件,即插即用,可以跨越多个应用共享,简化协作工作,同时协同数据集中存储在 ZooKeeper 服务端,有利于简化生产问题的排查和解决。

  ZooKeeper 有客户端和服务端,都是以进程的方式运行,分布式系统中的应用节点可以认为是客户端,为了保证高可用,ZooKeeper 服务端通常都是一个集群,并且一个集群能为多个不同的分布式应用系统提供应用内和应用间的协同服务。

  分布式系统中的进程通信有两种选择:直接通过网络进行信息交换,或读写某些共享存储。ZooKeeper 使用共享存储模型来实现应用间的协作和同步原语。

二、主-从架构中的系统协同

  在主-从架构中,Master 负责跟踪 Worker 状态和任务有效性,并分配任务给 Worker,而多个Worker 负责执行任务,并在任务执行完处于空闲状态时通知 Master。对于 ZooKeeper 来说,这个架构风格具有代表性。



  为了实现健壮的主-从架构,需要解决三个问题:

1、主节点崩溃

  毫无疑问,主节点在主-从架构中举足轻重,如果崩溃,会导致系统无法分配任务(包括新的任务和需要重新分配的任务)。因此,为了避免单点故障,需要有备用主节点,当主节点崩溃时,接管主节点的角色,快速进行故障转移,通常会有多个备用主节点,它们之间通过竞争来选出新的主节点。

  选出新的主节点之后,首先要做的就是将新的主节点恢复到旧主节点崩溃前的状态,并且不能从旧的主节点来获取这些数据,需要通过 ZooKeeper 来获取,一来是因为旧的主节点可能无法通信,二来是因为旧主节点崩溃后,系统中可能有了一些新的变化需要新的主节点实时获取(比如增加了新的从节点,客户端提交了新的任务等)。

  除了状态转移外,在某些情况下,假如主节点负载过高导致消息延迟过高,会导致备用主节点接管成为主节点,出现多个主节点并存的情况;如果这时还发生网络分区,就会出现部分从节点跟第一个主节点通信,部分从节点跟第二个主节点通信,主从系统一分为二。这种系统中一个或者多个部分开始独立工作,导致整体行为不一致性的问题,称之为“脑裂”。为此,需要找到处理好主节点失效和避免脑裂的办法。

  对于 Zookeeper,采用的是基于Paxos的ZAB协议实现的选举算法,简单地说就是一个节点要成为主节点,必须得到集群中一半以上的节点的认可,这样对于一个集群来说,不会存在同时满足该条件的主节点,从而避免脑裂。

脑裂

2、从节点崩溃

  跟主节点崩溃相比,从节点崩溃的破坏力降低了很多,但依然需要善后,从节点完成任务后,会通知主节点,既是为了返回任务执行结果,也是为了等待分配新的任务(假如分配的任务已经全部完成)。

  因此,当从节点崩溃时,首先主节点需要有检测从节点崩溃的能力,并确定当前有哪些从节点可以派发崩溃节点的任务,然后派发任务。从节点崩溃时,可能已经全部或部分执行了某些任务,如果这些任务是可以被重复执行的,则无需多余的操作,但如果某些任务不可以被重复执行的,则在重新执行之前,必须先回滚掉之前崩溃从节点的全部或部分执行,清理之前的执行状态。

  为了实现对工作节点的动态检测,使用 ZooKeeper 可以采用这样的方案:当一个工作者节点加入集群时,为其创建一个临时节点,当工作者节点宕机、通讯中断或者响应超时时,集群认为该节点已不可用,对应的临时节点会被删除,主节点通过监试工作者临时节点,就能实现对其动态检测。



3、通信故障

  通信故障带来的第一个影响是需要重新派发从节点任务,如上所述。第二个影响是分布式锁可能会阻止任务的执行,比如一个从节点崩溃前持有一个锁L1,崩溃之后由于还没释放锁,所以其他等待锁释放执行任务的其他从节点无法执行任务。

  针对这种情况,从节点应该告诉 ZooKeeper 是临时状态,并且 ZooKeeper 需要从节点定期发送存活通知(或者说心跳检测),如果从节点由于消息延迟或者其他原因导致无法及时通知,所有属于这个从节点的数据将被清除,锁本质上也是一种数据,清理数据的同时也意味着释放了锁。

  对于分布式系统,网络是通讯的生命线,但是不管是内网外网,偶尔还是会出现网络波动、阻塞、分区、中断的情况,所以通信故障是最常见也是最复杂的问题;除了网络的因素,服务器负载过高,导致时延过长,更糟糕的情况,CPU 100%、内存溢出可能导致宕机,这些都可能导致无法正常通信。

  ZooKeeper 采取的策略是:对于服务端集群来说,首先会有一台集群 Leader,管理同步所有 follower 转发给它的事务,并跟跟随者 follower 保持心跳通信,心跳是有一定周期的,意味着服务器的故障时间只要不超过一个周期,它的故障是不会被其他跟它通信的服务器感知到的,即使故障了,只要设定时间内恢复正常,还是可以重新加入到集群中提供服务;对于客户端来说,只要服务端集群还能正常提供服务,就算服务集群中有个别服务器故障,也不会对其造成影响,由于客户端跟服务端通讯前要建立会话,并且会话有一定的超时时间,所以即使由于客户端的问题导致跟服务端的通信故障了,只要在超时时间内能够恢复,就可以继续使用原来的会话。

4、需求总结

  通过前面的分析,可以得到主-从架构的需求如下:

三、分布式协作的难点

  分布式系统总会遇到各种各样的问题,比如崩溃、通信故障等,还有集群中的节点需要定期心跳检测来判断是否存活,如此一来,时钟偏移、节点负载过高甚至操作系统的时间片调度都可能导致节点超时被认为不能正常提供服务,我们无法在一致性(Consistency)、可用性(Avaliability)和分区容错性(Partition-tolerance)上都得到满足,需要适当放松一些要求,比如假设时钟是同步的、牺牲一些分区容错能力等,这有助于建立一个更加务实的分布式系统。

  ZooKeeper 不是银弹,不能解决所有分布式应用中的所有问题,它只是帮助开发者降低处理分布式系统协调问题的成本,事实上没有一个完美的方案,各种问题依然会存在,开发者要有所取舍,将精力聚焦在应用逻辑本身。

上一篇下一篇

猜你喜欢

热点阅读