为何不该该使用Zookeeper作服务发现?(转载)

【编者的话】本文做者经过ZooKeeper与Eureka做为 Service发现服务 (注:WebServices体系中的UDDI就是个发现服务)的优劣对比,分享了Knewton在云计算平台部署服务的经验。本文虽然略显偏激,可是看得出Knewton在云平台方面是很是有经验的,这篇文章从实践角度出发分别从云平台特色、CAP原理以及运维三个方面对比了ZooKeeper与Eureka两个系统做为发布服务的优劣,并提出了在云平台构建发现服务的方法论。

背景不少公司选择使用

ZooKeeper 做为Service发现服务(Service Discovery),可是在构建 Knewton (Knewton是一个提供个性化教育平台的公司、学校和出版商能够经过Knewton平台为学生提供自适应的学习材料)平台时,咱们发现这是个根本性的错误。在这边文章中,咱们将用咱们在实践中遇到的问题来讲明,为何使用ZooKeeper作Service发现服务是个错误。

请留意服务部署环境让咱们从头开始梳理。咱们在部署服务的时候,应该首先考虑服务部署的平台(平台环境),而后才能考虑平台上跑的软件系统或者如何在选定的平台上本身构建一套系统。例如,对于云部署平台来讲,平台在硬件层面的伸缩(注:做者应该指的是系统的冗余性设计,即系统遇到单点失效问题,可以快速切换到其余节点完成任务)与如何应对网络故障是首先要考虑的。当你的服务运行在大量服务器构建的集群之上时(注:原话为大量可替换设备),则确定会出现单点故障的问题。对于knewton来讲,咱们虽然是部署在AWS上的,可是在过往的运维中,咱们也遇到过形形色色的故障;因此,你应该把系统设计成“故障开放型”(expecting failure)的。其实有不少一样使用AWS的

公司 跟咱们遇到了(同时有不少 是介绍这方面的)类似的问题。你必须可以提早预料到平台可能会出现的问题如:意外故障(注:原文为box failure,只能意会到做者指的是意外弹出的错误提示框),高延迟与 网络分割问题 (注:原文为network partitions。意思是当网络交换机出故障会致使不一样子网间通信中断)——同时咱们要能构建足够弹性的系统来应对它们的发生。

永远不要指望你部署服务的平台跟其余人是同样的!固然,若是你在独自运维一个数据中心,你可能会花不少时间与钱来避免硬件故障与网络分割问题,这是另外一种状况了;可是在云计算平台中,如AWS,会产生不一样的问题以及不一样的解决方式。当你实际使用时你就会明白,可是,你最好提早应对它们(注:指的是上一节说的意外故障、高延迟与网络分割问题)的发生。

ZooKeeper做为发现服务的问题ZooKeeper(注:ZooKeeper是著名Hadoop的一个子项目,旨在解决大规模分布式应用场景下,服务协调同步(Coordinate Service)的问题;它能够为同在一个分布式系统中的其余服务提供:统一命名服务、配置管理、分布式锁服务、集群管理等功能)是个伟大的开源项目,它很成熟,有至关大的社区来支持它的发展,并且在生产环境获得了普遍的使用;可是用它来作Service发现服务解决方案则是个错误。



在分布式系统领域有个著名的 CAP定理 (C-数据一致性;A-服务可用性;P-服务对网络分区故障的容错性,这三个特性在任何分布式系统中不能同时知足,最多同时知足两个);ZooKeeper是个CP的,即任什么时候刻对ZooKeeper的访问请求能获得一致的数据结果,同时系统对网络分割具有容错性;可是它不能保证每次服务请求的可用性(注:也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序须要从新请求才能得到结果)。可是别忘了,ZooKeeper是分布式协调服务,它的职责是保证数据(注:配置数据,状态数据)在其管辖下的全部服务之间保持同步、一致;因此就不难理解为何ZooKeeper被设计成CP而不是AP特性的了,若是是AP的,那么将会带来恐怖的后果(注:ZooKeeper就像交叉路口的信号灯同样,你能想象在交通要道忽然信号灯失灵的状况吗?)。并且,做为ZooKeeper的核心实现算法 Zab ,就是解决了分布式系统下数据如何在多个服务之间保持同步问题的。

做为一个分布式协同服务,ZooKeeper很是好,可是对于Service发现服务来讲就不合适了;由于对于Service发现服务来讲就算是返回了包含不实的信息的结果也比什么都不返回要好;再者,对于Service发现服务而言,宁肯返回某服务5分钟以前在哪几个服务器上可用的信息,也不能由于暂时的网络故障而找不到可用的服务器,而不返回任何结果。因此说,用ZooKeeper来作Service发现服务是确定错误的,若是你这么用就惨了!

并且更况且,若是被用做Service发现服务,ZooKeeper自己并无正确的处理网络分割的问题;而在云端,网络分割问题跟其余类型的故障同样的确会发生;因此最好提早对这个问题作好100%的准备。就像 Jepsen 在ZooKeeper网站上发布的博客中所说:在ZooKeeper中,若是在同一个网络分区(partition)的节点数(nodes)数达不到ZooKeeper选取Leader节点的“法定人数”时,它们就会从ZooKeeper中断开,固然同时也就不能提供Service发现服务了。

若是给ZooKeeper加上客户端缓存(注:给ZooKeeper节点配上本地缓存)或者其余相似技术的话能够缓解ZooKeeper由于网络故障形成节点同步信息错误的问题。 Pinterest Airbnb 公司就使用了这个方法来防止ZooKeeper故障发生。这种方式能够从表面上解决这个问题,具体地说,当部分或者全部节点跟ZooKeeper断开的状况下,每一个节点还能够从本地缓存中获取到数据;可是,即使如此,ZooKeeper下全部节点不可能保证任什么时候候都能缓存全部的服务注册信息。若是ZooKeeper下全部节点都断开了,或者集群中出现了网络分割的故障(注:因为交换机故障致使交换机底下的子网间不能互访);那么ZooKeeper会将它们都从本身管理范围中剔除出去,外界就不能访问到这些节点了,即使这些节点自己是“健康”的,能够正常提供服务的;因此致使到达这些节点的服务请求被丢失了。(注:这也是为何ZooKeeper不知足CAP中A的缘由)

更深层次的缘由是,ZooKeeper是按照CP原则构建的,也就是说它能保证每一个节点的数据保持一致,而为ZooKeeper加上缓存的作法的目的是为了让ZooKeeper变得更加可靠(available);可是,ZooKeeper设计的本意是保持节点的数据一致,也就是CP。因此,这样一来,你可能既得不到一个数据一致的(CP)也得不到一个高可用的(AP)的Service发现服务了;由于,这至关于你在一个已有的CP系统上强制栓了一个AP的系统,这在本质上就行不通的!一个Service发现服务应该从一开始就被设计成高可用的才行!

若是抛开CAP原理无论,正确的设置与维护ZooKeeper服务就很是的困难;错误会 常常发生 ,致使不少工程被创建只是为了减轻维护ZooKeeper的难度。这些错误不只存在与客户端并且还存在于ZooKeeper服务器自己。Knewton平台不少故障就是因为ZooKeeper使用不当而致使的。那些看似简单的操做,如:正确的重建观察者(reestablishing watcher)、客户端Session与异常的处理与在ZK窗口中管理内存都是很是容易致使ZooKeeper出错的。同时,咱们确实也遇到过ZooKeeper的一些经典bug: ZooKeeper-1159   ZooKeeper-1576 ;咱们甚至在生产环境中遇到过ZooKeeper选举Leader节点失败的状况。这些问题之因此会出现,在于ZooKeeper须要管理与保障所管辖服务群的Session与网络链接资源(注:这些资源的管理在分布式系统环境下是极其困难的);可是它不负责管理服务的发现,因此使用ZooKeeper当Service发现服务得不偿失。

作出正确的选择:Eureka的成功咱们把Service发现服务从ZooKeeper切换到了Eureka平台,它是一个开源的服务发现解决方案,由Netflix公司开发。(注:Eureka由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用做服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、做为轮询负载均衡器,并提供服务的故障切换支持。)Eureka一开始就被设计成高可用与可伸缩的Service发现服务,这两个特色也是Netflix公司开发全部平台的两个特点。(

他们都在讨论Eureka )。自从切换工做开始到如今,咱们实现了在生产环境中全部依赖于Eureka的产品没有下线维护的记录。咱们也被告知过,在云平台作服务迁移注定要遇到失败;可是咱们从这个例子中获得的经验是,一个优秀的Service发现服务在其中发挥了相当重要的做用!

首先,在Eureka平台中,若是某台服务器宕机,Eureka不会有相似于ZooKeeper的选举leader的过程;客户端请求会自动切换到新的Eureka节点;当宕机的服务器从新恢复后,Eureka会再次将其归入到服务器集群管理之中;而对于它来讲,全部要作的无非是同步一些新的服务注册信息而已。因此,不再用担忧有“掉队”的服务器恢复之后,会从Eureka服务器集群中剔除出去的风险了。Eureka甚至被设计用来应付范围更广的网络分割故障,并实现“0”宕机维护需求。当网络分割故障发生时,每一个Eureka节点,会持续的对外提供服务(注:ZooKeeper不会):接收新的服务注册同时将它们提供给下游的服务发现请求。这样一来,就能够实如今同一个子网中(same side of partition),新发布的服务仍然能够被发现与访问。

可是,Eureka作到的不止这些。正常配置下,Eureka内置了心跳服务,用于淘汰一些“濒死”的服务器;若是在Eureka中注册的服务,它的“心跳”变得迟缓时,Eureka会将其整个剔除出管理范围(这点有点像ZooKeeper的作法)。这是个很好的功能,可是当网络分割故障发生时,这也是很是危险的;由于,那些由于网络问题(注:心跳慢被剔除了)而被剔除出去的服务器自己是很”健康“的,只是由于网络分割故障把Eureka集群分割成了独立的子网而不能互访而已。

幸运的是,Netflix考虑到了这个缺陷。若是Eureka服务节点在短期里丢失了大量的心跳链接(注:可能发生了网络故障),那么这个Eureka节点会进入”自我保护模式“,同时保留那些“心跳死亡“的服务注册信息不过时。此时,这个Eureka节点对于新的服务还能提供注册服务,对于”死亡“的仍然保留,以防还有客户端向其发起请求。当网络故障恢复后,这个Eureka节点会退出”自我保护模式“。因此Eureka的哲学是,同时保留”好数据“与”坏数据“总比丢掉任何”好数据“要更好,因此这种模式在实践中很是有效。

最后,Eureka还有客户端缓存功能(注:Eureka分为客户端程序与服务器端程序两个部分,客户端程序负责向外提供注册与发现服务接口)。因此即使Eureka集群中全部节点都失效,或者发生网络分割故障致使客户端不能访问任何一台Eureka服务器;Eureka服务的消费者仍然能够经过Eureka客户端缓存来获取现有的服务注册信息。甚至最极端的环境下,全部正常的Eureka节点都不对请求产生相应,也没有更好的服务器解决方案来解决这种问题时;得益于Eureka的客户端缓存技术,消费者服务仍然能够经过Eureka客户端查询与获取注册服务信息,这点很重要。

Eureka的构架保证了它可以成为Service发现服务。它相对与ZooKeeper来讲剔除了Leader节点的选取或者事务日志机制,这样作有利于减小使用者维护的难度也保证了Eureka的在运行时的健壮性。并且Eureka就是为发现服务所设计的,它有独立的客户端程序库,同时提供心跳服务、服务健康监测、自动发布服务与自动刷新缓存的功能。可是,若是使用ZooKeeper你必须本身来实现这些功能。Eureka的全部库都是开源的,全部人都能看到与使用这些源代码,这比那些只有一两我的能看或者维护的客户端库要好。

维护Eureka服务器也很是的简单,好比,切换一个节点只须要在现有EIP下移除一个现有的节点而后添加一个新的就行。Eureka提供了一个web-based的图形化的运维界面,在这个界面中能够查看Eureka所管理的注册服务的运行状态信息:是否健康,运行日志等。Eureka甚至提供了Restful-API接口,方便第三方程序集成Eureka的功能。

结论关于Service发现服务经过本文咱们想说明两点:一、留意服务运行的硬件平台;二、时刻关注你要解决的问题,而后决定使用什么平台。Knewton就是从这两个方面考虑使用Eureka替换ZooKeeper来做为service发现服务的。云部署平台是充满不可靠性的,Eureka能够应对这些缺陷;同时Service发现服务必须同时具有高可靠性与高弹性,Eureke就是咱们想要的!


相关文章
相关标签/搜索