服务调用出现的问题
- 服务消费者如何获取服务提供者的地址信息?
- 如果有多个服务提供者,消费者该如何选择?
- 消费者如何得知服务提供者的健康状态?
eureka 的作用
服务注册中心是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者的作用,主要包含如下几个功能:
- 服务消费者如何获取服务提供者的地址信息?
- 服务提供者启动时向 Eureka 注册自己的信息
- eureka 保存这些信息
- 消费者根据服务名称向 eureka 拉取提供者信息
- 如果有多个服务提供者,消费者该如何选择?
- 服务消费者利用负载均衡算法,从服务列表中挑选一个
- 消费者如何得知服务提供者的健康状态?
- 服务提供者会每隔 30 秒向 EurekaServer 发送心跳请求,报告健康状态
- Eureka 会更新记录服务列表信息,心跳不正常会被剔除
- 消费者可以拉取到最新的消息
Eureka架构
Eureka架构图
该图是Eureka集群的工作原理。各个节点的名词解释:
- Application Service:服务提供者
- Application Client:服务消费者
- Make Remote Call:调用RESTful API的行为
- us-east-1c、us-east-1d 都属于 us-east-1 这个集群
Eureka 包含两个组件:Eureka Server 和 Eureka Client。
- Eureka Server:服务端,注册中心
- 记录服务信息
- 心跳检测
- Eureka Client:客户端
- Provider:服务提供者
- 注册自己的信息到 Eureka Server
- 每隔 30 秒向 Eureka Server 发送心跳
- Consumer:服务消费者
- 根据服务名称从 EurekaServer 拉取服务列表
- 根据服务列表做负载均衡,选中一个微服务后发起远程调用
- Provider:服务提供者
Eureka 案例
步骤:
- 搭建 EurekaServer
- 引入 eureka-server 依赖
- 添加 @EnableEurekaServer 注解
- 在 application.yml 中配置 eureka 地址
- 微服务注册到 Eureka Server
- 引入 eureka-client 依赖
- 在 application.yml 中配置 eureka 地址
搭建 Eureka Server
项目地址:传送门
- 创建工程,引入 spring-cloud-starter-netflix-eureka-server 的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- 编写启动类,添加@EnableEurekaServer注解,声明这是一个Eureka Server
//激活Eureka Server端配置
@EnableEurekaServer
- 配置application.yml
server:
port: 8080
eureka:
instance:
hostname: localhost
client:
# registerWithEureka: 是否将自己注册到Eureka服务中,默认为true,由于当前项目本身就是Eureka Server所以无需注册
register-with-eureka: false
# fetchRegistry : 是否从Eureka中获取注册信息,默认为true,楼主这里搭建的是单点的Eureka Server,不是集群,所以设为false
fetch-registry: false
service-url:
# serviceUrlEureka: 客户端与Eureka服务端进行交互的地址,多个地址可使用,分割
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
application:
name: chenfu-eureka
微服务注册到 Eureka Server
- 在项目中引入Eureka Client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 修改application.yml添加Eureka Server信息
spring:
application:
# 指定注册到Eureka Server上的应用名称
name: chenfu-client
server:
port: 8082
eureka:
client:
service-url:
defaultZone: http://localhost:8080/eureka/
instance:
# 使用IP注册,如不配置或设为false,则表示将微服务所在操作系统的hostname注册到Eureka Server
prefer-ip-address: true
- 修改启动类,添加服务发现支持(可选)
//@EnableDiscoveryClient
//@EnableEurekaClient
从Spring Cloud Edgware版本开始,@EnableDiscoveryClient 或@EnableEurekaClient可省略。只需加上相关依赖,并进行相应配置,即可将微服务注册到服务发现组件上。
注意 @EnableEurekaClient 是 spring-cloud-netflix 项目的注解,只能与Eureka一起工作,选用了别的服务发现组件,如Zookeeper、Consul等就无效了,而@EnableDiscoveryClient都支持。
Eureka中的自我保护
微服务第一次注册成功之后,每30秒会发送一次心跳将服务的实例信息注册到注册中心,通知 Eureka Server 该实例仍然存在。如果超过90秒没有发送更新,则服务器将从注册信息中将此服务移除。Eureka Server在运行期间,会统计心跳失败的客户端比例在15分钟之内是否低于85%,如果出现低于的情况 (在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),Eureka Server 就会将当前的实例注册信息保护起来,不再删除服务注册表中的数据(不注销任何微服务)同时提示这个警告。当网络故障修复后,该Eureka Server节点会自动退出自我保护模式。使用自我保护机制,可以让Eureka集群更加健壮、稳定。
注意:在验证完自我保护机制开启后,并不会马上呈现到web上,而是默认需等待 5 分钟(可以通过 eureka.server.wait-time-in-ms-when-sync-empty
配置),也可以通过eureka.server.enable-self-preservation=false
禁用自我保护。
Eureka中的元数据
Eureka的元数据有两种:标准元数据和自定义元数据
- 标准元数据:主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注 册表中,用于服务之间的调用
- 自定义元数据:可以使用eureka.instance.metadata-map配置,符合KEY/VALUE的存储格式。这些元数据可以在远程客户端中访问
在程序中可以使用DiscoveryClient 获取指定微服务的所有元数据信息
@Autowired
private DiscoveryClient discoveryClient;
public void test() {
//根据微服务名称从注册中心获取相关的元数据信息
List<ServiceInstance> instances = discoveryClient.getInstances("serviceId");
}
Eureka中的常见问题
服务注册慢
默认情况下,服务注册到Eureka Server的过程较慢,因为服务的注册涉及到心跳,默认心跳间隔为30s。在实例、服务器、客户端都在本地缓存中具有相同的元数据之前,服务不可用于客户端发现(所以可能需要3次心跳)。可以通过配置 eureka.instance.leaseRenewalIntervalInSeconds
(心跳频率)加快客户端连接到其他服务的过程。在生产中,最好坚持使用默认值,因为在服务器内部有一些对续约的计算。
服务节点剔除问题
默认情况下,由于Eureka Server剔除失效服务间隔时间为90s且存在自我保护的机制。所以不能有效而迅速的剔除失效节点,这对开发或测试会造成困扰。解决方案如下
– Eureka Server:
配置关闭自我保护,设置剔除无效节点的时间间隔
eureka:
instance:
hostname: eureka1
client:
service-url:
defaultZone: http://eureka2:8762/eureka
server:
enable-self-preservation: false #关闭自我保护
eviction-interval-timer-in-ms: 4000 #剔除时间间隔,单位:毫秒
– Eureka Client:
配置开启健康检查,并设置续约时间
eureka:
client:
healthcheck: true #开启健康检查(依赖spring-boot-actuator)
serviceUrl:
defaultZone: http://eureka1:8761/eureka/,http://eureka1:8761/eureka/
instance:
preferIpAddress: true
lease-expiration-duration-in-seconds: 10 #eureka client发送心跳给server端后,续 约到期时间(默认90秒)
lease-renewal-interval-in-seconds: 5 #发送心跳续约间隔
监控页面显示ip
在Eureka Server的管控台中,显示的服务实例名称默认情况下是微服务定义的名称和端口。为了更好的对所有服务进行定位,微服务注册到Eureka Server的时候可以手动配置示例ID。配置方式如下
eureka:
instance:
#spring.cloud.client.ip-address:获取ip地址
instance-id: ${spring.cloud.client.ip-address}:${server.port}