服务注册发现consul之三:服务发现比较:Consul vs Zookeeper vs Etcd vs Eureka
这里就平时经常用到的服务发现的产品进行下特性的对比,首先看下结论:
Feature | Consul | zookeeper | etcd | euerka |
---|---|---|---|---|
服务健康检查 | 服务状态,内存,硬盘等 | (弱)长连接,keepalive | 连接心跳 | 可配支持 |
多数据中心 | 支持 | — | — | — |
kv存储服务 | 支持 | 支持 | 支持 | — |
一致性算法 | raft | paxos | raft | — |
cap | cp | cp | cp | ap |
使用接口(多语言能力) | 支持http和dns | 客户端 | http/grpc | http(sidecar) |
watch支持 | 全量/支持long polling | 支持 | 支持 long polling | 支持 long polling/大部分增量 |
自身监控 | metrics | — | metrics | metrics |
安全 | acl /https | acl | https支持(弱) | — |
spring cloud集成 | 已支持 | 已支持 | 已支持 | 已支持 |
线程读 | 支持 | 不支持 | 支持 | |
多版本控制 | 支持 | 不支持 | 不支持 | |
事务 | 支持 | 支持 | 支持 | |
变更通知 | 支持 | 支持 | 支持 | |
HTTP/JSON API | 支持 | 不支持 | 支持 | |
高负载读写性能 | 高 | 低 | 低 | |
成员变更 | 支持 | >3.5.0支持 | 支持 |
Eureka是一个服务发现工具。该体系结构主要是客户端/服务器,每个数据中心有一组Eureka服务器,通常每个可用区域一个。通常Eureka的客户使用嵌入式SDK来注册和发现服务。对于非本地集成的客户,使用功能区边框等透过Eureka透明地发现服务。
Eureka提供了一个弱一致的服务视图,使用尽力而为复制。当客户端向服务器注册时,该服务器将尝试复制到其他服务器,但不提供保证。服务注册的生存时间(TTL)较短,要求客户端对服务器心存感激。不健康的服务或节点将停止心跳,导致它们超时并从注册表中删除。发现请求可以路由到任何服务,由于尽力而为的复制,这些服务可能会导致陈旧或丢失数据。这个简化的模型允许简单的群集管理和高可扩展性。
CONSUL提供了一套超级功能,包括更丰富的健康检查,关键/价值存储以及多数据中心意识。Consul需要每个数据中心都有一套服务器,以及每个客户端的代理,类似于使用像Ribbon这样的负载均衡。Consul代理允许大多数应用程序成为Consul不知情者,通过配置文件执行服务注册并通过DNS或负载平衡器sidecars发现。
Consul提供强大的一致性保证,因为服务器使用Raft协议复制状态 。Consul支持丰富的健康检查,包括TCP,HTTP,Nagios / Sensu兼容脚本或基于Eureka的TTL。客户端节点参与基于Gossip的健康检查,该检查分发健康检查工作,而不像集中式心跳检测那样成为可扩展性挑战。发现请求被路由到选举出来的领事领导,这使他们默认情况下强烈一致。允许陈旧读取的客户端使任何服务器都可以处理他们的请求,从而实现像Eureka这样的线性可伸缩性。
Consul强烈的一致性意味着它可以作为领导选举和集群协调的锁定服务。Eureka不提供类似的保证,并且通常需要为需要执行协调或具有更强一致性需求的服务运行ZooKeeper。
Consul提供了支持面向服务的体系结构所需的一系列功能。这包括服务发现,还包括丰富的运行状况检查,锁定,密钥/值,多数据中心联合,事件系统和ACL。Consul和consul-template和envconsul等工具生态系统都试图尽量减少集成所需的应用程序更改,以避免需要通过SDK进行本地集成。Eureka是一个更大的Netflix OSS套件的一部分,该套件预计应用程序相对均匀且紧密集成。因此,Eureka只解决了一小部分问题,希望ZooKeeper等其他工具可以一起使用。
consul、zookeeper、etcd作为服务注册中心的原理
后边这两个工具是通过键值存储来实现服务的注册与发现。
-
ZooKeeper利用临时节点的机制,业务服务启动时创建临时节点,节点在服务就在,节点不存在服务就不存在。
-
etcd利用TTL机制,业务服务启动时创建键值对,定时更新ttl,ttl过期则服务不可用。
ZooKeeper和etcd的键值存储都是强一致性的,也就是说键值对会自动同步到多个节点,只要在某个节点上存在就可以认为对应的业务服务是可用的。
Consul的数据同步也是强一致性的,服务的注册信息会在Server节点之间同步,相比ZK、etcd,consul服务的信息还是持久化保存的,即使服务部署不可用了,仍旧可以查询到这个服务部署。但是业务服务的可用状态是由注册到的Agent来维护的,Agent如果不能正常工作了,则无法确定服务的真实状态,并且Consul是相当稳定了,Agent挂掉的情况下大概率服务器的状态也可能是不好的,此时屏蔽掉此节点上的服务是合理的。Consul也确实是这样设计的,DNS接口会自动屏蔽挂掉节点上的服务,HTTP API也认为挂掉节点上的服务不是passing的。
ZooKeeper与Eureka的区别:
Apache Zookeeper -> CP
与 Eureka 有所不同,Apache Zookeeper
在设计时就紧遵CP原则,即任何时候对 Zookeeper 的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性,但是 Zookeeper
不能保证每次服务请求都是可达的。从 Zookeeper 的实际应用情况来看,在使用 Zookeeper 获取服务列表时,如果此时的
Zookeeper 集群中的 Leader 宕机了,该集群就要进行 Leader 的选举,又或者 Zookeeper
集群中半数以上服务器节点不可用(例如有三个节点,如果节点一检测到节点三挂了
,节点二也检测到节点三挂了,那这个节点才算是真的挂了),那么将无法处理该请求。所以说,Zookeeper 不能保证服务可用性。
当然,在大多数分布式环境中,尤其是涉及到数据存储的场景,数据一致性应该是首先被保证的,这也是
Zookeeper
设计紧遵CP原则的另一个原因。但是对于服务发现来说,情况就不太一样了,针对同一个服务,即使注册中心的不同节点保存的服务提供者信息不尽相同,也并不会造成灾难性的后果。因为对于服务消费者来说,能消费才是最重要的,消费者虽然拿到可能不正确的服务实例信息后尝试消费一下,也要胜过因为无法获取实例信息而不去消费,导致系统异常要好(淘宝的双十一,京东的幺六八就是紧遵AP的最好参照)。
当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30~120s,而且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署环境下, 因为网络问题使得zk集群失去master节点是大概率事件,虽然服务能最终恢复,但是漫长的选举事件导致注册长期不可用是不能容忍的。
Spring Cloud Eureka -> AP
Spring Cloud Netflix 在设计 Eureka 时就紧遵AP原则(尽管现在2.0发布了,但是由于其闭源的原因 ,但是目前 Ereka 1.x 任然是比较活跃的)。Eureka Server 也可以运行多个实例来构建集群(后面专门的文章讲解),解决单点问题,但不同于 ZooKeeper 的选举 leader 的过程,Eureka Server 采用的是Peer to Peer 对等通信。这是一种去中心化的架构(参看:微服务与微服务架构思想与原则),无 master/slave 之分,每一个 Peer 都是对等的。在这种架构风格中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。每个节点都可被视为其他节点的副本。
在集群环境中如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点上,当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会在节点间进行复制(replicate To Peer)操作,将请求复制到该 Eureka Server 当前所知的其它所有节点中。
当一个新的 Eureka Server 节点启动后,会首先尝试从邻近节点获取所有注册列表信息,并完成初始化。Eureka Server 通过 getEurekaServiceUrls() 方法获取所有的节点,并且会通过心跳契约的方式定期更新。默认情况下,如果 Eureka Server 在一定时间内没有接收到某个服务实例的心跳(默认周期为30秒),Eureka Server 将会注销该实例(默认为90秒,如果某个 eureka.instance.lease-expiration-duration-in-seconds 进行自定义配置)。当 Eureka Server 节点在短时间内丢失过多的心跳时,那么这个节点就会进入自我保护模式(后面有文章会谈及关于 Eureka Server 的自我保护机制)。
Eureka的集群中,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
- Eureka不再从注册表中移除因为长时间没有收到心跳而过期的服务;
- Eureka仍然能够接受新服务注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用);
- 当网络稳定时,当前实例新注册的信息会被同步到其它节点中;
但是这个自我保护模式慎用,需要具体情况具体分析,例如你在生产发布新版本应用,不希望在部署服务时还被用户访问到,此时就需要关闭自我保护模式,不然eureka不会对正在发布的节点进行剔除,用户依然可以访问到该节点从而导致无数据返回。
自我保护模式失效:(心跳时间有关)
eurekaServer端默认30s频率来向服务提供者发送心跳,如果是2个eurekaServer则希望收到最少的心跳为 实例数 x 2 x 85% = 最少心跳数。2台实例的话希望收到的心跳是 2 x 2 x 82% = 3.4,3个心跳。
但是如果更改了心跳时间15s发送一次,一分钟会有4个心跳,而运行一段时间后2个eurekaServer挂掉一个,对应公式则为 1 x 2 x 82% = 3.4,还是3个心跳,如果使用自我保护模式 不建议降低心跳时间。
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使得整个注册服务瘫痪。
在CAP中,Consul使用CP体系结构,有利于实现可用性的一致性。
最大的区别是Eureka保证AP, Consul为CP。
Consul强一致性(C)带来的是:
- 服务注册相比Eureka会稍慢一些。因为Consul的raft协议要求必须过半数的节点都写入成功才认为注册成功
- Leader挂掉时,剩余节点则会发起选举,选举期间导致短暂不可用的情况,所以保证了强一致性而无法保证高可用性。
Eureka保证高可用(A)和最终一致性:
- eureka在设计时的分区容错保证了eureka各个节点都是平等的,只要不是所有节点都挂掉eureka就可以正常注册与使用,不会像zk出现选举而短暂不可用的情况
- 服务注册相对要快,因为不需要等注册信息replicate到其他节点,也不保证注册信息是否replicate成功
- 当数据出现不一致时,虽然A, B上的注册信息不完全相同,但每个Eureka节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求A查不到,但请求B就能查到。如此保证了可用性但牺牲了一致性。
其他方面,eureka就是个servlet程序,跑在servlet容器中; Consul则是go编写而成。
这里就平时经常用到的服务发现的产品进行下特性的对比,首先看下结论:
- Euraka 使用时需要显式配置健康检查支持;Zookeeper,Etcd 则在失去了和服务进程的连接情况下任务不健康,而 Consul 相对更为详细点,比如内存是否已使用了90%,文件系统的空间是不是快不足了。服务的健康检查
- 多数据中心支持
Consul 通过 WAN 的 Gossip 协议,完成跨数据中心的同步;而且其他的产品则需要额外的开发工作来实现;
- KV 存储服务
除了 Eureka ,其他几款都能够对外支持 k-v 的存储服务,所以后面会讲到这几款产品追求高一致性的重要原因。而提供存储服务,也能够较好的转化为动态配置服务哦。
- 产品设计中 CAP 理论的取舍
Eureka 典型的 AP,作为分布式场景下的服务发现的产品较为合适,服务发现场景的可用性优先级较高,一致性并不是特别致命。其次 CP 类型的场景 Consul,也能提供较高的可用性,并能 k-v store 服务保证一致性。 而Zookeeper,Etcd则是CP类型 牺牲可用性,在服务发现场景并没太大优势;
- 多语言能力与对外提供服务的接入协议
Zookeeper的跨语言支持较弱,其他几款支持 http11 提供接入的可能。Euraka 一般通过 sidecar的方式提供多语言客户端的接入支持。Etcd 还提供了Grpc的支持。 Consul除了标准的Rest服务api,还提供了DNS的支持。
- Watch的支持(客户端观察到服务提供者变化)
Zookeeper 支持服务器端推送变化,Eureka 2.0(正在开发中)也计划支持。 Eureka 1,Consul,Etcd则都通过长轮询的方式来实现变化的感知;
- 自身集群的监控
除了 Zookeeper ,其他几款都默认支持 metrics,运维者可以搜集并报警这些度量信息达到监控目的;
- 安全
Consul,Zookeeper 支持ACL,另外 Consul,Etcd 支持安全通道https.
- Spring Cloud的集成
目前都有相对应的 boot starter,提供了集成能力。
总的来看,目前Consul 自身功能,和 spring cloud 对其集成的支持都相对较为完善,而且运维的复杂度较为简单(没有详细列出讨论),Eureka 设计上比较符合场景,但还需持续的完善。