微服务注册与发现

Posted on 2020-07-03 15:26  三月老泉  阅读(609)  评论(0编辑  收藏  举报

 

一、       为什么需要服务注册与发现机制

当我们在尝试使用微服务架构时,我们会将一个大的单应用拆解成多个独立自治的小服务,如果在没有服务发现的机制下,我们想要在服务之间进行通信,我们只能使用 hard code 的方式,将需要通信的服务的网络信息写在服务中。这样会导致一系列的问题:

  • 使用场景有限:由于每个服务属于"微"服务,每个服务生命周期不长,每个服务可能随时被关闭、重启、替换,如果服务提供者的网络地址发生了变化,将会影响服务消费者。
  • 无法动态收缩:在生产环境中,每个服务一般都会部署多个实例,从而实现容灾和负载均衡,硬编码则无法适应这种需求。

二、       服务发现简介

那么要解决这些问题,服务的消费者就需要有一个强大的服务发现机制,服务消费者使用这个机制获取服务提供者的网络信息。即使服务提供者的信息发生变化,服务消费者也无须修改配置文件。服务发现组件便提供了这种能力,在微服务架构中,服务发现组件是一个非常重要的组件。

  1. 在各个服务在启动时,将自己的网络地址等信息注册到服务发现组件中,服务发现组件会存储这些信息。
  2. 服务消费者可从服务发现组件中查询提供者到网络地址,并使用该地址调用服务提供者的接口。
  3. 各个服务与服务发现组件使用一定机制(例如心跳机制)通信。服务发现组件如果长时间无法与某微服务实例通信,就会注销该实例。
  4. 微服务网络地址发生变更时,会重新注册到微服务发现组件。

 

 

三、       服务发现技术选型比较: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集成

已支持

已支持

已支持

已支持

CAP原则,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得 [1]  。

● 一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

● 可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

● 分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

 

Eureka是一个服务发现工具。该体系结构主要是客户端/服务器,每个数据中心有一组Eureka服务器,通常每个可用区域一个。通常Eureka的客户使用嵌入式SDK来注册和发现服务。对于非本地集成的客户,使用功能区边框等透过Eureka透明地发现服务。

Eureka提供了一个弱一致的服务视图,使用尽力而为复制。当客户端向服务器注册时,该服务器将尝试复制到其他服务器,但不提供保证。服务注册的生存时间(TTL)较短,要求客户端对服务器心存感激。不健康的服务或节点将停止心跳,导致它们超时并从注册表中删除。发现请求可以路由到任何服务,由于尽力而为的复制,这些服务可能会导致陈旧或丢失数据。这个简化的模型允许简单的群集管理和高可扩展性。

CAP中,Consul使用CP体系结构,有利于实现可用性的一致性。

最大的区别是Eureka保证AP, ConsulCP

Consul强一致性(C)带来的是:

  1. 服务注册相比Eureka会稍慢一些。因为Consulraft协议要求必须过半数的节点都写入成功才认为注册成功
  2. Leader挂掉时,重新选举期间整个consul不可用。保证了强一致性但牺牲了可用性。

Eureka保证高可用(A)和最终一致性:

  1. 服务注册相对要快,因为不需要等注册信息replicate到其他节点,也不保证注册信息是否replicate成功
  2. 当数据出现不一致时,虽然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 设计上比较符合场景,但还需持续的完善。

 

 

四、       Eureka 简介

Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

Eureka包含两个组件:Eureka Server和Eureka Client。

Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。

Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。

在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。

Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。

 

五、       Eureka 原理

 

Eureka 包含两个组件:Eureka Server 和 Eureka Client

  • Eureka Server 提供服务发现的能力,各个微服务启动时,会向 Eureka Server 注册自己的信息,Eureka Server 会存储这些信息
  • Eureka Client 是一个 Java 客户端,用于简化与 Eureka Server 的交互
  • 微服务启动后会周期性(默认30秒)的向 Eureka Server 发送心跳以续约自己的“租期“
  • 如果 Eureka Server 在一定时间内没有接收到某个服务实例到心跳,那么会注销该实例
  • 默认情况下,Eureka Server 同时也是 Eureka Client,多个 Eureka Server 实例之间是通过复制的方式来实现服务注册表中数据的同步
  • Eureka Client 会缓存注册表中的信息。无须微服务每次请求都查询 Eureka Server

六、       编写 Eureka Server

  1. 添加 eureka 依赖

 

  1. 在启动类上添加 @EnableEurekaServer注解,声明这是一个 Eureka Server
  2. 在配置文件application.properties中添加

 

  1. 访问http://localhost:8000/

 

 

五、       将微服务注册到 Eureka Server 上

  1. 在微服务应用中添加依赖

 

  1. 在配置文件中添加

 

 

  1. 启动类上添加 @EnableDiscoveryCilent 或者@EnableEurekaClient注解,声明这个是一个 Eureka Client。
  2. 启动 服务发现组件APP 和 微服务客户端,访问 http://localhost:8000

六、       高可用

Eureka Server 可以通过运行多个实例并相互这次的方式实现高可用部署,Eureka Server 会彼此增量的同步信息,从而确保所有节点数据一致。

  1. 在 hosts 中配置以下信息

 

 

  1. 将 application.yml 配置中添加

 

 

 

3 将应用注册到 Eureka Server 上
在 application.yml 中添加

 

 

 

七、       备注

Eureka参数配置如下:

 

 

Name

Default

Description

1

eureka.client.enabled

true

表明尤里卡客户端启用

2

eureka.client.eureka-connection-idle-timeout-seconds

30

显示HTTP连接尤里卡服务器处于闲置状态多少时间(以秒为单位)才可以关闭。     

在AWS环境中,建议值是30秒或更少,因为在不稳定状态防火墙清除连接信息几分钟后断开连接

3

eureka.client.eureka-server-connect-timeout-seconds

5

表示要等多长时间(以秒为单位)之前到尤里卡的连接服务器超时。

注意,连接在客户端被org.apache.http.client汇集。HttpClient和创造这个设置会影响实际的连接以及等待时间从池中获取连接。

4

eureka.client.register-with-eureka

true

表明该实例能否被注册到尤里卡服务的其他客户端发现。

在某些情况下,您不希望您的实例被发现而你想发现其他实例。

5

eureka.client.fetch-registry

true

表明这个客户能否应该从尤里卡服务端获取尤里卡注册表信息

6

eureka.client.g-zip-content

true

显示只要是支持的服务从尤里卡服务端获取的内容是否被压缩。

表明从尤里卡服务端获取的信息是压缩过的用来优化网络流量。

7

eureka.client.heartbeat-executor-thread-pool-size

2

心跳执行器的线程池初始值。

8

eureka.client.initial-instance-info-replication-interval-seconds

40

表明最初多长时间(以秒为单位)复制实例信息到尤里卡服务。

9

eureka.client.instance-info-replication-interval-seconds

30

表明多长时间(以秒为单位)复制实例更改到尤里卡服务。

10

eureka.client.registry-fetch-interval-seconds

30

表明多长时间(以秒为单位)从尤里卡服务获取注册表信息。

11

eureka.client.serviceUrl.defaultZone

 

尤里卡客户端和服务端通信的地址,多个地址用逗号隔开,e.g. http://localhost:8761/eureka/

12

eureka.dashboard.enabled

true

表明是否启用尤里卡服务控制台,默认为启用

13

eureka.dashboard.path

/

尤里卡服务控制台的相对路径,默认为“/”

14

eureka.instance.health-check-url

 

尤里卡实例健康检查绝对路径URL

15

eureka.instance.home-page-url

 

尤里卡实例home页面绝对路径URL

16

eureka.instance.hostname

 

尤里卡实例主机名;如果不配置,尤里卡会直接使用操作系统的主机名

17

eureka.instance.lease-expiration-duration-in-seconds

90

表明尤里卡服务等待的时间间隔,以秒为单位自收到最后的心跳才能把这个实例从它的视图中删除。

这个值被设置为至少高于leaseRenewalIntervalInSeconds中指定的值。

18

eureka.instance.lease-renewal-interval-in-seconds

30

表明尤里卡客户端间隔多长时间(以秒为单位)向尤里卡服务发送心跳信息用来证明客户端是活着的;

在leaseExpirationDurationInSeconds参数的指定值期间没有收到来自客户端的心跳,这个实力会被尤里卡服务删除

19

eureka.instance.namespace

eureka

通过配置文件找到namespace,忽略springcloud的配置

20

eureka.instance.status-page-url

 

尤里卡实例状态页面绝对路径URL