服务治理之Spring Cloud Eureka
1.服务治理。可以说是微服务架构中最为核心和基础的模块,主要用来实现各个微服务实例的自动化注册于发现。
PS:为了解决微服务架构中的服务实例维护问题,产生了大量的服务治理框架和产品。而他们都围绕着服务注册与服务发现机制来完成对微服务应用实例的自动化管理。
-
服务注册。在服务治理框架中,通常都会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,将主机与端口号、版本号、通信协议等一些附加信息告知注册中心,注册中心按服务名分类组织服务清单。eg:
- 服务发现。由于在服务治理框架下运作,服务间的调用不再通过制定具体的实例地址来实现,而是通过服务名发起请求调用实现。so,服务调用方在调用服务提供方接口的时候,并不知道具体的服务实例位置。so,调用方需要向服务注册中心咨询服务,并获取所有服务的实例清单,达到访问服务实例的目的。
-
Netflix Eureka。 Spring Cloud Eureka 是Spring Cloud Netflix 微服务套件中的一部分,它基于Netflix Eureka 做了二次封装。通过使用Netflix Eureka来实现服务的注册与发现。包含服务端组件和客户端组件。
- Eureka服务端。也称为服务注册中心。和其他的服务注册中心一样,支持高可用配置。它依托于强一致性提供良好的服务实例可用性,可应对多种不同的故障场景。如果Eureka以集群模式部署,当集群中有分片出现故障时,Eureka就转入自我保护模式。
- Eureka客户端。 主要处理服务的注册与发现。客户端服务通过注解和参数配置的方式,嵌入在客户端应用程序的代码中,在应用程序运行时,它向服务注册中心(服务端)注册自身提供的服务并周期性地发送心跳来更新它的服务租约。同时,它也能从服务端查询当前注册的服务信息并把他们缓存到本地并周期性地刷新服务状态。
2.使用Eureka构建注册中心以及进行注册与发现服务。
- 搭建服务注册中心。
创建基础的 SpringBoot 工程,命名:eureka-server,并在pom.xml 中引入必要的依赖。通过@EnableEurekaServer 注解启动一个服务注册中心提供给其他应用进行对话。【ps:】默认情况下,该服务注册中心也会将自己作为客户端来注册它自己,so,需要禁用他的客户端注册行为,只需要在application.properties 中增加 如下配置:
a. server.port=1111
b.eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://{server.port}/eureka/
服务启动后,访问http://localhost:1111/ 可以看到Eureka的信息面板。 - 注册服务提供者。
(1)修改pom.xml,增加Spring Cloud Eureka模块的依赖。(2)改造/hello 请求处理接口,通过注入 DiscoveryClient对象,在日志中打印出服务的相关内容。(3)在主类中加上@EnableDiscoveryClient 注解,激活 Eureka中的DiscoveryClient实现。(4)在 application.properties 配置文件中,通过spring.application.name属性为服务命名,eg:hello-service。 - 高可用注册中心。Eureka Server 的高可用实质是将自己作为服务向其他服务注册中心注册自己,这样既可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。eg:构建一个双节点的服务注册中心集群。
- 创建application-peer1.properties,作为peer1服务中心的配置,并将serviceUrl 指向peer2;同时创建application-peer2.properties,作为peer2服务中心的配置,并将serviceUrl指向peer1;在/etc/hosts 文件中添加对peer1和peer2的转换;通过spring.profiles.active 属性来分别启动peer1和peer2。
3.Eureka详解。
1.基础架构,即三个核心要素。服务注册中心、服务提供者、服务消费者。
2.服务治理机制。
a. 服务提供者:服务注册、服务同步、服务续约。
b. 服务消费者:获取服务、服务调用、服务下线。
c.服务注册中心:失效剔除、自我保护。
eg:服务注册:服务提供者在启动的时候会通过REST请求的方式将自己注册到Eureka Server上,同时带上自身服务的一些元数据信息。Eureka Server接收到这个Rest请求之后,将元数据信息存储在一个双层结构的Map中,其中第一层的key是服务名。第二层的key 是具体服务的实例名。
在服务注册时,需要确认一下eureka.client.register-with-eureka=true参数是否正确,该值默认为true。若设置为fasle将不会启动注册操作。
eg:服务同步:从eureka服务治理体系架构图中可以看到,不同的服务提供者可以注册在不同的服务注册中心上,它们的信息被不同的服务注册中心维护。
此时,由于多个服务注册中心互相注册为服务,当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发给集群中相连的其他注册中心,从而实现服务注册中心之间的服务同步。通过服务同步,提供者的服务信息就可以通过集群中的任意一个服务注册中心获得。
eg:服务续约:在注册服务之后,服务提供者会维护一个心跳用来持续高速Eureka Server,“我还在持续提供服务”,否则Eureka Server的剔除任务会将该服务实例从服务列表中排除出去。我们称之为服务续约。
下面是服务续约的两个重要属性:
(1)eureka.instance.lease-expiration-duration-in-seconds
leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance。默认为90秒,如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。
如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。
该值至少应该大于leaseRenewalIntervalInSeconds
(2)eureka.instance.lease-renewal-interval-in-seconds
leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。
eg:获取服务:消费者服务启动时,会发送一个Rest请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server会维护一份只读的服务注册清单来返回给客户端,同时该缓存清单默认会每隔30秒更新一次。
下面是获取服务的两个重要的属性:
(1)eureka.client.fetch-registry
是否需要去检索寻找服务,默认是true
(2)eureka.client.registry-fetch-interval-seconds
表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒
eg:服务调用:服务消费者在获取服务清单后,通过服务名可以获取具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。
eg:服务下线:在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭操作时,会触发一个服务下线的Rest服务请求给Eureka Server,告诉服务注册中心:“我要下线了。”服务端在接收到该请求后,将该服务状态置位下线(DOWN),并把该下线事件传播出去。
3. region(地域)与zone(可用区)
-
region和zone(或者Availability Zone)均是AWS的概念。在非AWS环境下,我们可以简单地将region理解为地域,zone理解成机房。一个region可以包含多个zone,可以理解为一个地域内的多个不同的机房。不同地域的距离很远,一个地域的不同zone间距离往往较近,也可能在同一个机房内。
region可以通过配置文件进行配置,如果不配置,会默认使用us-east-1。同样Zone也可以配置,如果不配置,会默认使用defaultZone。
Eureka Server通过eureka.client.serviceUrl.defaultZone属性设置Eureka的服务注册中心的位置。
指定region和zone的属性如下:
(1)eureka.client.availabilityZones.myregion=myzone# myregion是region
(2)eureka.client.region=myregionRibbon的默认策略会优先访问通客户端处于同一个region中的服务端实例,只有当同一个zone中没有可用服务端实例的时候才会访问其他zone中的实例。所以通过zone属性的定义,配合实际部署的物理结构,我们就可以设计出应对区域性故障的容错集群。
4.服务实例类配置
-
端点配置
eureka实例的状态页面和健康监控的url默认为spring boot actuator提供的/info端点和/health端点。我们必须确保Eureka客户端的/health端点在发送元数据的时候,是一个能够被注册中心访问到的地址,否则服务注册中心不会根据应用的健康检查来更改状态(仅当开启了healthcheck功能时,以该端点信息作为健康检查标准)。而如果/info端点不正确的话,会导致在Eureka面板中单击服务时,无法访问到服务实例提供的信息接口。
大多数情况下,我们不需要修改这个几个url配置。但是当应用不使用默认的上下文(context path或servlet path,比如配置server.servletPath=/test),或者管理终端路径(比如配置management.contextPath=/admin)时,我们需要修改健康检查和状态页的url地址信息。
application.yml配置文件如下:
server.context-path=/helloeureka
-
元数据。
元数据是Eureka客户端在向服务注册中心发送注册请求时,用来描述自身服务信息的对象,其中包含了一些标准化的元数据,比如服务名称、实例名称、实例IP、实例端口等用于服务治理的重要信息;以及一些用于负载均衡策略或是其他特殊用途的自定义元数据信息。
我们可以通过eureka.instance.<properties>=<value>的格式对标准化元数据直接进行配置,其中<properties>就是EurekaInstanceConfigBean对象中的成员变量。而对于自定义元数据,可以通过eureka.instance.metadataMap.<key>=<value>的格式来进行配置。比如:
eureka.instance.metadataMap.zone=shanghai
//随机生成实例名
eureka.instance.metadataMap.instanceId={random.value}
-
健康检测。
默认情况下,Eureka中各个服务实例的健康检测并不是通过spring-boot-acturator模块的/health端点来实现的,而是依靠客户端心跳的方式来保持服务实例的存活。在Eureka的服务续约与剔除机制下,客户端的健康状态从注册到注册中心开始都会处于UP状态,除非心跳终止一段时间之后,服务注册中心将其剔除。默认的心跳实现方式可以有效检查客户端进程是否正常运作,但却无法保证客户端应用能够正常提供服务。
在Spring Cloud Eureka中,可以把Eureka客户端的健康检测交给spring-boot-actuator模块的health端点,以实现更加全面的健康状态维护,设置方式如下:
(1) 在pom.xml中引入spring-boot-starter-actuator模块的依赖
(2) 在application.properties中增加参数配置
eureka.client.healthcheck.enabled=true
5.跨平台支持
- 默认情况下,Eureka使用 Jersey和 XStream 配合JSON作为Server与Client之间的通讯协议。也可以选择实现自己的协议来代替。