Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务治理。在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
在springboot项目中使用Eureka十分简单,只需要以下几步就可以启动一个server了。
pom文件中添加依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
修改yml文件
server:
port: 8610
spring:
application:
name: datax-eureka
eureka:
instance:
lease-renewal-interval-in-seconds: 20
lease-expiration-duration-in-seconds: 60
# 设置使用IP
prefer-ip-address: true
# 设置外网IP号
ip-address: localhost
client:
register-with-eureka: false
fetch-registry: false
instance-info-replication-interval-seconds: 40
service-url:
defaultZone: http://${eureka.instance.ip-address}:${server.port}/eureka/
启动类添加@EnableEurekaServer注解
@EnableEurekaServer
@SpringBootApplication
public class DemoEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(DataxEurekaApplication.class, args);
}
}
浏览器访问http://127.0.0.1:8610/可以看到一个简单的EurekaServer已经搭建成功了
过了一段时间出现了提示:EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
出现这个错误的原因是因为Eureka进入自我保护模式
默认情况下,如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障(比如网络故障或频繁的启动关闭客户端),Eureka Server自动进入自我保护模式。不再剔除任何服务,当网络故障恢复后,该节点自动退出自我保护模式。
可以使用eureka.server.enable-self-preservation=false来禁用自我保护模式,生产环境不建议这么做。
还有一种方式是把阈值因子eureka.server.renewalPercentThreshold调低,默认是0.85,如果阈值比最小值大,则自我保护模式开启
eureka:
server:
enable-self-preservation: true
#eureka server清理无效节点的时间间隔,默认60000毫秒,即60秒
eviction-interval-timer-in-ms: 60000
#阈值更新的时间间隔,单位为毫秒,默认为15 * 60 * 1000
renewal-threshold-update-interval-ms: 15 * 60 * 1000
#阈值因子,默认是0.85,如果阈值比最小值大,则自我保护模式开启
renewal-percent-threshold: 0.85
#清理任务程序被唤醒的时间间隔,清理过期的增量信息,单位为毫秒,默认为30 * 1000
delta-retention-timer-interval-in-ms: 30000
默认情况下,Eureka使用客户端心跳来确定客户端是否已启动。在成功注册后,Eureka始终宣布应用程序处于“UP”状态,这就引发一个问题,客户端虽然是启动的,但是可能由于某种原因(比如数据库宕机)无法提供正确的服务。为了解决这个问题,需要引入健康检查机制。
前置条件:启动一个server(本文端口为8610),下面开始创建client(端口为8611)
Eureka的健康检查依赖于Springboot-actuator的/health,需要在pom.xml中引入spring-boot-starter-actuator模块的依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
在eureka客户端中的application.properties或yml文件中配置:eureka.client.healthcheck.enabled=true,就可以改变eureka server对客户端健康检测的方式,改用actuator的/actuator/health端点来检测。
# 注册中心配置
eureka:
instance:
lease-renewal-interval-in-seconds: 20
# 设置使用IP
prefer-ip-address: true
# 设置外网IP号
ip-address: localhost
client:
healthcheck:
enabled: true
register-with-eureka: true
fetch-registry: true
instance-info-replication-interval-seconds: 30
registry-fetch-interval-seconds: 3
service-url:
defaultZone: http://localhost:8610/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
新建HealthIndicatorImpl 并实现HealthIndicator,自定义监控的逻辑。
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class HealthIndicatorImpl implements HealthIndicator {
private boolean up = true;
@Override
public Health health() {
if (up) {
return new Health.Builder().withDetail("status", "up").up().build(); //自定义监控内容
} else {
return new Health.Builder().withDetail("error", "client is down").down().build();
}
}
public boolean isUp() {
return up;
}
public void setUp(boolean up) {
this.up = up;
}
}
在启动类上添加注解@EnableDiscoveryClient 或@EnableEurekaClient(@EnableEurekaClient只适用于Eureka作为注册中心,@EnableDiscoveryClient 可以是其他注册中心)
客户端启动后,sever端显示客户端服务状态为UP
访问http://127.0.0.1:8611/actuator/health 查看客户端状态
{
"status": "UP",
"components": {
"configServer": {
"status": "UP",
"details": {
"repositories": [
{
"name": "app",
"profiles": [
"default"
],
"label": null
}
]
}
},
"discoveryComposite": {
"status": "UP",
"components": {
"discoveryClient": {
"status": "UP",
"details": {
"services": [
"datax-config"
]
}
},
"eureka": {
"description": "Remote status from Eureka server",
"status": "UP",
"details": {
"applications": {
"DATAX-CONFIG": 1
}
}
}
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 107373129728,
"free": 6842404864,
"threshold": 10485760,
"exists": true
}
},
"healthIndicatorImpl": {
"status": "UP",
"details": {
"status": "up"
}
},
"hystrix": {
"status": "UP"
},
"ping": {
"status": "UP"
},
"refreshScope": {
"status": "UP"
}
}
}
为了方便模拟,创建个controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HealthController {
@Autowired
private HealthIndicatorImpl myHealthChecker;
@RequestMapping("/up")
public String up(@RequestParam("up") Boolean up) {
myHealthChecker.setUp(up);
return myHealthChecker.isUp() ? "UP" : "DOWN";
}
}
访问http://127.0.0.1:8611/up?up=false更改客户端状态, server端可以看到状态由UP变为DOWN了。