微服务注册与发现

微服务注册与发现

服务发现简介

通过前文的讲解,我们知道硬编码提供者地址的方式有不少问题。想要解决这些问题,服务消费者需要一个强大的服务发现机制,服务消费者使用这种机制获取服务提供者的网络信息。不仅如此,即使服务提供者的信息发生变化,服务消费者也无需修改配置文件。
服务提供者、服务消费者、服务发现组件这三者之间的关系大致如下:

  • 各个微服务在启动时,将自己的网络地址等信息注册到服务发现组件中,服务发现组件会存储这些信息。
  • 服务消费者可从服务发现组件查询服务提供者的网络地址,并使用该地址调用服务提供者的接口。
  • 各个微服务与服务发现组件使用一定机制(例如心跳)通信。服务发现组件若长时间无法与某微服务实例通信,就会注销该实例。
  • 微服务网络地址发生变更(例如实例增删或者IP端口发生变化等)时,会重新注册到服务发现组件。使用这种方式,服务消费者就无须人工修改提供者的网络地址了。
    综上,服务发现组件应具备以下功能。
  • 服务注册表:是服务发现组件的核心,它用来记录各个微服务的信息,例如微服务的名称、IP、端口等。服务注册表提供查询API和管理API,查询API用于查询可用的微服务实例,管理API用于注册和注销。
  • 服务注册与服务发现:服务注册是指微服务在启动时,将自己的信息注册到服务发现组件上的过程。服务发现是指查询可用微服务列表及其网络地址的机制。
  • 服务检查:服务发现组件使用一定机制定时检测已注册的服务,如发现某实例长时间无法访问,就会从服务注册表中移除该实例。
    综上,使用范围发现的好处是显而易见的。Spring Cloud提供了多种服务发现组件的支持,例如Eureka、Consul和ZooKeeper等。
    注:目前市面上书籍中所提到的服务注册、服务发现或注册中心等名词,多数场景下都可理解为服务发现组件。服务发现的方式可细分为服务器端发现和客户端发现。

Eureka简介

Eureka是Netflix开源的服务发现组件,本身是一个基于REST的服务。它包含Server和Client两部分。Spring Cloud将它集成在子项目Spring Cloud Netflix中,从而实现微服务的注册与发现。

Eureka原理

在分析Eureka的原理之前,先来了解一下Region和Availability Zone。
Region和AvailabilityZone均是AWS的概念。其中Region表示AWS中的地理位置,每个Region都有多个AvailabilityZone,各个Region之间完全隔离。AWS通过这种方式实现了最大的容错和稳定性。
Spring Cloud默认使用的Region是us-east-1,在非AWS环境下,可以将Availability Zone理解为机房,将Region理解为跨机房的Eureka集群。
在这里插入图片描述

  • Application Service:相当于本书中的服务提供者。
  • Application Client:相当于本书中的服务消费者。
  • Make Remote Call:可以理解成调用RESTful API的行为。
  • us-east-1c、us-east-1d等都是zone,它们都属于us-east-1这个region。
    Eureka包含两个组件:Eureka Server和Eureka Client,它们的作用如下:
  • Eureka Server提供服务发现的能力,各个微服务启动时,会向Eureka Server注册自己的信息(例如IP、端口、微服务名称等),Eureka Server会存储这些信息。
  • Eureka Client是一个Java客户端,用于简化与Eureka Server的交互。
  • 微服务启动后,会周期性(默认30s)地向Eureka Server发送心跳以续约自己的"租期"。
  • 如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将注销该实例(默认90s)。
  • 默认情况下,Eureka Server同时也是Eureka Client。多个Eureka Server实例互相之间通过复制的方式来实现服务注册表中数据的同步。
  • Eureka Client会缓存服务注册表中的信息。这种方式有一定的优势——首先,微服务无须每次请求都查询Eureka Server,从而降低了Eureka Server的压力;其次,即使Eureka Server所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者并完成调用。
    综上,Eureka通过心跳检查、客户端缓存等机制,提高了系统的灵活性、可伸缩性和可用性。

编写Eureka Server

1)创建一个空项目chapter04。
2)在项目下创建一个Modules,Artifact是microservice-discovery-eureka的Spring Initializr项目。选择web和eureka依赖

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>microservice-discovery-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>microservice-discovery-eureka</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3)修改启动类,在启动类添加@EnableEurekaServer注解,声明这是一个Eureka Server。

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class MicroserviceDiscoveryEurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(MicroserviceDiscoveryEurekaApplication.class, args);
    }

}

4)在配置文件application.yml中添加以下内容

server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url: 
      defaultZone: http://localhost:8761/eureka/
  • eureka.client.register-with-eureka:表示十分将自己注册到Eureka Server,默认为true。由于当前应用就是Eureka Server,故而设为false。
  • eureka.client.fetchRegistry:表示是否从Eureka Server获取注册信息,默认为true。因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,故而设为false。
  • eureka.client.serviceUrl.defaultZone:设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。默认是http://localhost:8761/eureka;多个地址间可使用,分隔。
    测试
    启动Eureka Server,访问http://localhost:8761/
    在这里插入图片描述
    由图可知,Eureka Server的首页展示了很多信息,例如当前实例的系统状态、注册到Eureka Server上的服务实例、常用信息、实例信息等。显然,当前还没有任何微服务实例被注册到Eureka Server上。

将微服务注册到Eureka Server上

1)复制项目microservice-simple-provide-user,将ArtifactId修改为microservice-provider-user。
2)在pom.xml中添加以下依赖

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>microservice-provider-user</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>microservice-provider-user</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3)在配置文件application.yml中添加以下配置

spring:
  application:
    name: microservice-provider-user
eureka:
  client:
    service-url: 
      defaultZone: http://localhost:8761/eureka/
instance:
  prefer-ip-address: true

其中,spring.application.name用于指定注册到Euerka Server上的应用名称;eureka.instance.prefre-ip-address= true表示将自己的IP注册到Eureka Server。若不配置该属性或将其设置为false,则表示注册微服务或将其设置为false,则表示注册微服务所在操作系统的hostname到Eureka Server。

同理将microservice-simple-consumer-movie复制到当前目录microservice-consumer-movie

测试

  1. 启动microservice-discovery-eureka
  2. 启动microservice-provider-user
  3. 启动microservice-consumer-movie
  4. 访问http://localhost:8761/
    在这里插入图片描述
    注:在Spring Cloud Edgware之前,想要将微服务注册到Eureka Server或其他服务发现组件上,必须在启动类上添加@EnableEurekaClient或@EnableDiscoveryClient。
    在Spring Cloud Edgware以及更高版本中,只需添加相关依赖,即可自动注册。这是由于在实际项目中,我们可能希望实现"不同环境不同配置"的效果,例如:在开发环境中,不注册到Eureka Server上,而是服务提供者、服务消费者直连,便于调测;在生产环境中,我们又希望能够享受服务发现的优势——服务消费者无须知道服务提供者的绝对地址。为适应该需求,Spring Cloud Commons进行了改进。
    若不想将服务注册到Eureka Server,只需设置 spring.cloud.service-registry.auto-registration.enabled= falsse,或@EnableDiscoveryClient(autoRegister= false)即可。

Eureka Server的高可用

前面编写的单节点Eureka Server并不适合线上生产环境。Eureka Client会定时连接Eureka Server,获取服务注册表中的信息并缓存在本地。微服务在消费者远程API时总是使用本地缓存中的数据。因此一般来说,即使Eureka Server发生宕机,也会不影响服务之间的调用。但如果Eureka Server宕机时,某些微服务也出现了不可用的情况,Eureka Client中的缓存若不被更新,就可能会影响微服务的调用,甚至影响整个应用系统的高可用性。因此,在生产环境中,通常会部署一个高可用的Eureka Server集群。

编写高可用Eureka Server

Eureka Server可以通过运行多个实例并相互注册的方式实现高可用部署,Eureka Server实例会彼此增量地同步信息,从而确保所有节点数据一致。事实上,节点之间相互注册是Eureka Server地默认行为,还记得前文编写单节点Eureka Server时,额外配置了eureka.client.registerWithEureka=flase、eureka.client.fetchRegistry=false吗?
这里构建一个双节点Eureka Server集群。
1)复制项目microservice-discovery-eureka,将ArtifactId修改为microservice-discovery-eureka-ha。
在这里插入图片描述
2)配置系统的hosts,Windows系统的hosts文件路径是C:\Windows\System32\drivers\etc\hosts;liunx及Mac OS等系统的文件路径是/etc/hosts

127.0.0.1       peer1 peer2

3)将application.yml修改如下,让两个节点的Eureka Server相互注册
application.yml

spring:
  application:
    name: microservice-discovery-eureka-ha
---
spring:
     profiles: peer1
server:
  port: 8761
eureka:
  instance:
    hostname: peer1
  client:
    service-url:
      defaultZone: http://peer2:8762/eureka/
---
spring:
     profiles: peer2
server:
  port: 8762
eureka:
  instance:
    hostname: peer2
  client:
    service-url: 
      defaultZone: http://peer1:8761/eureka/

如上,使用连字符(—)将该application.yml文件分为三段。第二段和第三段分别为spring.properties指定了一个指,该值表示它所在的那段内容应用在哪个Profile里。第一段由于并为指定spring.profiles,因此这段内容会所有Profile生效。
我们定义了peer1和peer2这两个Profile。当应用以peer1这个Profile启动时,配置该Eureka Server的主机名为peer1,并将注册到http://peer2:8762/eureka/;反之,当应用以profile=peer2时,Eureka Server会注册到peer1节点的Eureka Server。
测试
1)打包项目,并使用以下命令启动两个Eureka Server节点。

java -jar microservice-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1
java -jar microservice-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2

在这里插入图片描述
在这里插入图片描述

通过spring.profiles.active指定使用哪个profile启动。
2)访问http://peer1:8761,会发现"registered-replicas"中已有peer2节点;同理,访问http://peer2:8762,也能发现其中的"registered-replicas"有peer1节点。
在这里插入图片描述
在这里插入图片描述
注:事实上,还可使用更精简的配置方式配置Eureka Server集群。

spring:
  application:
    name: microservice-discovery-eureka-ha
eureka:
  client:
    service-url:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/
---
spring:
  profiles: peer1
server:
  port: 8761
eureka:
  instance:
    hostname: peer1
---
spring:
     profiles: peer2
server:
  port: 8762
eureka:
  instance:
    hostname: peer2

将应用注册到Eureka Server集群上

以microservice-provider-user项目为例,只需修改eureka.client.serviceUrl.defaultZone,配置多个Eureka Server地址,就可以将其注册到Eureka Server集群了。

eureka:
  client:
    service-url:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/

这样就可以将服务注册到Eureka Server集群上了。
当然,微服务即使只配置Eureka Server集群中的某个节点,也能正常注册到Eureka Server集群,因为多个Eureka Server之间的数据会互相同步

eureka:
  client:
    service-url:
      defaultZone: http://peer1:8761/eureka/

用户认证

在前面的实例中,Eureka Server是运行匿名访问的,在实际项目中,可能希望必须经过用户认证才允许访问Eureka Server。

为Eureka Server添加用户认证

1)复制项目microservice-discovery-eureka,将ArtifactId修改为microservice-discovery-eureka-authentication。
2)在pom.xml中添加spring-boot-starter-security的依赖,该依赖为Rureka Server提供用户认证能力。

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

3)在application.yml中添加以下内容

security:
  basic:
    enabled: true
  user:
    name: user
    password: password123

这样就为Eureka Server添加了基于HTTP basic的认证。如果不设置这段内容,账号默认是user,密码是一个随机值,该值会在启动时打印出来。
4)将Eureka Server中的eureka.client.serviceUrl.defaultZone修改为http://user:password@EUREKA_HOST:EUREKA_PORT/eureka/的形式。

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://user:password123@localhost:8761/eureka/

测试
1)启动microservice-discovery-eureka-authenticating。
2)访问http://localhost:8761/时需要身份验证
在这里插入图片描述

将微服务注册到需认证的Eureka Server

只需修改配置文件

eureka:
  client:
    service-url:
      defaultZone: http://user:password123@localhost:8761/eureka/

对于更复杂的需求,可创建一个类型为DiscoveryClientOptionalArgs的@Bean,并向其中注入ClientFilter。
1)将之前的配置文件修改回来,保证配置文件中没有明示的密码。
2)引入依赖

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
    <version>1.19.1</version>
</dependency>

3)在需要注册的服务下创建一个config包并在其下创建一个DiscoveryConfig.java

package com.example.config;

import com.netflix.discovery.DiscoveryClient;
import com.sun.jersey.api.client.filter.ClientFilter;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class DiscoveryConfig {
    @Bean
    public DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs(){
        DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs=new DiscoveryClient.DiscoveryClientOptionalArgs();
        List<ClientFilter> additionalFilters = new ArrayList<>();
        additionalFilters.add(new HTTPBasicAuthFilter("user","password123"));
        discoveryClientOptionalArgs.setAdditionalFilters(additionalFilters);
        return discoveryClientOptionalArgs;
    }
}

这样就将用户名和密码写入了注入了Spring boot在之后访问Eureka时会自动使用。

Eureka的元数据

Eureka的元数据有两种,分别是标准元数据和自定义元数据。
标准元数据指的是主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。自定义元数据可以使用eureka.instance.meradata-map配置,这些元数据可以在远程客户端中访问,但一般不会改变客户端的行为,除非客户端知道该元数据的含义。

改造用户微服务

1)复制项目microservice-provider-user,将ArtifactId修改为microservice-provider-user-my-metadata。
2)修改application.yml,使用eureka.instance.metadata-map属性为该微服务添加应自定义的元数据。

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    metadata-map: #自定义的元数据,key/value都可以随便写
      my-metadata: 我自定义的元数据
    prefer-ip-address: true

改造电影微服务

1)复制项目microservice-consumer-movie,将ArtifacId修改为microservice-consumer-movie-understanding-metadata
2)修改Controller

package com.example.controller;

import com.example.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class MovieController {
    @Autowired
    private RestTemplate restTemplate;
    @Value("${user.userServiceUrl}")
    private String userServiceUrl;
    @Autowired
    private DiscoveryClient discoveryClient;
    @GetMapping("/user/{id}")
    public User findById(@PathVariable Long id) {
        return this.restTemplate.getForObject(this.userServiceUrl + id, User.class);
    }
    /*
    * 查询microservice-provider-user服务的信息并返回
    * @return microservice-provider-user服务的信息
    * */
    @GetMapping("/user-instance")
    public List<ServiceInstance> showInfo(){
        return this.discoveryClient.getInstances("microservice-provider-user");
    }
}

使用DiscoveryClient.getInstances(serviceId),可查询指定微服务在Eureka上的实例列表。
测试
1)启动microservice-discovery-eureka。
2)启动microservice-provider-user-my-metadata。
3)启动microservice-consumer-movie-understanding-metadata。
4)访问http://localhost:8761/eureka/apps可查看Eureka的metadata。
5)访问http://localhost:8010/user-instance,可以返回类似如下的内容

[{
	"host": "192.168.137.1",
	"port": 8000,
	"metadata": {
		"management.port": "8000",
		"my-metadata": "\\u6211\\u81EA\\u5B9A\\u4E49\\u7684\\u5143\\u6570\\u636E"
	},
	"secure": false,
	"uri": "http://192.168.137.1:8000",
	"serviceId": "MICROSERVICE-PROVIDER-USER",
	"instanceInfo": {
		"instanceId": "LA********5UB.mshome.net:microservice-provider-user:8000",
		"app": "MICROSERVICE-PROVIDER-USER",
		"appGroupName": null,
		"ipAddr": "192.168.137.1",
		"sid": "na",
		"homePageUrl": "http://192.168.137.1:8000/",
		"statusPageUrl": "http://192.168.137.1:8000/info",
		"healthCheckUrl": "http://192.168.137.1:8000/health",
		"secureHealthCheckUrl": null,
		"vipAddress": "microservice-provider-user",
		"secureVipAddress": "microservice-provider-user",
		"countryId": 1,
		"dataCenterInfo": {
			"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
			"name": "MyOwn"
		},
		"hostName": "192.168.137.1",
		"status": "UP",
		"leaseInfo": {
			"renewalIntervalInSecs": 30,
			"durationInSecs": 90,
			"registrationTimestamp": 1635325678338,
			"lastRenewalTimestamp": 1635325798241,
			"evictionTimestamp": 0,
			"serviceUpTimestamp": 1635325677755
		},
		"isCoordinatingDiscoveryServer": false,
		"metadata": {
			"management.port": "8000",
			"my-metadata": "\\u6211\\u81EA\\u5B9A\\u4E49\\u7684\\u5143\\u6570\\u636E"
		},
		"lastUpdatedTimestamp": 1635325678338,
		"lastDirtyTimestamp": 1635325677697,
		"actionType": "ADDED",
		"asgName": null,
		"overriddenStatus": "UNKNOWN"
	}
}]

可以看到,使用DiscoveryClient的API获得了用户微服务的各种信息,其中包括了标准元数据和自定义元数据。例如IP、端口等信息都是标准元数据,用于服务之间的调用;同时,自定义的元数据my-metadata,也可通过客户端查询到,但是并不会改变客户端行为。

使用Eureka Server实现轮询效果

1)在microservice-provider-user和microservice-provider-user-my-metadata下的controller中添加一个新方法

    @Value("${server.post}")
    private String post;
    @Value("${spring.application.name}")
    private String name;
    @GetMapping(value = "/whoareyou")
    public String whoAreYou(){
        return "I am "+name+",post:"+post;
    }

2)在microservice-consumer-movie-understanding-metadata下的controller中添加一个新方法。

    private int range=0;

    @GetMapping("/whoareyou")
    public String whoAreYou(){
        List<ServiceInstance> instances = this.discoveryClient.getInstances("microservice-provider-user");
        ServiceInstance serviceInstance = instances.get(range);
        String host = serviceInstance.getHost();
        int port = serviceInstance.getPort();
        range++;
        return this.restTemplate.getForObject("http://"+host+":"+port+"/whoareyou", String.class);
    }

3)启动microservice-discovery-eureka-authenticating、microservice-provider-user、microservice-provider-user-my-metadata、microservice-consumer-movie-understanding-metadata
在这里插入图片描述
4)访问localhost:8010/whoareyou
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Eureka的自我保护模式

默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务的实例的心跳,Eureka Server将注销该实例(默认为90s)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。
Eureka通过"自我保护模式"来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,Eureka Server节点会自动退出自我保护模式。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
在Spring Cloud中,可以使用eureka.server.enable-self-preservation = false禁用自我保护模式。
在这里插入图片描述

多网卡环境下的IP选择

对于多网卡的服务器,各个微服务注册到Eureka Server上的IP要如何指定呢?
指定IP在某些场景下很有用。例如某台服务器有eth0、eth1和eth2三块网卡,但是只有eth1可以被其他的服务器访问;如果Eureka Client将eth0或者eth2注册到Eureka Server上,其他微服务就无法通过这个IP调用该微服务的接口。
Spring Cloud提供了按需选择IP的能力,从而避免以上的问题。
1)忽略指定名称的网卡

spring:
	cloud:
	    inetutils:
	      ignored-interfaces: 
	        - docker0
	        - veth.*
eureka:
  instance:
    prefer-ip-address: true

2)使用正则表达式,指定使用的网络地址

spring:
	cloud:
	    inetutils:
	      preferred-networks: 
	        - 192.168
	        - 10.0
eureka:
  instance:
    prefer-ip-address: true

3)只使用站点本地地址

cloud:
    inetutils:
      use-only-site-local-interfaces: true
eureka:
  instance:
    prefer-ip-address: true

4)手动指定IP地址。在某些极端场景下,可以手动指定注册到Eureka Server的微服务IP

eureka:
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

Eureka的健康检查

在这里插入图片描述
Status一栏有个up,表示应用程序状态正常。应用状态还有其他取值,例如DOWN、OUT_OF_SERVICE、UNKNOEN等。只有标记为UP的微服务会被被请求。
Eureka Server与Eureka Client之间使用心跳机制来确定Eureka Client的状态,默认情况下,服务器端与客户端的心跳保持正常,应用程序就会始终保持UP状态。
以上机制并不能完全反映应用程序的状态。微服务与Eureka Server之间的心跳正常,Eureka Server认为微服务"UP";然而,该微服务的数据源发生了问题,根本无法正常工作。
前文说过,Spring Boot Actuator提供了/health端口,该端口可展示应用程序的健康信息。
要实现这一点,只需启用Eureka的健康检查。这样,应用程序就会将自己的健康状态传播到Eureka Server。开启的方法非常简单,只需为微服务配置以下内容,就可以开启健康检查。
引入依赖

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
eureka:
  client:
    healthcheck:
      enabled: true

某些场景下,可能希望更细粒度地控制健康检查,此时可实现com.netflix.appinfo.HealthCheckHandler接口。

  • eureka.client.healthcheck.enabled=true只能配置到application.yml中,如果配置在bootstrap.yml中,可能会导致一些不良地后果,例如应用注册到Eureka Server上的状态是UNKNOWN。

排除Jersey依赖

默认情况下,Eureka Client 使用Jersey 1.x与Eureka Server交互。
在Spring Cloud Edgware中,Jersey并非必选,我们可排除Jersey的相关依赖。此时,Spring Cloud将自动配置一个基于RestTemplate的HTTP客户端。
排除Jersey的操作方法

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-client</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey.contribs</groupId>
                    <artifactId>jersey-apache-client4</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要下载并实战 springboot 微服务项目,可以按照以下步骤进行: 1. 在任何一个网页浏览器中打开您喜欢的搜索引擎。 2. 在搜索引擎上输入“springboot 微服务项目实战下载”等相关关键词。 3. 您将看到一些网站、论坛或博客上的链接,点击其中一个链接以访问下载页面。 4. 在下载页面,您可能需要提供一些信息,例如您的电子邮件地址或注册账户等,以便开始下载。 5. 确保选择可靠和信誉良好的网站,以确保下载的项目是真实、安全且无恶意软件。 6. 点击下载按钮或链接,等待下载完成。下载时间取决于您的网络速度和文件大小。 7. 下载完成后,将文件保存到您的计算机的合适位置。您可以选择创建一个新的文件夹并将项目文件保存到其中。 8. 解压下载的项目文件(如果是压缩文件),确保您的计算机上已安装适当的解压工具,如WinRAR或7-Zip。 9. 打开解压后的项目文件夹,在其中您可能会找到一些文档、源代码、配置文件等,这些文件将帮助您开始项目实战。 10. 阅读文档并按照指导进行操作,根据您对项目的需求和要求进行相应的配置和定制。 11. 根据需要,在您的IDE(集成开发环境)中导入项目文件,并构建、编译和运行项目。 12. 接下来,您可以根据实际情况对项目进行调试、测试和部署等操作,以确保其正常运行。 通过以上步骤,您就可以下载和实战 springboot 微服务项目了。请注意,根据不同的项目和实战场景,可能会有一些特定的要求和步骤。因此,确保您在实践中参考项目文档和特定的实战指南。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值