天天看点

Spring Cloud(Finchley.RELEASE版本)微服务学习实践:2.2服务提供方及健康检查设置-Eureka Discovery

环境:

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

Spring Cloud(Finchley.RELEASE版本)微服务学习实践:2.2服务提供方及健康检查设置-Eureka Discovery

访问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

4.源码地址

github地址:https://github.com/cc6688211/springCloud.git

继续阅读