前提:已经对Zookeeper和Eureka的架构特点有所了解, 对分布式中基本理论CAP和BASE了解
两者都可以作为服务注册中心使用,即都可以用于服务发现 (服务治理),所以比较也是从服务发现的角度去比较
Zookeeper保证CP
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。
Eureka保证AP
Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
因此, Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。
zookeeper保证数据一致性
zookeeper时分布式的协调服务,职责是保证数据(注:配置数据,状态数据)在其管辖下的所有服务之间保持同步、一致。所以就不难理解为什么ZooKeeper被设计成CP而不是AP特性的了。
作为ZooKeeper的核心实现算法Zab,就是解决了分布式系统下数据如何在多个服务之间保持同步问题的。
Eureka保证服务能被发现
对于Service发现服务来说,就算是返回了包含不实的信息的结果也比什么都不返回要好;再者,对于Service发现服务而言,宁可返回某服务5分钟之前在哪几个服务器上可用的信息,也不能因为暂时的网络故障而找不到可用的服务器,而不返回任何结果。所以说,用ZooKeeper来做Service发现服务是肯定错误的,如果你这么用就惨了!
1)Eureka集群节点的平等性,无需因leader选取而中断对外提供服务
在Eureka平台中,如果某台服务器宕机,Eureka不会有类似于ZooKeeper的选举leader的过程;客户端请求会自动切换到新的Eureka节点;当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中;而对于它来说,所有要做的无非是同步一些新的服务注册信息而已。所以,再也不用担心有“掉队”的服务器恢复以后,会从Eureka服务器集群中剔除出去的风险了。Eureka甚至被设计用来应付范围更广的网络分割故障,并实现“0”宕机维护需求(多个zookeeper之间网络出现问题,造成出现多个leader,发生脑裂)。当网络分割故障发生时,每个Eureka节点,会持续的对外提供服务(注:ZooKeeper不会):接收新的服务注册同时将它们提供给下游的服务发现请求。这样一来,就可以实现在同一个子网中(same side of partition),新发布的服务仍然可以被发现与访问。
2)Eureak的自我保护机制
正常配置下,Eureka内置了心跳服务,用于剔除一些“濒死”的服务器;但是当网络分割故障发生时,这也是非常危险的;因为,那些因为网络问题(注:心跳慢被剔除了)而被剔除出去的服务器本身是很”健康“的,只是因为网络分割故障把Eureka集群分割成了独立的子网而不能互访而已。
幸运的是,Netflix考虑到了这个缺陷。如果Eureka服务节点在短时间里丢失了大量的心跳连接(如果在15分钟内超过85%的节点都没有正常的心跳),那么这个Eureka节点会进入”自我保护模式“,同时保留那些“心跳死亡“的服务注册信息不过期。此时,这个Eureka节点对于新的服务还能提供注册服务,对于”死亡“的仍然保留,以防还有客户端向其发起请求。当网络故障恢复后,这个Eureka节点会退出”自我保护模式“。所以Eureka的哲学是,同时保留”好数据“与”坏数据“总比丢掉任何”好数据“要更好,所以这种模式在实践中非常有效。
3)Eureka客户端的缓存功能
Eureka还有客户端缓存功能,所以即便Eureka集群中所有节点都失效,或者发生网络分割故障导致客户端不能访问任何一台Eureka服务器,Eureka服务的消费者仍然可以通过Eureka客户端缓存来获取现有的服务注册信息。甚至最极端的环境下,所有正常的Eureka节点都不对请求产生响应,也没有更好的服务器解决方案来解决这种问题时,得益于Eureka的客户端缓存技术,消费者服务仍然可以通过Eureka客户端查询与获取注册服务信息,这点很重要。
4)Eureka的构架保证了它能够成为Service发现服务
Eureka就是为发现服务所设计的,它有独立的客户端程序库,同时提供心跳服务、服务健康监测、自动发布服务与自动刷新缓存的功能。
5)维护Eureka服务器也非常的简单
比如,切换一个节点只需要在现有EIP下移除一个现有的节点然后添加一个新的就行。Eureka提供了一个web-based的图形化的运维界面,在这个界面中可以查看Eureka所管理的注册服务的运行状态信息:是否健康,运行日志等。Eureka甚至提供了Restful-API接口,方便第三方程序集成Eureka的功能。
1)Leader节点的选取过程中断对外提供服务
ZooKeeper的选举leader的过程会中断对外提供服务,另外,在ZooKeeper中,如果在同一个网络分区(partition)的节点数(nodes)数达不到ZooKeeper选取Leader节点的“法定人数”时,它们就会从ZooKeeper中断开,当然同时也就不能提供Service发现服务了。
2)ZooKeeper下服务消费者加缓存设计不合理
为ZooKeeper加上缓存的做法的目的是为了让ZooKeeper变得更加可靠(available),但是,ZooKeeper设计的本意是保持节点的数据一致,也就是CP。所以,这样一来,你可能既得不到一个数据一致的(CP)也得不到一个高可用的(AP)的Service发现服务了;因为这相当于你在一个已有的CP系统上强制栓了一个AP的系统,这在本质上就行不通的!一个Service发现服务应该从一开始就被设计成高可用的才行!
3)zookeeper的CP的设计原则
ZooKeeper设计的本意是保持节点的数据一致,也就是CP
4)设置与维护ZooKeeper服务就非常的困难
这些错误不仅存在与客户端而且还存在于ZooKeeper服务器本身。那些看似简单的操作,如:正确的重建观察者(reestablishing watcher)、客户端Session与异常的处理与在ZK窗口中管理内存都是非常容易导致ZooKeeper出错的。同时,我们确实也遇到过ZooKeeper的一些经典bug:ZooKeeper-1159 与ZooKeeper-1576;我们甚至在生产环境中遇到过ZooKeeper选举Leader节点失败的情况。这些问题之所以会出现,在于ZooKeeper需要管理与保障所管辖服务群的Session与网络连接资源(注:这些资源的管理在分布式系统环境下是极其困难的)
首先需要明白,根据zookeeper的架构特性,众多开发者利用其提供的一系列API接口(或者称为原语集),摸索出来的典型使用方法。可以被用来解决不同的问题,比如 1.命名服务 2.配置管理 3.集群管理 4.分布式锁 5.队列管理 等,当然可以作为服务发现来使用(但是不推荐用作服务发现)(可能还会被发现其他使用zookeeper的奇淫技巧?)
所以在说到两者的使用场景,就不能单纯的从作为服务注册中心的角度考虑是使用Eureka还是zookeeper。
问题: 淘宝的分布式系统在面对双十一业务场景时,选择 CP 还是 AP 呢?
因为是分布式系统, 所有必须有P(分区容错性) ,所有实际就是先保证可用性(A)(服务器不能瘫痪),还是必须保证数据一致(C), 服务器瘫痪,宕机都是次要的?
毫无疑问,肯定选择是AP,先保证 服务器的正常运行,再过了双十一高峰,再核对数据,实现数据一致性。
zookeeper的使用场景:
https://juejin.im/post/5db059046fb9a0204875e6c7
1、leader选举失败的情况:
一个集群有3台机器,挂了一台后的影响是什么?挂了两台呢?
挂了一台:挂了一台后就是收不到其中一台的投票,但是有两台可以参与投票,按照上面的逻辑,它们开始都投给自己,后来按照选举的原则,两个人都投票给其中一个,那么就有一个节点获得的票等于2,2 > (3/2)=1 的,超过了半数,这个时候是能选出leader的。
挂了两台: 挂了两台后,怎么弄也只能获得一张票, 1 不大于 (3/2)=1的,这样就无法选出一个leader了。
2、ZAB算法:
ZAB(ZooKeeper Atomic Broadcast ) 全称为:原子消息广播协议;ZAB可以说是在Paxos算法基础上进行了扩展改造而来的,ZAB协议设计了支持崩溃恢复,ZooKeeper使用单一主进程Leader用于处理客户端所有事务请求,采用ZAB协议将服务器数状态以事务形式广播到所有Follower上;由于事务间可能存在着依赖关系,ZAB协议保证Leader广播的变更序列被顺序的处理,:一个状态被处理那么它所依赖的状态也已经提前被处理;ZAB协议支持的崩溃恢复可以保证在Leader进程崩溃的时候可以重新选出Leader并且保证数据的完整性;