第三章 服务治理: Spring Cloud Eureka
Spring Cloud Eureka是 Spring Cloud Netflix微服务套件中的一部分,它基于Netflix Eureka做了二次封装,主要负责完成微服务架构中的服务治理功能
服务治理
服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例自动化注册与发现
- 服务注册:在服务治理框架中,通常都会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务。注册中心按服务名分类组织服务清单
- 服务发现:在服务治理框架下运作,服务间的调用不再通过指定具体的实例地址来实现,而是通过向服务名发起请求调用实现
Netflix Eureka
Spring Cloud Eureka,使用Netflix eureka来实现服务注册与发现,它既包含了服务端组件也包含客户端组件,并且均采用java编写。
- Eureka服务端:服务注册中心,同其他服务注册中心一样,支持高可用配置
- Eureka客户端:主要处理服务的注册与发现
Eureka详解
基础架构
整个 Eureka 服务治理基础架构有三个核心要素:
- 服务注册中心: Eureka 提供的服务端, 提供服务注册与发现的功能, 也就是在上一节中我们实现的 eureka-server
- 服务提供者:提供服务的应用, 可以是 Spring Boot 应用, 也可以是其他技术平台且遵循 Eureka 通信机制的应用。它将自己提供的服务注册到 Eureka, 以供其他应用发现, 也就是在上一节中我们实现的 HELLO-SERVICE 应用
- 服务消费者:消费者应用从服务注册中心获取服务列表, 从而使消费者可以知道去何处调用其所需要的服务,在上一节中使用了 Ribbon 来实现服务消费,另外后续还会介绍使用 Feign 的消费方式
服务治理机制
- "服务注册中心-1" 和 “服务注册中心-2", 它们互相注册组成了高可用集群。
- "服务提供者” 启动了两个实例, 一个注册到 “服务注册中心-1" 上, 另外一个注册到 “服务注册中心-2" 上
- 还有两个 “服务消费者“, 它们也都分别只指向了一个注册中心
服务提供者:
- 服务注册:“服务提供者” 在启动的时候会通过发送REST请求的方式将自己注册到EurekaServer 上, 同时带上了自身服务的一些元数据信息。Eureka Server接收到这个REST请求之后,
将元数据信息存储在一个双层结构Map中, 其中第一层的key是服务名, 第二层的key是具体服务的实例名。在服务注册时, 需要确认一下 eureka.cli ent.register-with-eureka=true
参数是否正确, 该值默认为true。 若设置为false将不会 启动注册操作 - 服务同步:由于服务注册中心之间因互相注册为服务, 当服务提供者发送注册请求到一个服务注册中心时, 它会将该请求转发给集群中相连的其他注册中心, 从而实现注册中心之间的服务同步 。 通过服务同步,两个服务提供者的服务信息就可以通过这两台服务注册中心中的任意一台获取到
- 服务续约:在注册完服务之后,服务提供者会维护一个心跳用来持续告诉EurekaSe1-ver: "我还活着”, 以防止Eureka Server的“剔除任务 ” 将该服务实例从服务列表中排除出去,我们称该操作为服务续约(Renew)。关于服务续约有两个重要属性,我们可以关注并根据需要来进行调整:
#参数用于定义服务续约任务的调用间隔时间,默认为30秒
eureka.instance.lease-renewal-interval-in-seconds=30#参数用于定义服务失效的时间,默认为90秒 eureka.ins七ance.lease-expiration-duration-in-seconds=90
服务消费者:
- 荻取服务:当我们启动服务消费者的时候, 它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单 。 为了性能考虑, Eureka Server会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30秒更新 一次。获取服务是服务消费者的基础,所以必须确保eureka.c巨ent.fetch-registry=true参数没有被修改成false, 该值默认为七rue。若希望修改缓存清单的 更新时间,可以通过 eureka.c巨ent.registry-fetch-interval-seconds= 30参数进行修改,该参数默认值为30, 单位为秒
- 服务调用:服务消费者在 获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。 因为有这些服务实例的详细信息, 所以客户端可以根据自己的需要决定具体调用哪个实例,在沁bbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡
- 服务下线:当服务实例进行正常的关闭操作时, 它会触发一个服务下线的REST请求给Eurke a Server, 告诉服务注册中心:“我要下线了”。 服务端在接收到请求之后, 将该服务状态置为下线(DOWN), 并把该下线事件传播出去
服务注册中心 :
- 失效剔除:为了从服务列表中将这些无法提供服务的实例剔除, Eureka Server在启动的时候会创建一个定时任务,默认每隔一段时间(默认为60秒) 将当前清单中超时(默认为90秒)没有续约的服务剔除出去
- 自我保护:EurekaServer 在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%, 如果出现低于的情况(在单机调试的时候很容易满足, 实际在生产环境上通常是由于网络不稳定导致), EurekaServer会将当前的实例注册信息保护起来, 让这些实例不会过期, 尽可能保护这些注册信息。 但是, 在这段保护期间内实例若出现问题, 那么客户端很容易拿到实际已经不存在。由于本地调试很容易触发注册中心的保护机制, 这会使得注册中心维护的服务实例不那么准确。 所以, 我们在本地进行开发的时候, 可以使用eureka.server.enableself-preserva巨on = false参数来关闭保护机制, 以确保注册中心可以将不可用的实例正确剔除
配置详解
在Eureka的服务治理体系中, 主要分为服务端与客户端两个不同的角色, 服务端为服务注册中心, 而客户端为各个提供接口的微服务应用。 当我们构建了高可用的注册中心之后, 该集群中所有的微服务应用和后续将要介绍的一些基础类应用(如配置中心、 API网关等)都可以视作该体系下的一个微服务(Eureka客户端)。 服务注册中心也一样, 只是高可用环境下的服务注册中心除了作为客户端之外, 还为集群中的其他客户端提供了服务注册的特殊功能
Eureka服务端更多地类似于一个现成产品, 大多数情况下, 我们不需要修改它的配置信息
Eureka客户端的配置主要分为以下两个方面:
- 服务注册相关的配置信息, 包括服务注册中心的地址、 服务获取的间隔时间、 可用区域等
- 指定注册中心:
eureka.client.serviceUrl.defaultZone=http://localhost:llll/eureka/ #构建了高可用的服务注册中心集群 eureka.client.serviceUrl.defaul七Zone=http://peerl: 1111/eureka/, http:/ /peer2: 111 2/eureka/
- 其他配置:
参数名 说明 默认值 enabled 启用Eureka客户端 true registryFetcl让ntervalSeconds 从Eureka服务端获取注册信息的间隔时间,单位为秒 30 instancelnfoReplicationlnterva!Seconds 更新实例信息的变化到E田eka服务端的间隔时间, 单位为秒 30 in I tiallnstancelnfoRep I icationintervalSeconds 初始化 实例信息到 Eureka 服务端的间隔时间, 单位为秒 40 eurekaServiceUrlPolllntervalSeconds 轮询Eureka服务端地址更改的间隔时间, 单位为秒。 当我们与Spring Cloud Config配合,动态刷新Eureka的serv1ceURL地址时需要关注该参数 300 eurekaServerReadTimeoutSeconds 读取Eureka Se1-ver信息的超时时间, 单位为秒 8 eurekaServerConnectTimeoutSeconds 连接 Eureka Server的超时时间, 单位为秒 5 eurekaServerTotalConnections 从Eureka客户端到所有Eureka服务端的连接总数 200 eurekaServerTotalConnectionsPerHost 从Eureka客户端到每个Eureka服务端主机的连接总数 50 eurekaConnectionldleTimeoutSeconds Eureka服务端 连接的空闲关闭时间, 单位为秒 30 heartbeatExecutorT缸eadPoolSize 心跳连接池的初始化线程数 2 heartbeatExecutorExponentta!BackOffBound 心跳超时重试延迟时间的最大乘数值 10 cacheRefresl让xecutorThreadPoolS1ze 缓存刷新线程池的初始化线程数 2 cacheRefreshExecutorExponentialBackOffBound 缓存刷新重试延迟时间的最大乘数值 10 useDnsForFetchmgServ1ceUrls 使用DNS来获取Eureka服务端的serviceUri false registerWitl也ureka 是否要将自身的实例信息 注册到Eureka服务端 true preferSameZoneEureka 是否偏好使用处于相同Zone的Eureka服务端 true fi lterOnlyUplnstances 获取实例 时是否过滤, 仅保留UP状态的实例 true fetchRegistry 是否从Eureka服务端获取注册信息 true
- 服务实例相关的配置信息, 包括服务实例的名称、IP地址、 端口号、 健康检查路径等
- 元数据:它是Eureka 客户端在向服务注册 中心发送注册请求时, 用来描述自身服务信息的对象, 其中包含了一些标准化的元数据, 比如 服务名称、 实例名称、 实例IP、 实例端口等用于服务治理的重要信息;以及一些用 千负载均衡策略或是其他特殊用途的自定义元数据信息
- 实例名配置:实例名, 即Instance工nfo 中的instanceI d参数, 它是区分同 一 服务 中不同实例的唯一 标识
eureka.ins七ance.instanceid=${spring.applica七ion.name}:${random.int}}
- 健康检测:默认情况下,Eureka中各个服务实例的健康检测并不是通过spring-boot-actuator模块的/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 3 如果客户端的/health端点路径做了 一 些特殊处理,请参考前文介绍端点配置时的方法进行配置, 让服务注册中心可以正确访问到健康检测端点
- 其他配置:
参数名 说明 默认值 preferlpAddres 是否优先使用IP地址作为主机名的标识 false leaseRenewallntervallnSeconds Eureka客户端向服务端发送心跳的时间间隔, 单位为秒 30 leaseExpirationDurationlnSeconds Eureka服务端在收到砓后 一次心跳之后等待的时间上限,单位为秒。 超过该时间之后服务端会将该服务实例从服务消单中剔除, 从而禁止服务调用请求被发送到该实例上 90 nonSecurePort 非安全的通信端口号 80 securePort 安全的通信端口号 443 nonSecurePotiEnabled 是否启用非安全的通信端口号 true securePortEnabled 是否启用安全的通信端口号 appname 服务名,默认取spring.app巨ca巨on.name的配置值,如果没有则为unknown hostname 主机名, 不配置的时候将根据操作系统的主机名来获取
不积跬步,无以至千里;不积小流,无以成江海