什么是服务发现与注册?
随着微服务的出现,服务发现与注册成为微服务的主要连接方式。
服务注册
服务将自己在哪,能做什么等信息在某个地方进行注册。
服务发现
百度百科上:指使用一个注册中心来记录分布式系统中的全部服务的信息,以便其他服务能够快速的找到这些已注册的服务。
内部百科上:用于解决服务注册和服务发现的问题,支持多机房和跨机房,并且托管实例的健康检查
本人对其的理解:
- 一块存储(注册中心)来保存服务的信息
- 快速找到已注册服务的能力
- 对所注册服务做健康检查(高级的要求)
为什么需要服务发现与注册?
上面有提到是随着微服务发现才产生的服务发现与注册,因此如果想知道为什么需要服务发现与注册,当然也不得不提到服务的演进。
石器时代
服务部署在一个机器上,多个用户如需要访问服务都去访问同一个机器。
青铜时代
因为用户的增多,单个机器已经无法满足大家同时去访问服务了,负载均衡的出现解决了这个问题
铁器时代
随着人们对服务的需求的增多,服务越来越来大,单个服务内越来越复杂,任意改动都会牵一发而动全身(可以想象整个公司的研发都改同一个project,是多恐怖的事情,无尽的代码冲突),这时候不同维度去划分服务边界,将大服务拆分、解耦成为了新的问题,自此,微服务就诞生了出来。
然而因为各个微服务之间互相调用,一次请求可能需要经过很多的微服务,调用链路给大家看张图(这个还不算很复杂的调用)
想象一下,各个微服务写代码的时候都需要去找维护一层与其他服务调用的地址,并且在服务新部署后地址还可能发生变更,这是多恐怖的事情。于是,机智的程序猿想到了一句话:“坐上来,自己动”
于是服务发现与注册就出现了,所有的微服务在启动的时候,自动去找个第三方中介注册上,当其他服务需要调用的时候,统一去找中介查询需要的使用服务地址,然后去使用其服务。
综上,本人对其实现的理解:
- 动态管理维护各个微服务节点
- 简化、解耦各个微服务间调用依赖的细节
服务发现与注册的实现有哪些?
DNS SRV
最早期服务发现与注册的雏形,可视为服务发现与注册发现的一种方案。
访问服务的时候,本地的DNS resolver从DNS服务器查询到一个地址列表,根据优先级和权重,从中选取一个地址作为本次请求的目标地址。。
发现过程则是去DNS服务器上查询被调用方,本地的DNS客户端会DNS服务器查询到一个地址列表,根据优先级和权重,从中选取一个地址作为本次请求的目标地址,同时也会周期性的缓存和刷新数据
其缺陷就是没有相应的健康检查机制,若是注册上的服务提供方发生问题或者修改IP,DNS无法及时做出反应。
SkyDNS
DNS的升级版,它采用Go语言编写。
服务注册:与 DNS不同的是,服务会使用基于HTTP的API创建带有TTL的连接,服务需要周期性通过心跳报告其状态,同时在SRV上也做了扩展,可以支持服务版本、环境和地区。
服务发现:基本和DNS SRV一样。
优势:
- 支持的注册中心有多个
- 支持健康检查
劣势:
- 健康检查策略简单,依赖心跳和TTL
Zookeeper
Zookeeper是分布式协调服务,提供了数据/发布订阅、负载均衡、分布式同步等功能。
Zookeeper基于主从架构,搭建可高扩展的服务集群,其服务架构如下:
- Leader-Server:Leader负责进行投票的发起和决议,更新系统中的数据状态
- Server:Server中存在两种类型:Follower和Observer。其中Follower接受客户端的请求并返回结果(事务请求将转发给Leader处理),并在选举过程中参与投票;Observer与Follower功能一致,但是不参与投票过程,它的存在是为了提高系统的读取速度
- Client:请求发起方,Server和Client之间可以通过长连接的方式进行交互。如发起注册或者请求集群信息等。
服务注册:服务提供方在其Server添加一个节点存储其地址信息
服务发现:直接通过利用zookeeper目录存储结构查询,然后再对节点进行订阅
健康检查:通过HTTPS长连接,keepalive
优势:
- 其模型架构天然支持CP,是很好的注册中心
劣势:
- 健康检查策略简单,依赖HTTPS长连接
- 选主过程中无法支持读写操作
SmartStack
Zookeeper 负责以一致且容错的方式存储服务状态;Nerve 负责对检查服务的运行状态(健康检查)并向zookeeper注册;Synapse 会从zookeeper中读出服务提供者,并且配置在HAProxy中;每当zookeeper发生变化,Synapse都会去重新配置HAProxy;HAProxy需要部署在每个服务消费者里,可以做到负载均衡和连通性检查。 若Zookeeper挂掉,则不会去刷新HAProxy
优势:
- 提供负载、健康检查与联通性检查
- 支持分布式
劣势:
- 每当zookeeper发生变化,Synapse都会去重新配置HAProxy
- 需要提前配置Synapse 所需的服务
- HAProxy的连接检查成本高
Dubbo
- 配置中心。
- 存储 Dubbo 启动阶段的全局配置,保证配置的跨环境共享与全局一致性
- 负责服务治理规则(路由规则、动态配置等)的存储与推送。
- 元数据中心。
- 接收 Provider 上报的服务接口元数据,为 Admin 等控制台提供运维能力(如服务测试、接口文档等)
- 作为服务发现机制的补充,提供额外的接口/方法级别配置信息的同步能力,相当于注册中心的额外扩展
- 注册中心。协调 Consumer 与 Provider 之间的地址注册与发现
注册中心的架构图:
Dubbo 的Registry 可通过配置的方式引入不同组件,包括但不限于Nacos/Consul/Zookeeper, 因此其在服务发现与注册上的优缺点需要看具体依赖项。
Eureka
Eureka是Netflix开发的服务发现组件,本身是一个基于REST的服务。Spring Cloud将它集成在其子项目spring-cloud-netflix中,以实现Spring Cloud的服务发现功能,架构图如下
Eureka 整体有由Client + Server来构成,Client需要集成到具体的服务中。
服务注册:Eureka Client将正在运行的实例的信息注册到 Eureka Server。
服务发现:Eureka把所有注册信息都放在内存中,客户端会有一份本地注册信息的缓存,这样就不需要每次远程调用时都向Eureka查询注册信息。默认情况下,Eureka服务端自身也是个客户端,所以需要定一个Eureka Server的URL作为"伙伴"(peer)。
健康检查:向Eureka Server注册过的服务会每30秒向Server发送一次心跳连接, Server会根据心跳数据更新该服务的健康状态并复制到其他Server中。如果超过90秒没有收到该服务的心跳数据,则Server会将该服务移出列表
不同Eureka Server 之间同步主要通过Peer to Peer 模式,副本间不分主从,任何副本都可以接收写操作,然后每个副本间互相进行数据更新。但各个副本间数据同步时可能产生数据冲突。
对于循环同步,通过HEADER_REPLICATION来区分其他server发过来的请求是否消费过,对于数据冲突则是通过lastDirtyTimestamp(服务最近一次变更时间)
优势:
- 有心跳检查,并且心跳会去进行数据修复
- 支持部署多机房
劣势:
- 依赖于应用自身完成服务的注册与发现,对应用侵入强
- 由于是AP,数据一致性无法保证
- 停止了迭代
Nacos
Nacos 提供了一组简单易用的特性集,可快速实现动态服务发现、服务配置、服务元数据及流量管理。
服务注册:服务提供者使用 原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service。
服务发现:服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。
健康检查:Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式,主要还是通过心跳。
整体架构如下
优势:
- 属于外部应用,侵入性小
- 支持分布式
- 健康检查,可配置的健康检查方式,支持多
- 持续迭代
劣势:
- 目前无
Etcd
是一个分布式的,一致的 key-value 存储,主要用途是共享配置和服务发现。
Etcd(Server)大体上可以分为网络层、Raft、存储模块和辅助状态机
-
网络层:提供网络数据读写功能,监听服务端口,完成集群节点之间数据通信,收发客户端数据。
-
Raft模块:Raft强一致性算法的具体实现。
-
存储模块:涉及KV存储、WAL文件、Snapshot管理等,用户处理etcd支持的各类功能的事务,包括数据索引 节点状态变更、监控与反馈、事件处理与执行 ,是 etcd 对用户提供的大多数 API 功能的具体实现。
-
复制 状态机:这是一个抽象的模块,状态机的数据维护在内存中,定期持久化到磁盘,每次写请求都会持久化到 WAL 文件,并根据写请求的内容修改状态机数据。
服务注册,服务方将自身的地址信息以K-V形式存储进Etcd。
服务发现,通过注册时的Key,进行快速查找。
健康检查,对注册的服务设置Key TTL,定时保持服务的心跳以达到监控健康状态的效果。
优势:
- 其模型架构天然支持CP,是很好的注册中心
- 有健康检查策略
- 更像一个K-V存储库
劣势:
- 选主过程中无法支持读写操作
Consul
Consul是由HashiCorp基于Go语言开发的支持多数据中心分布式高可用的服务发布和注册服务软件,采用Raft算法保证服务的一致性,且支持健康检查。整体架构如下
单个数据中心中,Consul分为Client和Server两种节点(所有的节点也被称为Agent),Server节点保存数据,Client负责健康检查及转发数据请求到Server;Server节点有一个Leader和多个Follower,Leader节点会将数据同步到Follower
服务注册:可通过配置,或者调用HTTP API注册,Consul Client将注册信息发到Consul Server,服务信息保存在Server的各个节点中,并且通过Raft实现了强一致性
服务发现:服务通过API访问Client,Client会将请求转发到Server,Server查询到服务提供方信息返回。
健康检查:配置文件中定义或在运行时通过 HTTP 接口添加,支持多种检查方式,包括但不限于Script 、HTTP、TCP、TTL等
多数据中心:运行相同服务的不同数据中心的 Consul 集群可以用外网连接起来。集群的行为是互相独立的,且只会通过外网进行通信。除非通过 CLI 或 API 特别指明,默认情况 Consul 只会返回本地数据中心的结果,Consul 不会在多数据中心之间共享数据。consul-replicate 工具可以用来定期同步 KV 数据。
优势:
- 可配置化的执行健康检查
- 强一致性
- 支持分布式
- 外部应用,入侵小 劣势
- 强一致性导致的注册慢、选主过程不可用
对比
如有理解错误,欢迎批评指正
| 语言 | CAP | 一致性算法 | 连接方式 | 健康检查 | 多数据中心 | 支持负载 | 雪崩保护(限流、熔断等) | |
|---|---|---|---|---|---|---|---|---|
| SkyDNS | Go | AP | raft | HTTP/DNS | DNS的TTL+心跳 | - | 支持 | - |
| Zookeeper | Java | CP | paxos | Client binding | (弱)keepalive | - | - | - |
| SmartStack | Ruby | AP | 依赖zookeeper | Nerve + Synapse | Nerve提供 | - | 支持 | - |
| Dubbo | Java | - | 依赖Nacos/Consul/Zookeeper | 支持多协议 | 随依赖 | 随依赖 | 支持 | 支持 |
| Eureka | Java | AP | - | Client binding | 可配置 | 支持 | 支持 | |
| Nacos | Java | AP+CP | raft | HTTP/动态DNS/UDP等 | 心跳 | 支持 | 支持 | 支持 |
| Etcd | Go | AP | raft | Client binding/HTTP | 心跳 | - | 支持 | - |
| Consul | Go | CP | raft | HTTP/DNS等 | 可配置 | Gossip支持 | 支持 | - |
路漫漫其修远兮,吾将上下而求索。
参考资料
zhuanlan.zhihu.com/p/161277955
cloud.tencent.com/developer/a…