环境:
jdk1.8;spring boot2.0.3;spring cloud(Finchley.RELEASE版本);Maven3.3
摘要说明:
Eureka instance:一个服务,如:个人中心,会部署多台服务器,而每台服务器上提供的服务就是instance; 负载配置。
Eureka service:指的是服务,提供一种特定功能的服务,如:个人中心,而同一个服务可以提供多个instance;
Eureka client:主要将自己的服务注册到服务中心。但它既可以是服务的提供者也可以是消费者。它与Eureka instance感觉差不多,但其实意义是不一样的,Eureka client是相较于Eureka server来说的。而Eureka instance更倾向于负载技术。
Eureka server:服务注册中心。并管理各服务的中心。
注册中心保护机制:默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。
官方对于自我保护机制的定义:https://github.com/Netflix/eureka/wiki/Understanding-Eureka-Peer-to-Peer-Communication
总结:自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。
自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:
1、Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
2、Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
3、当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。
但实际情况下这种保护机制一定程度也影响了业务操作;若实际失败提供者也不会被注销,负载均衡也会调运这些失败的情况;且实际上网络异常的情况下还是极少的
步骤:
1.常用健康检查方式
配置注册中心
#——————————————添加健康检查——————————————
# 该配置可以移除这种自我保护机制,防止失效的服务也被一直访问 (Spring Cloud默认该配置是 true)
eureka.server.enable-self-preservation=true
# 该配置可以修改检查失效服务的时间,每隔10s检查失效服务,并移除列表 (Spring Cloud默认该配置是 60s)
eureka.server.eviction-interval-timer-in-ms=5000
配置服务提供者:
# 该配置指示eureka客户端需要向eureka服务器发送心跳的频率 (Spring Cloud默认该配置是 30s)
eureka.instance.lease-renewal-interval-in-seconds=1
# 该配置指示eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 (Spring Cloud默认该配置是 90s)
eureka.instance.lease-expiration-duration-in-seconds=10
通过上述配置,服务提供者每1秒向注册中心发送心跳,且告知注册中心接收到最后一个心跳10秒后移除该服务;注册中心会每10秒扫描下失效的服务列表并将其移除;
2.自定义健康检查方式
a.构建eurekaDiscoveryHealth
通过SPRING INITIALIZR
工具选择Ops:Actuator模块构建eurekaDiscoveryHealth子项目引入依赖(pom.xnl):
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>pers.cc</groupId>
<artifactId>springCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>eurekaDiscoveryHealth</artifactId>
<name>eurekaDiscoveryHealth</name>
<description>服务提供者自定义健康检查</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
b.配置eurekaDiscoveryHealth
使用@EnableDiscoveryClient注解开启enableDiscoveryClient的服务提供方配置:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class EurekaDiscoveryHealthApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaDiscoveryHealthApplication.class, args);
}
}
配置application.properties
#配置服务名称及端口
spring.application.name=eureka-client-health
server.port=2102
#将服务注册到注册中心
eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/
#——————————————添加健康检查配置——————————————
# 该配置指示eureka客户端需要向eureka服务器发送心跳的频率 (Spring Cloud默认该配置是 30s)
eureka.instance.lease-renewal-interval-in-seconds=1
# 该配置指示eureka服务器在接收到最后一个心跳之后等待的时间,然后才能从列表中删除此实例 (Spring Cloud默认该配置是 90s)
eureka.instance.lease-expiration-duration-in-seconds=10
# 开启自定义健康检查
eureka.client.healthcheck.enabled=true
c.开发eurekaDiscoveryHealth
自定义HealthIndicator:
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class MyHealthIndicator implements HealthIndicator {
private boolean up = true;
@Override
public Health health() {
if (up) {
return new Health.Builder().withDetail("aaa_cnt", 10) // 自定义监控内容
.withDetail("bbb_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;
}
}
开发HealthController和TestController用于测试
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;
import pers.cc.eurekaDiscoveryHealth.component.MyHealthIndicator;
@RestController
public class HealthController {
@Autowired
MyHealthIndicator myHealthIndicator;
@RequestMapping("/up")
public String up(@RequestParam("up") Boolean up) {
myHealthIndicator.setUp(up);
return up.toString();
}
}
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Autowired
DiscoveryClient discoveryClient;
@GetMapping("/dc")
public String dc() {
String services = "Services: " + discoveryClient.getServices() + new Date().getTime();
System.out.println(services);
return services;
}
@GetMapping("/add")
public Integer add(@RequestParam Integer a, @RequestParam Integer b) {
System.out.println(a + b);
return a + b;
}
@GetMapping("/stop")
public String stop() throws InterruptedException {
System.out.println("stop");
Thread.sleep(5000L);
return "stop";
}
}
在ribbon下的TestController上添加测试方法
@RequestMapping(value = "/test1", method = RequestMethod.GET)
public String test1() {
return restTemplate.getForEntity("http://EUREKA-CLIENT-HEALTH/dc", String.class).getBody();
}
d.测试eurekaDiscoveryHealth
先后启动
服务注册中心(eurekaServer):eureka-server(1001)
服务提供者(eurekaDiscoveryHealth):eureka-client-health(2101)
服务提供者(eurekaDiscoveryHealth):eureka-client-health(2102)
服务消费者(ribbon):ribbon-consumer(3001)
通过http://localhost:2101/up?up=false将eureka-client-health(2101)变成down
访问http://localhost:3001/test1可以通过控制台看到eureka-client-health(2101)无日志打印;全部打到eureka-client-health(2102)上;
访问http://localhost:2101/dc仍可访问;
3.更多Spring Cloud Eureka配置
请参考http://blog.51cto.com/881206524/2117014