作为服务注册中心,Eureka 比Zookeeper好在哪里?

  在分布式系统中,有一个很重要的理论就是CAP理论,在CAP理论中,分布式系统只会满足一致性、可用性、分区容错性中的两种,并且由于服务通信可能会失败所以分区容错性都会要求满足,所以导致一致性和可用性只能满足一个。可以看另一篇文章《CAP定理》。

Zookeeper

  Zookeeper保证CP,在任意时刻对Zookeeper的访问都能获得一致的结果。当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟之前的注册信息,但不能接受Zookeeper服务down掉不可用,也就是说,服务注册功能对可用性的要求高于一致性。但是,Zookeeper会出现这样一种情况,当master节点因为网络故障等原因与其他节点失去连接时其他剩余的节点会重新进行leader选举,但问题就在于,leader选举时间太长,30~120s,并且选举期间整个Zookeeper集群都是不可用的,这就导致选举期间基本上注册中心瘫痪。在云部署的环境下,因网络问题使得Zookeeper集群失去master节点是较大概率发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册中心长期不可用是不能容忍的。可以思考双十一。。。

  Zookeeper的劣势,下面几段描述引用原文地址,另外加上自我的理解。

  1)对于service发现服务来说就算是返回了包含不实的信息的结果也比什么不返回较好(可以试想用户发起请求,页面什么响应都没有,即使是错误,我觉得都应该返回)。再者,对于service发现服务而言,宁可返回某服务几分钟之前在哪几个服务器上可用的信息,即使是过时的信息,也不能一味暂时的网络故障导致服务不可用,没有响应结果。所以说,用Zookeeper来做service发现服务是错误的。

  如果被用作service发现服务,Zookeeper本身并没有正确的出来网络分割的问题。而在云端,网络分割问题跟其他类型的故障一样的确会发生,所以最好提前对这个问题做好100%的准备,就像Jeosen在Zookeeper网站上分布的博客中所说:在Zookeeper中,如果在同一个网络分区(partition)的节点数达不到Zookeeper选举leader节点的“法定人数”时,它们就会从Zookeeper中断开,导致就不能提供服务。

  2)Zookeeper下所有节点不可能保证在任何时候都能缓存所以服务的注册信息。如果Zookeeper下所有节点都断开了或者集群中出现了网络分割的故障(由于交换机故障导致交换机底下的子网间不能互访),那么Zookeeper会将它们都从自己管理范围中剔除出去,外界就不能访问到这些节点了,即使这些节点是“健康的”、可以提供正常服务的。所以导致到达这些节点的服务请求被丢失了(这也是Zookeeper不满足CAP中可用性的原因)。

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

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

  这个例子我觉的很有意思:

  一个集群有三台机器,挂了其中一台后影响是什么?

  挂了一台:挂了一台后就是收不到其中一台的投票,但是还有两台能够参与投票,按照上面的逻辑,它们都开始投给自己,后来按照选举leader的原则,两个投票都投给其中一个,那么就有一个节点的投票数是2,大于3/2=1的,超过了半数,这个时候能够选举出leader。

  挂了两台:挂了两台,只剩一台,只能投给自己,1是不可能大于3/2=1的,所以这样就选举不出leader。

Eureka

  Eureka看明白了这一点,因此在设计时就优先保证可用性AP。Eureka各个节点都是平等的,几个节点挂掉不会影响其他正常节点的工作,剩余节点依然可以提供注册和查询服务。而Eureka的客户端再向某个Eureka注册时如果发现连接失败,则会自动切换到其他节点,只要有一台Eureka节点还在,就能保证服务注册可用,只不过查到的信息可能不是最新的(不保证一致性)。除此之外,Eureka还存在一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为注册中心和客户端出现了网络故障,此时会出现以下几种情况:

  1、Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务

  2、Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点(保证当前节点可用)

  3、网络稳定时,当前实例新的注册信息会被同步到其他节点

  因此,Eureka可用很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样使的服务注册全部瘫痪。