SpringCloud系列—Spring Cloud Eureka服务注册中心

老老老JR老北
发布于 2022-7-26 17:38
浏览
0收藏

作者 | 宇木木兮
来源 |今日头条

学习目标

  1. Eureka是什么?它的作用是什么
  2. Eureka分为什么模块,以及如何部署
  3. Eureka的常见问题和常见操作
  4. Eureka集群搭建
    第1章 Eureka简介
    官网:
    https://cloud.spring.io/spring-cloud-netflix/reference/html/

1.1 Euraka介绍
Eureka是Netflix中的一个开源框架,Eureka由多个instance(服务实例)组成,这些服务实例可以分为两种:Eureka Server和Eureka Client。为了便于理解,我们将Eureka client再分为服务提供端provider和服务消费端consumer。

Eureka Server 提供服务注册和发现
服务提供方,将自身服务注册到Eureka,从而使服务消费方能够找到
服务消费方,从Eureka获取注册服务列表,从而能够消费服务
1.2 注册中心比较
1.2.1 Zookeeper
Apache Zookeeper 在设计时就紧遵CP原则,即任何时候对 Zookeeper 的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性,但是 Zookeeper 不能保证每次服务请求都是可达的。

从 Zookeeper 的实际应用情况来看,在使用 Zookeeper 获取服务列表时,如果此时的 Zookeeper 集群中的 Leader 宕机了,该集群就要进行 Leader 的选举,又或者 Zookeeper 集群中半数以上服务器节点不可用(例如有三个节点,如果节点一检测到节点三挂了 ,节点二也检测到节点三挂了,那这个节点才算是真的挂了),那么将无法处理该请求。所以说,Zookeeper 不能保证服务的可用性。

当然,在大多数分布式环境中,尤其是涉及到数据存储的场景,数据一致性应该是首先被保证的,这也是 Zookeeper 设计紧遵CP原则的另一个原因。

但是对于服务发现来说,情况就不太一样了,针对同一个服务,即使注册中心的不同节点保存的服务提供者信息不尽相同,也并不会造成灾难性的后果。

因为对于服务消费者来说,能消费才是最重要的,消费者虽然拿到可能不正确的服务实例信息后尝试消费一下,也要胜过因为无法获取实例信息而不去消费,导致系统异常要好(淘宝的双十一,京东的618就是紧遵AP的最好参照)。

当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30~120s,而且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。

在云部署环境下, 因为网络问题使得zk集群失去master节点是大概率事件,虽然服务能最终恢复,但是漫长的选举事件导致注册长期不可用是不能容忍的。

1.2.2 Eureka
Spring Cloud Netflix 在设计 Eureka 时就紧遵AP原则。

Eureka Server 也可以运行多个实例来构建集群,解决单点问题,但不同于 ZooKeeper 的选举 leader 的过程,Eureka Server 采用的是Peer to Peer 对等通信。这是一种去中心化的架构,无 master/slave 之分,每一个 Peer 都是对等的。在这种架构风格中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。每个节点都可被视为其他节点的副本。

在集群环境中如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点上,当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会在节点间进行复制(replicate To Peer)操作,将请求复制到该 Eureka Server 当前所知的其它所有节点中。

当一个新的 Eureka Server 节点启动后,会首先尝试从邻近节点获取所有注册列表信息,并完成初始化。Eureka Server 通过 getEurekaServiceUrls() 方法获取所有的节点,并且会通过心跳契约的方式定期更新。

默认情况下,如果 Eureka Server 在一定时间内没有接收到某个服务实例的心跳(默认周期为30秒),Eureka Server 将会注销该实例(默认为90秒,
eureka.instance.lease-expiration-duration-in-seconds 进行自定义配置)。

当 Eureka Server 节点在短时间内丢失过多的心跳时,那么这个节点就会进入自我保护模式。

Eureka的集群中,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

  • Eureka不再从注册表中移除因为长时间没有收到心跳而过期的服务;
  • Eureka仍然能够接受新服务注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用);
  • 当网络稳定时,当前实例新注册的信息会被同步到其它节点中;
    因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使得整个注册服务瘫痪。

1.2.3 Nacos
Nacos是阿里开源的,Nacos 支持基于 DNS 和基于 RPC 的服务发现。在Spring Cloud中使用Nacos,只需要先下载 Nacos 并启动 Nacos server,Nacos只需要简单的配置就可以完成服务的注册发现。Nacos跟eureka一样,也是走AP原则的。

Nacos除了服务的注册发现之外,还支持动态配置服务。动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。

一句话概括就是Nacos = Spring Cloud注册中心 + Spring Cloud配置中心。

1.2.4 CAP理论介绍
cap原理

P:Partition tolerance,网络分区容错。类似多机房部署,保证服务稳定性。
A: Availability,可用性。
C:Consistency ,一致性。
CAP定理:CAP三个属性对于分布式系统不同同时做到。如AP/CP/AC。SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区第2章 Eureka应用
2.1 Eureka Server部署
Eureka Server端的部署不同于Nacos-server端的部署,Nacos-server端的部署分为三种方式:

  1. 阿里大佬们已经帮我们做成了安装包了,直接下载安装包,然后配置相应的信息,再执行sh startup.sh就完事了
  2. 下载源码,然后自己编译,在启动main方法
  3. 通过docker的方式拉取并执行
    nacos-server端部署的具体细节参照Nacos应用讲义

而Eureka server端的部署实际上需要我们自己再去创建一个项目,在项目中集成Eureka的jar包,通常是
spring-cloud-starter-eureka-server包,然后再将我们自己的项目部署到服务器上去,接下来我们就来分析如果部署吧。

分为手动和自动两种方式

2.1.1 手动
1.创建springboot项目,eurekaserver-demo01

2.引包

<?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>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>eurekaserver-demo01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>eurekaserver-demo01</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>
    <dependencies>
        <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</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>

<packing>的值是jar

3.启动类

通过@EnableEurekaServer来标识该服务为Eureka Server。

@SpringBootApplication
@EnableEurekaServer
public class EurekaserverDemo01Application {
    public static void main(String[] args) {
        SpringApplication.run(EurekaserverDemo01Application.class, args);
    }

}

4.配置文件有两种: .properties和 .yml 两种文件,可以任务选一种,这里使用properties文件。

(1)applicaiton.properties文件格式如下:

server.port=8761
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8761/eureka/

(2)applicaiton.yml格式如下:

server:
	port:8761    
eureka:
  	instance:
    	hostname: localhost
  	client:
    	registerWithEureka: false
    	fetchRegistry: false
    	serviceUrl:
      		defaultZone: http://${eureka.instance.hostname}:8761/eureka/

5.工程目录如下SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区6.访问地址:http://localhost:8761/

2.1.2 自动
通过使用一个Idea自动新建一个工程

1.选择“Spring Initailizr”SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区2.选择“Eureka Server”SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区3.自动生成之后,如下目录SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区4.自动生成之后,可能还需要一些改动

(1)启动类需要添加@EnableEurekaServer。

@SpringBootApplication
@EnableEurekaServer
public class EurekaDeMoApplication {
....
}

(2)配置application.properties文件,同上面一样

5.启动访问:http://localhost:8761/

2.1.3 配置项解析

########通用配置项
# 应用名称,将会显示在Eureka界面的应用名称列
spring.application.name=config-service
# 应用端口,Eureka服务端默认为:8761
server.port=3333
########eureka.server前缀的配置项
# 是否允许开启自我保护模式,缺省:true
# 当Eureka服务器在短时间内丢失过多客户端时,自我保护模式可使服务端不再删除失去连接的客户端
eureka.server.enable-self-preservation = false
# Peer节点更新间隔,单位:毫秒
eureka.server.peer-eureka-nodes-update-interval-ms =
# Eureka服务器清理无效节点的时间间隔,单位:毫秒,缺省:60000,即60秒
eureka.server.eviction-interval-timer-in-ms = 60000
########eureka.instance前缀的配置项
# 服务名,默认取 spring.application.name 配置值,如果没有则为 unknown
eureka.instance.appname = eureka-client
# 实例ID
eureka.instance.instance-id = eureka-client-instance1
# 应用实例主机名
eureka.instance.hostname = localhost
# 客户端在注册时使用自己的IP而不是主机名,缺省:false
eureka.instance.prefer-ip-address = false
# 应用实例IP
eureka.instance.ip-address = 127.0.0.1
# 服务失效时间,失效的服务将被剔除。单位:秒,默认:90
eureka.instance.lease-expiration-duration-in-seconds = 90
# 服务续约(心跳)频率,单位:秒,缺省30
eureka.instance.lease-renewal-interval-in-seconds = 30
# 状态页面的URL,相对路径,默认使用 HTTP 访问,如需使用 HTTPS则要使用绝对路径配置,缺省:/info
eureka.instance.status-page-url-path = /info
# 健康检查页面的URL,相对路径,默认使用 HTTP 访问,如需使用 HTTPS则要使用绝对路径配置,缺省:/health
eureka.instance.health-check-url-path = /health
########eureka.client前缀
# Eureka服务器的地址,类型为HashMap,缺省的Key为 defaultZone;缺省的Value为 http://localhost:8761/eureka
# 如果服务注册中心为高可用集群时,多个注册中心地址以逗号分隔。
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
# 是否向注册中心注册自己,缺省:true
# 一般情况下,Eureka服务端是不需要再注册自己的
eureka.client.register-with-eureka = true
# 是否从Eureka获取注册信息,缺省:true
# 一般情况下,Eureka服务端是不需要的
eureka.client.fetch-registry = true
# 客户端拉取服务注册信息间隔,单位:秒,缺省:30
eureka.client.registry-fetch-interval-seconds = 30
# 是否启用客户端健康检查
eureka.client.health-check.enabled = true
#
eureka.client.eureka-service-url-poll-interval-seconds = 60
# 连接Eureka服务器的超时时间,单位:秒,缺省:5
eureka.client.eureka-server-connect-timeout-seconds = 5
# 从Eureka服务器读取信息的超时时间,单位:秒,缺省:8
eureka.client.eureka-server-read-timeout-seconds = 8
# 获取实例时是否只保留状态为 UP 的实例,缺省:true
eureka.client.filter-only-up-instances = true
# Eureka服务端连接空闲时的关闭时间,单位:秒,缺省:30
eureka.client.eureka-connection-idle-timeout-seconds = 30
# 从Eureka客户端到所有Eureka服务端的连接总数,缺省:200
eureka.client.eureka-server-total-connections = 200
# 从Eureka客户端到每个Eureka服务主机的连接总数,缺省:50
eureka.client.eureka-server-total-connections-per-host = 50

2.2 Eureka Client集成

  1. Eureka Client包括两个服务模块:Service Provider(服务提供方)和Service Consumer(服务消费方)。
  2. Eureka Client和Eureka Server目录类似, 不同点在于:
  • 启动类,使用@EnableDiscoveryClient 标识该服务为Euraka Client
  • 配置文件,需要指定Euraka Server地址和当前服务注册时的名称。
    2.2.1 服务提供端
    工程目录为

SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区1.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>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>eurekaclient-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>eurekaclient-provider</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>
    <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-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </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>

2.启动类

使用@EnalbeDiscoveryClinet标识当前服务为Euraka Client。

@SpringBootApplication
@EnableDiscoveryClient
public class EurekaclientProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaclientProviderApplication.class, args);
    }
}

3.请求函数

@RestController
public class TestController {
    @GetMapping("/query")
    public UserDto query(){
        UserDto user = new UserDto();
        user.setUserName("xiaomei");
        user.setName("小美");
        user.setSex("女");
        user.setAge(20);
        return user;
    }
}

4.配置文件

eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
server.port=8762
spring.application.name=service-provider1
eureka.instance.hostname=localhost

参数说明:

  • eureka.client.serviceUrl.defaultZone:指定Eureka Server的地址
  • spring.application.name:置在Eureka Server进行注册时,当前服务的名称。
    5.结果

查看admin页面:http://localhost:8761/,如下存在了名字为“service-prodvider1”的服务。SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区2.2.2 服务消费端
如下是客户端从Euraka Server中获取到服务的地址信息:

1.工程目录和Servie Providerder一样的。SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区为了从Euraka Server中获取服务地址信息,在上面Serice Proder工程中添加一个Controler,如下

@RestController
public class ClientController {
    @Autowired
    private DiscoveryClient discoveryClient;
    @GetMapping("/queryService")
    public ViewDto query(){
        List<ServiceInstance> instanceList = discoveryClient.getInstances("service-provider1");
        StringBuilder urls = new StringBuilder();
        for(ServiceInstance instance : instanceList){
            urls.append(instance.getHost()+":"+instance.getPort()).append(",");
        }
        ViewDto dto = new ViewDto();
        dto.setName("service-provider1");
        dto.setDescription(urls.toString());
        return dto;

    }
}

2.配置文件

eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
server.port=8673
spring.application.name=service-customer1
eureka.client.register-with-eureka=false

3.执行
http://localhost:8763/queryService ,结果为SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区4.问题:关于Servie Customer是否需要在Euraka Server中进行注册呢?

不一定。Service Customer只是从Eureka Serve中获取注册服务的地址信息,如果Service Customer 本身也是一个Service Porvider,那么此时就需要注册服务了。  SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区2.3 与OpenFeign集成应用
2.3.1 接口项目
1.创建一个Maven的quick-start项目eurekaclient-api

2.配置pom

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>eurekaclient-api</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>eurekaclient-api</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.3.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
      <version>2.2.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

3.定义接口

public interface UserService {
    @GetMapping("/users")
    String users();
    @PostMapping("/user")
    String insert(@RequestBody UserDto dto);
}

4.实体类

public class UserDto {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

5.FeignClient定义

@FeignClient("eurekaclient-provider")
public interface UserServiceClient extends UserService {
}

6.打包成jar

2.3.2 服务提供端

在eurekaclient-provider项目上改

1.配置pom,增加如下配置

<dependency>
    <groupId>com.example</groupId>
    <artifactId>eurekaclient-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

2.写接口的实现

@RestController
public class UserServiceImpl implements UserService {
    @Value("${server.port}")
    private int port;
    @Override
    public String users() {
        return "获取"+port+"端口上的Users成功";
    }
    @Override
    public String insert(UserDto userDto) {
        return port+"端口上:"+userDto.getName()+"插入成功";
    }
}

3.启动服务

2.3.3 服务消费端

在eurekaclient-customer项目上改

1.增加依赖包

<dependency>
    <groupId>com.example</groupId>
    <artifactId>eurekaclient-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<dependency><!--可以支持OKHTTP-->
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

2.在启动类上面开启OpenFeign

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.example.clients")
public class EurekaclientCustomerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaclientCustomerApplication.class, args);
    }

}

3.测试

@RestController
public class TestController {
    @Autowired
    UserServiceClient userServiceClient;
    @GetMapping("/test")
    public String test(){
        return userServiceClient.users();
    }
    @PostMapping("/test")
    public String insert(@RequestBody UserDto userDto){
        return userServiceClient.insert(userDto);
    }
}

第3章 常见问题
3.1 自我保护机制
1.问题描述

在admin页面出现如下错误“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.”,如下图SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区2.自我保护模式介绍

参考官网:
https://github.com/Netflix/eureka/wiki/Understanding-Eureka-Peer-to-Peer-Communication

保护模式,是Eureka 提供的一个特性,在默认的情况下,这个属性是打开的,而且也建议线上都使用这个特性。

如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,此时会触发Eureka Server进入保护模式,进入自我保护模式后,将会保护服务注册表中的信息,不再删除服务注册表中的数据。

3.相关属性设置

对于自我保护模式属性,建议都是使用默认的配置,不需要要设置这些属性。

(1)Eureka Server端

默认情况下自我保护机制是打开的,线上建议都是打开的,即不需要设置。如果在测试环境需要设置为关闭,可以通过如下配置:

# 设为false,关闭自我保护。默认是打开的。
eureka.server.enable-self-preservation=false

设置清零失效服务的间隔时间,但是不建议更改

# 清理间隔(单位毫秒,默认是60*1000)
eureka.server.eviction-interval-timer-in-ms=4000

这个“eureka.server.eviction-interval-timer-in-ms”时间,是Eureka Server执行清理无效服务的时间间隔,执行新清理任务时,如果下面判断生效,则清除服务。

当前时间 - 上次心跳时间 > lease-expiration-duration-in-seconds

其中,
lease-expiration-duration-in-seconds 属性在客户端进行配置

这里一个规范就是:服务端的“
eureka.server.eviction-interval-timer-in-ms” 值 要比 客户端配置 “lease-expiration-duration-in-seconds ”的时间短。

(2)Eureka Client端

开启健康检查,默认是开启的,如下

eureka.client.healthcheck.enabled=true

心跳相关的设置

# 单位是秒,默认30秒。此客户端发送心跳的频率
eureka.instance.lease-renewal-interval-in-seconds=10
# 单位是秒,默认90秒,表示eureka server在收到此client上次心跳之后,间隔多久没有收到,就摘除此服务。
eureka.instance.lease-expiration-duration-in-seconds=20

3.2 自动下线实例
在客户端服务kill -9或者宕机之后,需要自动从主从中心下掉。

1.服务端配置

因为我们测试实例只有一个,所以这里关闭了自我保护,在生产环境不需要设置这个属性,默认是打开的。因为开启自我保护,客户端是单实例时候,在被kill -9 之后是不会从注册中心下掉的,开启自我保护要保护注册中心注册表信息。

# 单位是秒,默认30秒。此客户端发送心跳的频率
eureka.instance.lease-renewal-interval-in-seconds=10
# 单位是秒,默认90秒,表示eureka server在收到此client上次心跳之后,间隔多久没有收到,就摘除此服务。
eureka.instance.lease-expiration-duration-in-seconds=15
# 清理间隔(单位毫秒,默认是60*1000)
eureka.server.eviction-interval-timer-in-ms=3000
# 设为false,关闭自我保护。默认是打开的。
eureka.server.enable-self-preservation=false

2.客户端配置

# 单位是秒,默认30秒。此客户端发送心跳的频率
eureka.instance.lease-renewal-interval-in-seconds=10
# 单位是秒,默认90秒,表示eureka server在收到此client上次心跳之后,间隔多久没有收到,就摘除此服务。
eureka.instance.lease-expiration-duration-in-seconds=15

3.测试结果

发现需要28s左右自动下线。为什么是28s?

eureka.instance.lease-renewal-interval-in-seconds + eureka.instance.lease-expiration-duration-in-seconds =25秒。由于定时任务间隔为3s,所以下线时间预计为25s~25+3s 之间。所以下线时间间隔为:

eureka.instance.lease-renewal-interval-in-seconds +
eureka.instance.lease-expiration-duration-in-seconds” 到* *“
eureka.instance.lease-renewal-interval-in-seconds + *
eureka.instance.lease-expiration-duration-in-seconds* +
eureka.server.eviction-interval-timer-in-ms”

第4章 Eureka操作
4.1 查看服务实例信息
查看服务实例信息。格式如下

/eureka/apps/{appName}

举例如下:

方法 GET
接口
http://localhost:8761/eureka/apps/SERVICE-PROVIDER1

结果为:

<application>
    <name>SERVICE-PROVIDER1</name> <!-- 服务名字 -->
    <instance>
        <instanceId>provider1:8762</instanceId><!-- 实例ID -->
        <hostName>provider1</hostName>
        <app>SERVICE-PROVIDER1</app>
        <ipAddr>192.168.8.20</ipAddr>
        <status>UP</status>
        <overriddenstatus>UNKNOWN</overriddenstatus>
        <port enabled="true">8762</port>
        <securePort enabled="false">443</securePort>
        <countryId>1</countryId>
        <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
            <name>MyOwn</name>
        </dataCenterInfo>
        <leaseInfo>
            <renewalIntervalInSecs>10</renewalIntervalInSecs>
            <durationInSecs>15</durationInSecs>
            <registrationTimestamp>1645432281902</registrationTimestamp>
            <lastRenewalTimestamp>1645432316868</lastRenewalTimestamp>
            <evictionTimestamp>0</evictionTimestamp>
            <serviceUpTimestamp>1645432281902</serviceUpTimestamp>
        </leaseInfo>
        <metadata>
            <management.port>8762</management.port>
        </metadata>
        <homePageUrl>http://provider1:8762/</homePageUrl>
        <statusPageUrl>http://provider1:8762/info</statusPageUrl>
        <healthCheckUrl>http://provider1:8762/health</healthCheckUrl>
        <vipAddress>service-provider1</vipAddress>
        <secureVipAddress>service-provider1</secureVipAddress>
        <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
        <lastUpdatedTimestamp>1645432281902</lastUpdatedTimestamp>
        <lastDirtyTimestamp>1645432281866</lastDirtyTimestamp>
        <actionType>ADDED</actionType>
    </instance>
</application>

4.2 下线操作
4.2.1 客户端直接停止服务
1、下线

这种方式没有办法立刻让注册中心感知到,需要注册中心等待某一时间没有收到心跳之后,才将这个服务从注册列表中移除。

2、恢复上线

此种方式下对应上线操作,就是重新部署。

4.2.2 客户端通知Eureka下线
1、 下线

使用actuator由客户端发起下线。调用客户端actuator提供的/shutdown/接口。执行完此操作之后,不仅停止了服务,还从eureka下线了。

(1)在项目中引用actuator:

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

(2)配置文件中添加

#启用shutdown
endpoints.shutdown.enabled=true
#不进行密码验证(线上环境应该设置为true)
management.security.enabled=false

(3)通过POST方式执行实例的
http://localhost:8762/shutdown。在postman执行结果如下:SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区2、恢复上线

重新部署服务

4.2.3 Eureka的delete操作
1、下线

delete格式为:

方法:DELETE
接口:/eureka/apps/{appName}/{instanceID}

参数中appName和instaceId可以由查看服务实例信息接口获取,也可以通过erueka admin获取,如下SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区举例,通过postman以delete方法访问
http://localhost:8761/eureka/apps/SERVICE-PROVIDER1/provider1:8762。如下SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区注意:Eureka客户端每隔一段时间(默认30秒)会发送一次心跳到注册中心。在通过delte方式下线一个服务时,如果没有停掉的该服务,那么该服务很快就又会注册到Eureka。所以在使用这种方式时,可以先kill掉服务,然后再执行delete操作,从注册中心移除改服务。

2、恢复上线

在此种方式下就是重新部署服务就可以让服务重新上线。

4.2.4 设置Eureka的服务实例状态
有时候我们下线服务实例之后,需要在不重新部署服务实例的情况下,重新上线服务实例。此时就使用这种方式。

1、下线

接口方式如下

方法:PUT
接口:/eureka/apps/{appName}/{instanceId}/status?value=OUT_OF_SERVICE

举例,通过postman使用 PUT方法 访问
http://localhost:8761/eureka/apps/SERVICE-PROVIDER1/provider1:8762/status?value=OUT_OF_SERVICE,如下:SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区执行结果如下图,改实例状态变为OUT_OF_SERVICESpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区2、 恢复上线

接口方式如下:

方法: DELETE
接口: /eureka/apps/{appName}/{instanceId}/status?value=UP

举例,通过postman使用 DELETE方法 访问

http://localhost:8761/eureka/apps/SERVICE-PROVIDER1/provider1:8762/status?value=UPSpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区执行后的结果为,服务实例重新上线,状态为”UP”  SpringCloud系列—Spring Cloud Eureka服务注册中心-鸿蒙开发者社区4.2.5 一个部署流程
比较优雅的一种服务部署流程方式有:

方式1 :可以通过“设置Eureka的服务实例状态”下线机器;执行部署脚本:kill 服务、重新部署服务;再通过“设置Eureka的服务实例状态”上线此实例。

方式2: 先调用实例的/shutdown接口,然后重新部署该服务

第5章 Eureka Server 集群搭建
本文只介绍单机房搭建
5.1 单机房集群搭建
相对于单点部署这里需要修改配置文件。比如存在3个机器 host1,host2,host3。配置如下:

host1的配置如下:

server.port=8761
spring.application.name = eureka_server
# 指定机器2
eureka.instance.hostname=host1
=============================================
### 如下属性是相对于单点部署有变化的
=============================================
## 指定另外两台机器
eureka.client.serviceUrl.defaultZone=http://host2:8761/eureka/,http://host3:8761/eureka/
## 服务中心可以注册自己。在默认情况下为trure,所以这里可以不加这个配置。单点时候这里是false。
eureka.client.registerWithEureka=true
eureka.client.fetchRegistry=true

host2的配置

server.port=8761
spring.application.name = eureka_server
# 指定机器2
eureka.instance.hostname=host2
=============================================
### 如下属性是相对于单点部署有变化的
=============================================
## 指定另外两台机器
eureka.client.serviceUrl.defaultZone=http://host1:8761/eureka/,http://host3:8761/eureka/
## 服务中心可以注册自己。在默认情况下为trure,所以这里可以不加这个配置。单点时候这里是false。
eureka.client.registerWithEureka=true
eureka.client.fetchRegistry=true

host3的配置

server.port=8761
spring.application.name = eureka_server
## 指定机器3
eureka.instance.hostname=host3
=============================================
### 如下属性是相对于单点部署有变化的
=============================================
## 指定另外两台机器
eureka.client.serviceUrl.defaultZone=http://host1:8761/eureka/,http://host2:8761/eureka/
## 服务中心可以注册自己。在默认情况下为trure,所以这里可以不加这个配置。单点时候这里是false。
eureka.client.registerWithEureka=true
eureka.client.fetchRegistry=true

这里有个偷懒的地方就是,就是三台机器的
eureka.client.serviceUrl.defaultZone配置都指定三台机器,可能启动时候会报错,但是没影响。

eureka.client.serviceUrl.defaultZone=http://host1:8761/eureka/,http://host2:8761/eureka/,http://host3:8761/eureka/

当Eureka-Server由单点变为集群时,对于Eureka-Client的变更,就是在配置中增加如下配置

eureka.client.serviceUrl.defaultZone=http://host1:8761/eureka/,http://host2:8761/eureka/,http://host3:8761/eureka/

第6章 补充
6.1 背景
像亚马逊这种大型的跨境电商平台,会有很多个机房。这时如果上线一个服务的话,我们希望一个机房内的服务优先调用同一个机房内的服务,当同一个机房的服务不可用的时候,再去调用其它机房的服务,以达到减少延时的作用。

于是亚马逊的 AWS 提供了 region 和 zone 两个概念

6.2 概念

  • region:可以简单理解为地理上的分区。比如亚洲地区,或者华北地区,再或者北京地区等等,没有具体大小的限制,根据项目具体的情况,可以自行划分region。
  • zone:可以简单理解为 region 内的具体机房,比如说 region 划分为华北地区,然后华北地区有两个机房,就可以在此 region 之下划分出 zone1、zone2 两个 zone
    eureka 也借用了 region 和 zone 的概念

分类
已于2022-7-26 17:38:08修改
收藏
回复
举报
回复
    相关推荐