服务注册中心Eureka

目录

一、基础知识

1.什么是服务治理:

2.什么是服务注册与发现:

⚪ Eureka Server 和 Eureka Client(服务端和客户端)

二、单机版Eureka构建:

1.新建项目cloud-eureka-server-7001

2.修改pom.xml

3.创建application.yml

4.主启动类

5.测试

三、将支付微服务8001入驻进eurekaServer

1.修改pom

2.在yml中添加相关配置

3. 在主启动类中添加注解 @EnableEurekaClient

​编辑4.测试

四、将订单微服务80入驻进eurekaServer

1.修改pom

2.在yml中添加相关配置

3. 在主启动类中添加注解 @EnableEurekaServer

4.测试

五、Eureka集群原理说明

六、Eureka集群环境构建

①新建cloud-eureka-server7002

②修改pom.xml,添加相关依赖

③修改映射配置

④application.yml

⑤主启动类

⑥测试 

七、将订单支付两个微服务注册进eureka集群

1.将支付服务8001微服务发布到上面两台Eureka集群配置中

⭐修改application.yml

2.将支付服务80微服务发布到上面两台Eureka集群配置中

⭐修改application.yml

🌳启动顺序

3.支付服务提供者8001集群环境构建(构建8002)

1.新建sloud-provider-payment8002

2.修改pom.xml

3.application.yml

4.主启动类

5.业务类

6.修改8001/8002的controller 

 7.测试

①访问eureka7001.com:7001 

②访问eureka7002.com:7002

🐱消费者如何访问由这两个提供者组成的集群?

添加注解@LoadBalanced —— 赋予RestTemplate负载均衡的能力

九、actuator微服务信息完善

1.主机名称:服务名称修改

2. actuator让Eureka显示ip

十、服务发现Discovery @EnableDiscoveryClient

十一、Eureka自我保护理论知识

1.Eureka 自我保护机制

2.为什么会产生Eureka自我保护机制?

3.什么是自我保护模式?

十二、怎么禁止自我保护

1. 在 Eureka Server 的模块中的 yml 文件进行配置:

2.修改 Eureka Client 模块的 心跳间隔时间: 

3.eureka配置项解读:

(1)eureka.instance.lease-expiration-duration-in-seconds

(2)eureka.instance.lease-renewal-interval-in-seconds

(3)*eureka.client.registry-fetch-interval-seconds*

(4)*eureka.server.enable-self-preservation*

十三、Eureka停更


一、基础知识

Eureka(服务发现框架)_百度百科 (baidu.com)

1.什么是服务治理:

  • SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理
  • 在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

2.什么是服务注册与发现:

  • Eureka采用了CS的设计结构,Eureka Server服务注册功能的服务器,它是服务注册中心。
  • 而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
  • 这点和zookeeper很相似
  • 在服务注册与发现中,有一个注册中心。当服务器启动时候,会把当前自己服务器的信息 比如服务地址 通讯地址等以别名方式注册到注册中心上。另一方(消费者服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。RPC远程调用框架核心设计思想:在于注册中心,因为便用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))
  • Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。
  • SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
  • Eureka是基于REST(Representational State Transfer)服务,主要以AWS云服务为支撑,提供服务发现并实现负载均衡和故障转移。我们称此服务为Eureka服务。Eureka提供了Java客户端组件,Eureka Client,方便与服务端的交互。客户端内置了基于round-robin实现的简单负载均衡。在Netflix,为Eureka提供更为复杂的负载均衡方案进行封装,以实现高可用,它包括基于流量、资源利用率以及请求返回状态的加权负载均衡。
  • Eureka 官方停更不停用,以后可能用的越来越少。

⚪ Eureka Server 和 Eureka Client(服务端和客户端)

  • Eureka Server:注册中心,是服务端,而服务提供者和消费者即为客户端,消费者也可以是服务者,服务者也可以是消费者。同时Eureka Server在启动时默认会注册自己,成为一个服务,所以Eureka Server也是一个客户端,这是搭建Eureka集群的基础。
  • Eureka Client:一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)。通过注册中心进行访问。是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(roundrobin)负载算氵去的负载均衡器
  • 在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)
  • 服务在Eureka上注册,然后每隔30秒发送心跳来更新它们的租约。如果客户端不能多次续订租约,那么它将在大约90秒内从服务器注册表中剔除。注册信息和更新被复制到集群中的所有eureka节点。来自任何区域的客户端都可以查找注册表信息(每30秒发生一次)来定位它们的服务(可能在任何区域)并进行远程调用
  • 服务提供者向注册中心注册服务,并每隔30秒发送一次心跳,就如同人还活着存在的信号一样,如果Eureka在90秒后还未收到服务提供者发来的心跳时,那么它就会认定该服务已经死亡就会注销这个服务。这里注销并不是立即注销,而是会在60秒以后对在这个之间段内“死亡”的服务集中注销,如果立即注销,势必会对Eureka造成极大的负担。这些时间参数都可以人为配置。
  • Eureka还有自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,所以不会再接收心跳,也不会删除服务。
  • 客户端消费者会向注册中心拉取服务列表,因为一个服务器的承载量是有限的,所以同一个服务会部署在多个服务器上,每个服务器上的服务都会去注册中心注册服务,他们会有相同的服务名称但有不同的实例id,所以拉取的是服务列表。我们最终通过负载均衡来获取一个服务,这样可以均衡各个服务器上的服务。

二、单机版Eureka构建:

  • 消费者端口80
  • 提供者端口8001。
  • Eureka端口7001

1.新建项目cloud-eureka-server-7001

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2022</artifactId>
        <groupId>com.atxupt.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server-7001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atxupt.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

3.创建application.yml

server:
  port: 7001

eureka:
  instance:
    hostname: localhost  # eureka 服务端的实例名称

  client:
    # false 代表不向服务注册中心注册自己,因为它本身就是服务中心
    register-with-eureka: false
    # false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与 Eureka Server 交互的地址,查询服务 和 注册服务都依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

4.主启动类

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

5.测试

三、将支付微服务8001入驻进eurekaServer

1.修改pom

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2.在yml中添加相关配置

eureka:
  client:
	# 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
      defaultZone: http://localhost:7001/eureka/

3. 在主启动类中添加注解 @EnableEurekaClient

4.测试

名称与application.yml中的配置一致

  

四、将订单微服务80入驻进eurekaServer

1.修改pom

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

2.在yml中添加相关配置

server:
  port: 80

spring:
  application:
    name: cloud-order-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka/

3. 在主启动类中添加注解 @EnableEurekaServer

4.测试

启动三个微服务

名称与application.yml中的配置一致

五、Eureka集群原理说明

  • 先启动eureka注册中心
  • 启动服务提供者payment支付服务
  • 支付服务启动后会把自身信息化 服务以别名方式注册进eureka
  • 消费者order服务在要调用接囗时,使用服务别名去注册中心取实际的RPC远程调用地址
  • 消费者获得调用地址后,底层实际是利用HttpClient技术实现远程调用
  • 消费者获得服务地址后会存jvm内存中,默认每间隔30s更新一次服务调用地址 

 

六、Eureka集群环境构建

Eureka 集群700X

Eureka Server在设计的时候就考虑了高可用设计,在Eureka服务治理设计中,所有节点既是服务的提供方,也是服务的消费方,服务注册中心也不例外。

Eureka Server的高可用实际上就是将自己做为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。

Eureka Server的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。可以采用两两注册的方式实现集群中节点完全对等的效果,实现最高可用性集群,任何一台注册中心故障都不会影响服务的注册与发现。

问题:微服务RPC远程服务调用最核心的是什么:

高可用,试想你的注册中心只有一个。onlyone,它出故障了那就呵呵了,会导致整个为服务环境不可用,所以要搭建Eureka注册中心集群,实现负载均衡+故障容错

Eureka 集群的原理:相互注册,互相守望

每台Eureka服务器都有集群里其他Eureka服务器地址的信息

①新建cloud-eureka-server7002

cloud-eureka-server7002:第二个 Eureka 服务注册中心

②修改pom.xml,添加相关依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
        <groupId>com.atxupt.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

③修改映射配置

  • Ⅰ、找到C:\Windows\System32\drivers\etc路径下的hosts

  • Ⅱ、添加配置

127.0.0.1 eureka7001.com

127.0.0.1 eureka7002.com

④application.yml

  • Ⅰ、7001 端口的Server yml文件:
server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com  # eureka 服务器的实例地址

  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
    ## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
      defaultZone: http://eureka7002.com:7002/eureka/
  • Ⅱ、7002 端口的Server yml文件:
server:
  port: 7002

eureka:
  instance:
    hostname: eureka7002.com  # eureka 服务器的实例地址

  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
    ## 一定要注意这里的地址 这是搭建集群的关键
      defaultZone: http://eureka7001.com:7001/eureka/

eureka.instance.hostname 才是启动以后 本 Server 的注册地址,而 service-url 是 map 类型,只要保证 key:value 格式就行,它代表 本Server 指向了那些 其它Server 。利用这个,就可以实现Eureka Server 相互之间的注册,从而实现集群的搭建。、

⑤主启动类

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

⑥测试 

七、将订单支付两个微服务注册进eureka集群

1.将支付服务8001微服务发布到上面两台Eureka集群配置中

⭐修改application.yml

 上面配置了多个Eureka作为集群,接下来要配置的是提供者集群,让提供者高可用

为提供者cloud-provider-payment8001 模块创建集群,新建模块名为 cloud-provider-payment8002

即两个提供者8001和8002

其余配置都一致,需要配置集群的配置如下:

配置区别要点:

集群中多个提供者的spring:application:name:要一致
启动类添加@EnableDiscoveryClient或者@EnableEurekaClient
1,@EnableDiscoveryClient注解是基于spring-cloud-commons依赖,并且在classpath中实现;
2,@EnableEurekaClient注解是基于spring-cloud-netflix依赖,只能为eureka作用;
如果你的classpath中添加了eureka,则它们的作用是一样的。
消费者(一般需要连接其他微服务的服务或者gateway/zuul)

# 提供者
server:
  port: 8001  # 端口号不一样

spring:
  application:
    name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.dkf.springcloud.entities  

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url: # 提供者注册到多个eureka中
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

注意在 Controller 返回不同的消息,从而区分者两个提供者的工作状态。(只是为了学习测试才这么做,生产环境直接复制即可)

在提供者的controller中

@Value("${server.port}")
private String serverPort;

2.将支付服务80微服务发布到上面两台Eureka集群配置中

⭐修改application.yml

server:
  port: 80

spring:
    application:
        name: cloud-order-service
    zipkin:
      base-url: http://localhost:9411
    sleuth:
      sampler:
        probability: 1

eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true。
    register-with-eureka: false
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #单机
      #defaultZone: http://localhost:7001/eureka
      # 集群
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版

🌳启动顺序

  • 先启动EurekaServer,7001,7002服务
  • 再启动服务提供者provider,8001
  • 最后启动消费者,80

 

3.支付服务提供者8001集群环境构建(构建8002)

1.新建sloud-provider-payment8002

2.修改pom.xml

🐟🐟🐟添加相关依赖

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.atxupt.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </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>
        <dependency>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-project-info-reports-plugin</artifactId>
            <version>3.4.0</version>
        </dependency>
        <!--spring boot 2.2.2-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.2.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--spring cloud Hoxton.SR1-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--spring cloud 阿里巴巴-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.8.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
            <scope>runtime</scope>
        </dependency>
        <!-- druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.1</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
        <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--配置中心jar包-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

        <!--连接msql数据库相关jar包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>

3.application.yml

server:
  port: 8002

spring:
  application:
    name: cloud-payment-service
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    #数据库url
    url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
    # 数据库访问账户
    username: root
    # 数据库访问密码
    password: 

eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka


mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.atxupt.springcloud.entities  #所有Entity别名类所在包

4.主启动类

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

5.业务类

直接从8001的业务类复制粘贴(U•ェ•*U)

6.修改8001/8002的controller 

(两个的controller都要修改)

 7.测试

按顺序启动7001->7002->8001->8002->80

①访问eureka7001.com:7001 

②访问eureka7002.com:7002

 

存在的问题:此时消费者一旦消费完之后,他以后访问的还是那台提供者。明显不对,原因在于消费者并没有去Eureka里找服务,而是自己找的

🐱消费者如何访问由这两个提供者组成的集群?

订单服务的地址不能写死

Eureka Server 上的提供者的服务名称如下:

@RestController
@Slf4j
public class OrderController {
    
    // 重点是这里,改成 提供者在Eureka 上的名称,而且无需写端口号	
    public static final String PAYMENY_URL = "http://CLOUD-PROVIDER-SERVICE";//取决于我们在提供者出配置的name,CLOUD-PAYMENY-SERVICE,//同时要注意使用@LoadBalanced注解赋予RestTemplate负载均衡能力

    @Resource
    private RestTemplate restTemplate;

    @PostMapping("customer/payment/create")
    public CommonResult<Payment> create (Payment payment){
        return restTemplate.postForObject(PAYMENY_URL + "/payment/create", payment, CommonResult.class);
    }

    @GetMapping("customer/payment/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id")Long id){
        return restTemplate.getForObject(PAYMENY_URL + "/payment/" + id, CommonResult.class);
    }
}

添加注解@LoadBalanced —— 赋予RestTemplate负载均衡的能力

@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced  //这个注解,就赋予了RestTemplate 负载均衡的能力
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

这时候,消费者消费的提供者多次访问就会变化了(这就是Ribbon的负载平衡功能)

九、actuator微服务信息完善

1.主机名称:服务名称修改

  • Ⅰ、存在问题:含有主机名称

  • Ⅱ、修改cloud-provider-payment8001

2. actuator让Eureka显示ip

为了在微服务Eureka控制台能看到我们的某个具体服务是在哪台服务器上部署的,我们需要配置一些内容。

修改 提供者在Eureka 注册中心显示的 主机名:即修改eureka:instance:instance-id:和eureka:instance:prefer-ip-address:

# 提供者
server:
  port: 8001  # 端口号不一样

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
  instance: #重点,和client平行
    instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
    prefer-ip-address: true # 可以显示ip地址

十、服务发现Discovery @EnableDiscoveryClient

对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息。

(即我们前面可视化页面的信息)

  • 在主启动类上添加注解:@EnableDiscoveryClient
  • 在 Controller 里面打印信息:
@Resource // 自动注入
private DiscoveryClient discoveryClient;

@GetMapping("/customer/discovery")
public Object discovery(){
    //获得服务清单列表
    List<String> services = discoveryClient.getServices();
    for(String service: services){
        log.info("*****service: " + service);
    }
    // 根据具体服务进一步获得该微服务的信息
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-ORDER-SERVICE");
    for(ServiceInstance serviceInstance:instances){
        log.info(serviceInstance.getServiceId() + "\t" + 
                 serviceInstance.getHost()+ "\t" + 
                 serviceInstance.getPort() + "\t" + 
                 serviceInstance.getUri());
    }
    return this.discoveryClient;
}

十一、Eureka自我保护理论知识

1.Eureka 自我保护机制

  • 某时刻某一个微服务不可用了,Eureka不会立即清理,依旧会对该微服务的信息进行保存。
  • 属于CAP里的AP(高可用)分支
  • 保护模式主要用于一组客户和Eureka Server之间存在网络分区场景下保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中固定信息,也就是不会注销任何微服务。

如果在Eureka Server的首页看到以下这段提示,则说明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

2.为什么会产生Eureka自我保护机制?

为了防止Eureka Client可以正常运行但是与Eureka Server网络不通情况下,Eureka Server不会立刻将Eureka Client服务剔除

3.什么是自我保护模式?

  • 默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。
  • 但是当网络分区故障发生、卡顿、拥挤时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了—因为微服务本身其实是健康的,此时本不应该注销这个微服务。
  • Eureka通过"自我保护模式"来解决这个问题 — 当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。

自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。

使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

十二、怎么禁止自我保护

1. 在 Eureka Server 的模块中的 yml 文件进行配置:

server:
port: 7001

eureka:
instance:
 hostname: eureka7001.com

client:
 register-with-eureka: false
 fetch-registry: false
 service-url:
   defaultZone: http://eureka7002.com:7002/eureka/
server: # 与client平行
	# 关闭自我保护机制,保证不可用该服务被及时剔除
	enable-self-preservation: false
	eviction-interval-timer-in-ms: 2000

2.修改 Eureka Client 模块的 心跳间隔时间: 

# 提供者
server:
  port: 8001  # 端口号不一样

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url: # 集群
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
  instance: #重点,和client平行
    instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
    prefer-ip-address: true # 可以显示ip地址
    # Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30s
    least-renewal-interval-in-seconds: 1
    # Rureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务
    least-expiration-duration-in-seconds: 2

3.eureka配置项解读:

在注册服务之后,服务提供者会维护一个心跳用来持续高速Eureka Server,“我还在持续提供服务”,否则Eureka Server的剔除任务会将该服务实例从服务列表中排除出去。我们称之为服务续约。

(1)eureka.instance.lease-expiration-duration-in-seconds

leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance。
默认为90秒
如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。
如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。
该值至少应该大于leaseRenewalIntervalInSeconds

(2)eureka.instance.lease-renewal-interval-in-seconds

leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。
默认30秒

(3)*eureka.client.registry-fetch-interval-seconds*

表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒

(4)*eureka.server.enable-self-preservation*

是否开启自我保护模式,默认为true。

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

十三、Eureka停更

Eureka停更说明:

2.0后停更了。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

elk-zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值