因为项目技术架构变更需要,去年年末调研过一次服务注册与发现组件,今天总结一下。常见的组件有Eureka、Zookeeper、etcd、consul、nacos,对比图如下:
组件名称/功能 | 通信方式 | watch机制 | 服务健康检查 | kv存储 | CAP | 一致性算法 | 跨数据中心(机房) | 开发语言 | 运维监控 | 社区活跃度 |
---|---|---|---|---|---|---|---|---|---|---|
Eureka | http | 发现方long polling | 注册方主动上报 | 不支持 | AP | ---- | ---- | java | 有 | 低 |
Zookeeper | tcp(sdk) | zk会主动通知发现方 | 注册方主动上报 | 支持 | CP | zab(paxos) | ---- | java | 无 | 低 |
nacos | http,grpc,dns,dubbo | 发现方 long polling | 注册方主动上报 | 支持 | CP/AP可选 | raft | 支持 | java | 有 | 高 |
etcd | http,grpc | 发现方long polling | 注册方主动上报 | 支持 | CP | raft | ---- | go | 无 | 高 |
consul | http,grpc | 发现方long polling | 注册方主动上报和consul主动询问 | 支持 | CP | raft +gossip | 支持 | go | 有 | 高 |
之所以会有服务注册与发现这种中间件,主要是在微服务大行其道之下,可能一开始由配置文件或数据库来管理服务的服务标识,服务ip,服务port等关键属性也可以,但随着服务增多,服务上线、下线、重启、非正常宕机越来越频繁,原来呆板的管理模式已经难以跟上服务频繁变动的步伐,于是诞生了服务注册与发现。
其核心功能如下:
服务注册就是服务提供者把自身的元数据告诉服务注册与发现中间件,元数据主要包含服务标识,服务ip,服务port,有时还可携带身份校验,协议,版本号等信息。
服务注册可分为客户端注册和代理注册。
代理注册是由一个单独的代理服务负责注册与下线,当服务提供者启动后以某种方式通知代理服务,然后代理服务负责向注册中心发起注册工作,见下图:
缺点:
优点:
ps:流行的服务注册与发现都提供多种语言的SDK,非必要使用客户端注册为宜。
客户端注册是有客户端直接引入相应的SDK进行注册与下线工作。服务启动时服务提供者直接向服务注册中心发起注册工作。
缺点:
优点:
健康检查是指服务注册中心检查服务提供者是否能正常提供服务,其本质就是心跳机制。心跳若基于TCP的KeepAlive机制并不保险,KeepAlive只能保证服务提供者存活,但存活不代表健康,比如服务提供者网络没问题,但数据库故障了,那么就无法正常提供服务,这就是存活但不健康,所以往往是由服务注册中心或服务提供者暴漏一个健康检查接口,根据是谁暴漏的接口可以分为主动检测和被动检测。
主动检测是由服务注册中心发起,调用服务提供者提供的健康检查接口。服务注册中心每隔一定时间就会主动询问服务提供者,服务提供者
正常应答,说明健康,否则服务注册中心就会将服务提供者下线,并通知服务消费者。
主动检测机制并不流行,主要是因为需要服务提供者提供接口,就需要开发者编写相应代码,与业务耦合,很麻烦。五种流行的中间件中就consul提供了主动检测的机制,但用的并不多。
被动检测就是由服务提供者发起,调用服务注册中心提供的健康检查接口。服务提供者每隔一定时间就会主动上报给服务注册中心,这样服
务注册中心依据健康策略(超时时间阈值、超时次数阈值)就可以知道服务提供者是否健康,不满足健康策略就将服务提供者下线,并通知
服务消费者。
服务注册中心如何检查呢,当然是定时任务了,比如每隔一定时间检查下该服务提供者上次上报的时间与当前时间差值是否超
过超时时间阈值之类的。
这种健康检查方式是最流行的,一般内置在SDK中,在服务提供者发起注册时,注册成功后就会启动健康检查逻辑。五种流行的中间件都提供了被动检测的机制。
服务发现就是服务消费者通过服务注册中心能够通过关键词查询到相应的服务提供者,然后去请求服务提供者。
服务发现也可分为代理发现和客户端发现。
代理发现是指服务消费者向服务提供者发起网络调用时由代理完成服务发现操作。
优点:
客户端发现是指服务消费者直接通过服务注册中心获取服务提供者的信息,然后直接向服务提供者发起网络调用。
与代理发现相比,优缺点相反。
服务消费者/代理第一次获取了所有服务提供者的信息后,就缓存在本地了,后续对服务提供者的网络调用就基于本地缓存了,那么后来某个服务提供者挂了或者新上线一个服务提供者该如何告诉服务发现的一方呢?这个时候就需要服务变更通知机制了。
服务通知机制从服务注册中心角度看,也分为主动通知与被动通知。
主动通知是建立在服务消费者和服务注册中心支持watch机制的基础上的。即服务消费者向服务注册中心注册要watch的服务标识(前缀),并实现接收服务注册中心通知服务提供者变更的逻辑(add,del),等服务服务变更者发生变更(新服务上线,已有服务故障或下线等)时便可及时通知服务消费者。
缺点:
优点:
主动通知虽然及时,但实现逻辑复杂,需要开发者关注,应用并不广,五大中间件中只有ZooKeeper支持
被动通知一般是通过长轮询的机制来实现的,也可以叫伪watch机制。即服务消费者通过SDK封装好的接口,设置要关注的服务标识,SDK内部会通过长轮询机制及时获取服务提供者的变更,进而更新服务消费者本地服务缓存。
优缺点与主动通知相反,但变更通知慢也是相对的,一般来说也是够用了,瑕不掩瑜,所以大多采用该方案进行服务变更通知。
在整个微服务系统中,注册中心服务地位无疑是特殊的,它一般不依赖于其他服务,但所有业务服务都依赖于它,一旦注册中心崩溃,将导致整个系统不可用,因此注册中心服务必须具有高可用的特性,所以在实际生产中都是集群式部署。
第一章总结了服务注册与发现的技术要点,下面再五种常用中间件总结如下:
Eureka:
Eureka是Netflix的开源项目,是一个很优秀的服务注册组件,但是Netflix将2.0闭源后,便已不是最优选择,不过现有的项目使用Eureka 1.x功能已足够使用,不必急于更换技术栈,新项目建议不要使用Eureka了。
Zookeeper
Zookeeper是由Google开源的由Java语言实现的分布式协调服务
,是Hadoop和Hbase的重要组件,提供了KV存储、发布订阅、负载均衡、分布式同步等功能。由此可以看出Zookeeper的诞生与服务注册与发现并没有几毛钱的关系,只是恰巧其中某些功能可以实现服务注册于发现,于是大家就拿来用了。
ZooKeeper使用临时节点(ephemeral node)来实现服务注册和基本的健康检查功能。每当服务实例启动就会在ZooKeeper中注册一个临时节点,而当服务实例故障或下线该临时节点会被ZooKeeper自动删除,如果有其他服务依赖这个服务可以设置监听该服务实例对应的临时节点,当临时节点被删除时,依赖该服务的其他服务会获得通知。依赖ZooKeeper自身的高可用及临时节点提供的健康检查和监听机制来实现具备容错能力的服务发现机制。
由于zookeeper 遵循CP,一旦Leader挂掉,重新选举非常耗时,网上资料是30-120s,在此期间均不可用,显然不符合服务注册与发现的高可用要求
,因此并不是非常适合做服务注册与发现中间件。
etcd
etcd本身只是一个高可用的一致性键值存储系统,用于提供可靠的分布式键值存储,若要实现服务注册与发现功能,需要象ZK一样,基于etcd的api来做进一步封装。
consul
consul是HashiCorp开源的专门面向服务注册与发现功能的中间件,开箱即用。
nacos
nacos是Alibaba开源的专门面向服务注册与发现功能的中间件,开箱即用。
由此可知,consul和nacos乃上上只选,当然还是要根据项目按需评估。
服务注册发现组件的原理及比较
五种常用的注册中心比较
etcd v3 服务注册与发现
选Zookeeper作为注册中心我们还要注意些什么
Eureka介绍