在微服务架构中,各微服务实例的一个重要能力就是可以快速上线或下线,进行水平扩展,并保证服务的可用性。如何保持服务消费者能够与不断上下线的服务进行正常通信,就需要依靠服务治理。

服务治理通过抽象将服务提供者与服务消费者进行隔离。消费者不需要知道具体服务提供者的真是地址,也不需要知道有多少个服务提供者可用;而服务提供者只需要将自己注册到服务治理服务器中即可;同时服务治理服务器能够发现并绕开有问题的服务实例,降低对应用的影响。Eureka提供相应的解决方案,主要包括三个概念:服务注册中心、服务提供者和服务消费者。

  • 服务注册中心:负责服务列表的注册、维护和查询等功能,即Eureka Server;
  • 服务提供者:Eureka Client,负责将微服务所提供的服务向Eureka
    Server进行注册,以 便服务消费者可以发现并进行消费;
  • 服务消费者:也是一个Eureka Client,启动时默认从Eureka Server中获取所有的服务注册表信息,根据需要消费相应的服务。

在实际调用过程中,一个服务消费者可能会调用多个服务提供者,同时也可能会作为服务提供者对外提供服务。

以下简单介绍如何搭建Eureka注册中心和服务注册,依赖Spring Boot 2.1.4.RELEASE和Spring Cloud Greenwich.SR1。

一、Eureka服务器

1.创建一个eureka_server的springboot项目

pom.xml文件如下:

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

  <groupId>com.kevin</groupId>
  <artifactId>eureka_server</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>eureka_server</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.4.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
  </dependencies>
  
  <dependencyManagement>
    <dependencies>
        <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-dependencies</artifactId>
           <version>Greenwich.SR1</version>
           <type>pom</type>
           <scope>import</scope>
        </dependency>
    </dependencies>
  </dependencyManagement>
</project>

2. application.properties

spring.application.name=eurekaServer
server.port=9101
eureka.instance.hostname=localhost

eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false

备注:registerWithEureka=false和fetchRegistry=false来表明自己是一个eureka server.

3. Application.java

package com.kevin.eureka_server;

import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class Application {
	
    public static void main( String[] args ) {
    	new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
    }
}

4. 启动访问http://127.0.0.1:9101/,可以看到Eureka Server管理后台
在这里插入图片描述

二、Eureka服务注册(eureka client)
1. 创建一个eureka_client的springboot项目,pom.xml如下:

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

  <groupId>com.kevin</groupId>
  <artifactId>eureka_client</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>eureka_client</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.4.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
  </dependencies>
  
  <dependencyManagement>
    <dependencies>
        <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-dependencies</artifactId>
           <version>Greenwich.SR1</version>
           <type>pom</type>
           <scope>import</scope>
        </dependency>
    </dependencies>
  </dependencyManagement>
</project>

2. application.properties

# 此处name一定不能有下划线,否则注册的服务不能被消费
spring.application.name=eurekaClient
server.port=9103

3. Application.java,@EnableDiscoveryClient能够让注册中心能够发现和扫描到该服务;也可使用@EnableEurekaClient,但其只支持Eureka不支持其他注册中心。

@SpringBootApplication
@EnableDiscoveryClient
public class Application {
	
    public static void main( String[] args ) {
    	new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
    }
}

4. 创建一个rest api, HelloController.java

@RestController
public class HelloController {
	
	@RequestMapping("sayHello")
	public String sayHello() {
		System.out.println("收到请求");
		return "Hello World";
	}
}

5. 通过修改端口启动两个服务,查看服务器中已注册两个服务
在这里插入图片描述

6. 自我保护机制
1)Eureka服务器出现提示: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 Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。
自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:
1、Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
2、Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
3、当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。

解决方案:(适用于开发环境,生产环境不建议调整)
1、 EurekaServer注册中心关闭自我保护机制,修改检查失效服务的时间。

#关闭自我保护机制,保证不可用服务及时剔除
eureka.server.enable-self-preservation=false
#间隔3秒剔除
eureka.server.eviction-interval-timer-in-ms: 3000

2、EurekaClient修改减短服务心跳的时间。

#在收到最后一次心跳后等待的时间上限,超过则剔除,默认90秒
eureka.instance.lease-expiration-duration-in-seconds=10
#向注册中心发送心跳的时间间隔,默认30秒
eureka.instance.lease-renewal-interval-in-seconds=3

7. Eureka’s Health Checks健康检查
默认情况下,服务器端与客户端的心跳保持正常,应用程序就会始终保持“UP”状态,但是该机制并不能完全反应应用程序的状态。比如:微服务与Eureka Server的心跳正常,但是该微服务的数据源发生了问题(比如网络抖动,连不上数据源),根本无法正常工作。

可自定义实现更细粒度地控制健康检查。
1)开启健康检查

eureka.client.healthcheck.enabled=true

2)依赖springboot的actuator,pom.xml引入相关jar包

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

3)做完上面两步后重新注册服务,服务地址点击查看就不报异常了
在这里插入图片描述
在这里插入图片描述

4)实现springboot的healthcheck,HealthCheckIndicator .java根据需要自行检查并返回结果

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Status;
import org.springframework.stereotype.Component;

@Component
public class HealthCheckIndicator implements HealthIndicator{

	@Override
	public Health health() {
		return new Health.Builder(Status.UP).build();
	}
	
}

5)实现服务的健康检查,HealthCheckStatusHandler.java根据springboot的健康结果返回

package com.kevin.eureka_client.component.healthcheck;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Status;
import org.springframework.stereotype.Component;

import com.netflix.appinfo.HealthCheckHandler;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;


@Component
public class HealthCheckStatusHandler implements HealthCheckHandler{
	
	@Autowired
	private HealthCheckIndicator healthCheckIndicator;
	
	@Override
	public InstanceStatus getStatus(InstanceStatus instanceStatus) {
		Status status=healthCheckIndicator.health().getStatus();
		if(Status.UP.equals(status)) {
			return InstanceStatus.UP;
		}else {
			return InstanceStatus.DOWN;
		}
	}

}

6)Eureka服务器会定时检查Eureka Client的健康状态,可以通过debug断点查看是否进入自定义的健康检查;通过/actuator/health可以查看服务状态

在这里插入图片描述
在这里插入图片描述
8. Spring Cloud Eureka 常用配置详解
Spring Cloud Eureka 主要分为下面三个模块的参数:
Eureka Server
Eureka Client
Eureka Instance

1) Eureka Server
Eureka Server 的配置参数格式:eureka.server.xxx
enable-self-preservation 表示注册中心是否开启服务的自我保护能力。
renewal-percent-threshold 表示 Eureka Server 开启自我保护的系数,默认:0.85。
eviction-interval-timer-in-ms 表示 Eureka Server 清理无效节点的频率,默认 60000 毫秒。

更多 Eureka Server 参数配置可以看一下这个类:org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean

2)Eureka Client
Eureka Client 的配置参数格式:eureka.client.xxx
register-with-eureka 表示此实例是否注册到 Eureka Server 以供其他实例发现。在某些情况下,如果你不想自己的实例被发现,而只想发现其他实例,配置为 false 即可。
fetch-registry 表示客户端是否从 Eureka Server 获取实例注册信息。
serviceUrl.defaultZone 表示客户端需要注册的 Eureka Server 的地址。

更多 Eureka Client 参数配置可以看一下这个类:
org.springframework.cloud.netflix.eureka.EurekaClientConfigBean

3)Eureka Instance
Eureka Instance 的配置参数格式:eureka.instance.xxx
instance-id 表示实例在注册中心注册的唯一ID。
prefer-ip-address
true:实例以 IP 的形式注册
false:实例以机器 HOSTNAME 形式注册
lease-expiration-duration-in-seconds 表示 Eureka Server 在接收到上一个心跳之后等待下一个心跳的秒数(默认 90 秒),若不能在指定时间内收到心跳,则移除此实例,并禁止此实例的流量。
此值设置太长,即使实例不存在,流量也能路由到该实例
此值设置太小,由于网络故障,实例会被取消流量
需要设置为至少高于 lease-renewal-interval-in-seconds 的值,不然会被误移除了。

lease-renewal-interval-in-seconds 表示 Eureka Client 向 Eureka Server 发送心跳的频率(默认 30 秒),如果在 lease-expiration-duration-in-seconds 指定的时间内未收到心跳,则移除该实例。

更多 Eureka Instance 参数配置可以看一下这个类:
org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean

参考:
https://cloud.spring.io/spring-cloud-static/Greenwich.SR1/single/spring-cloud.html#spring-cloud-eureka-server

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐