3、服务注册与发现Eureka(个人学习笔记)

1、EUREKA服务注册与发现

1.1、EUREKA基础知识

什么是服务治理

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

什么是服务注册与发现

  • Eureka采用了CS(客户端和服务端)的设计架构,Eureka Sever作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。

  • 在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心存放服务地址相关信息(接口地址)

在这里插入图片描述

Eureka两大组件 Eureka Server 和 Eureka Client

  • Eureka Server提供服务注册服务

各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

  • Eureka Client通过注册中心进行访问

它是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。

1.2、EurekaServer服务端安装

还是我们熟悉的五步骤

  • 创建工程cloud-eureka-server7001的Maven工程
  • 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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server7001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--   eureka-server   -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--   引入自己定义的api通用包,可以使用Payment支付Entity     -->
        <dependency>
            <groupId>com.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--  boot web actuator   -->
        <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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>
</project>
  • yml文件
server:
  port: 7001

eureka:
  instance:
    hostname: localhost  #Eureka服务端的实例名称
  client:
    #false代表不向注册中心注册自己
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  • 主启动 需要添加注解@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class, args);
    }
}
  • 测试是否能够访问Eureka服务

运行EurekaMain7001服务,进入浏览器输入http://localhost:7001,会查看到Spring Eureka服务主页。

在这里插入图片描述

  • 此时还没有任何实例注册到Eureka中,下一步我们将微服务消费者入驻到Eureka

1.3、支付微服务8001入驻进EurekaServer

修改8001工程的pom文件,添加spring-cloud-starter-netflix-eureka-client的依赖

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

改yml文件

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

主启动类上添加注解@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class, args);
    }
}
  • 先启动EurekaServer7001服务,在启动PaymentMain8001支付服务,访问http://localhost:7001

在这里插入图片描述

1.4、订单微服务80入驻进EurekaServer

修改80工程的pom文件,添加spring-cloud-starter-netflix-eureka-client的依赖

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

改yml文件

server:
  port: 80

spring:
  application:
    name: cloud-order-service

eureka:
  client:
    #表示是否将自己注册到EurekaServer中,默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认是true。单节点无所谓,集群必须设置为true才能配合Ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

主启动类上添加注解@EnableEurekaClient

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

先启动EurekaServer7001服务,在启动PaymentMain8001支付服务和OrderMain80订单服务,访问http://localhost:7001

在这里插入图片描述

2、Eureka集群原理说明

在这里插入图片描述

Eureka Server

  • 服务注册:将服务信息注册进注册中心

  • 服务发现:从注册中心上获取服务信息

  • 实质:存到的是key:服务名,取的是value:调用地址

注册的工作流程和生命周期

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

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

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

3、Eureka集群环境搭建

原理:互相注册,相互守望

创建cloud-eureka-server7002工程,同样是建Model,改pom,写yml,主启动

在建7002工程前先修改一下我们的映射配置(C:\Windows\System32\drivers\etc路径下的hosts文件,修改映射配置添加进hosts文件)

在这里插入图片描述

7002的yml文件

server:
  port: 7002

eureka:
  instance:
    hostname: eureka7002.com  #Eureka服务端的实例名称
  client:
    #false代表不向注册中心注册自己
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
  	#集群指向其它eureka
      defaultZone: http://eureka7001.com:7001/eureka/
    #单机就是7002自己
      #defaultZone: http://eureka7002.com:7002/eureka/

修改cloud-eureka-server7001配置文件

server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com  #Eureka服务端的实例名称
  client:
    #false代表不向注册中心注册自己
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
    service-url:
      #集群指向其它eureka
      defaultZone: http://eureka7002.com:7002/eureka/
      #单机就是7002自己
      #defaultZone: http://eureka7001.com:7001/eureka/

启动两个eureka服务

  • http://eureka7001.com:7001/
    在这里插入图片描述

  • http://eureka7002.com:7002/
    在这里插入图片描述

4、订单微服务和支付两微服务注册进Eureka集群

将支付服务8001微服务发布到7001和7002Eureka集群配置中(修改8001的yml配置文件)

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

将订单服务80微服务发布到7001和7002Eureka集群配置中(修改80的yml配置文件)

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

测试结果是否正确

在这里插入图片描述

测试步骤

  • 先启动EurekaServer7001和7002服务

  • 在启动服务提供者provider8001

  • 在启动消费者80

  • 测试接口是否能够正常访问到数据

  • 结果:服务都启动后,可以看到订单微服务和支付微服务都注册到了7001和7002EurekaServer服务中
    在这里插入图片描述

  • 访问接口http://localhost/consumer/payment/get/1,可以得到正确的数据
    在这里插入图片描述

5、支付者服务8001集群环境搭建

新建Modle:cloud-provider-payment8002

在这里插入图片描述

修改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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8002</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--  eureka-client  -->
        <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.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--   引入自己定义的api通用包,可以使用Paymeny支付Entity     -->
        <dependency>
            <groupId>com.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>

写yml文件

server:
  port: 8002

spring:
  application:
    name: cloud-payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource  #当前数据源操作类型
    driver-class-name: org.gjt.mm.mysql.Driver    # mysql驱动包
    url: jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: Seeyon123456

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

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.spring.study.entity  #所有Entity别名类所在的包

主启动

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

编写业务类(业务类和8001一致)

修改8001和8002的controller

@Value作用:读取到配置文件(yml)中的数据
在这里插入图片描述

这里我们要实现负载均衡(提前看一下效果),所以订单微服务80的访问地址就不能写死,要修改为要访问的服务名称

在这里插入图片描述

这里我们还有开启RestTemplate的负载均衡功能

在这里插入图片描述

测试

  • 先要启动EurekaServer,7001/7002服务
  • 再要启动服务提供者provider,8001/8002服务
  • 访问接口:http://localhost/consumer/payment/get/1
  • 结果:两个服务轮询被访问,负载均衡效果达到,8001/8002端口交替出现

6、actuator微服务信息完善(可配可不配)

主机名称:服务名称修改

  • 启动项目,可以看到这里显示的主机的名称,我们要将这里暴露的修改为服务名称(去掉主机名称)
    在这里插入图片描述

  • 修改cloud-provider-payment8001,cloud-provider-payment8002

在这里插入图片描述

  • 修改后的效果(显示我们指定的服务名称)

在这里插入图片描述

访问信息有IP信息提示,(将鼠标指针移至payment8001,payment8002名下,会有IP地址提示)

在这里插入图片描述

  • 修改后的效果

在这里插入图片描述

7、服务发现Discovery

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

修改 cloud-provider-payment8001的controller

@Slf4j
@RestController
public class PaymentController {

    @Resource
    private PaymentService paymentService;

    @Resource
    private DiscoveryClient discoveryClient; //添加注解

    @Value("${server.port}")
    private String serverPort;
    
    @GetMapping("/payment/discovery")
    public Object discovery() {
        //查看当前eureka中注册好的微服务
        List<String> services = discoveryClient.getServices();
        for (String element : services) {
            log.info("***************element" + element);
        }

        //根据具体的微服务名称进一步获取微服务的信息
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance instance : instances) {
            log.info(instance.getInstanceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
        }

        return this.discoveryClient;
    }
}

主启动类上添加注解

在这里插入图片描述

启动项目,查看结果 http://localhost:8001/payment/discovery

在这里插入图片描述

在这里插入图片描述

8、Eureka自我保护理论知识

现象

保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会 注销任何微服务

如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入了保护模式。
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THANTHRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUSTTO BE SAFE

在这里插入图片描述

导致原因

某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存。

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

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

什么是自我保护模式

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

在这里插入图片描述

自我保护机制 ∶默认情况下EurekaClient定时向EurekaServer端发送心跳包。

  • 如果Eurekaserver端在一定时间内(默认90秒)没有收到EurekaClient发送的心跳包,便会直接从服务注册列表中剔除该服务,但是在短时间( 90秒中)内丢失了大量的服务实例心跳,这时候 Eurekaserver会开启自我保护机制,不会剔除该服务(该现象可能出现在如果网络不通但是EurekaClient出现宕机,此时如果换做别的注册中心如果一定时间内没有收到心跳会将剔除该服务,这样就出现了严重失误,因为客户端还能正常发送心跳,只是网络延迟问题,而保护机制是为了解决此问题而产生的)。

  • 在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。

  • 它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着。

  • 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

怎么禁止自我保护

  • 修改注册中心eurekaServer端7001

    • 出厂默认:自我保护机制是开启的 ==> server.enable-self-preservation: true
    • 使用server.enable-self-preservation: false可以禁用自我保护模式
      在这里插入图片描述
    • 关闭后的效果
      在这里插入图片描述
  • 修改客户端eurekaClient端8001

    • 出厂默认:eureka.instance.lease-renewal-interval-in-seconds = 30
      lease-renewal-interval-in-seconds 表示eureka client发送心跳给server端的频率。如果在设置的时间 (默认是30秒) 内,server端没有收到client端的心跳,则该instance会被摘除,
    • 出厂默认:eureka.instance.lease-expiration-duration-in-seconds = 90
      表示至上一次收到client的心跳之后, 等待下一次心跳的超时时间,在这个时间内若没有收到下一次心跳,则移除该实例(instance),默认是90秒,如果该值太大的时候,那么很有可能将流量转发过去的时候,这个instance已经不存在了,如果设置太小的话,那么有可能因为网络临时的抖动而被删除掉。该值至少应该大于 lease-renewal-intervalIn-seconds
      在这里插入图片描述
  • 测试:先启动7001,再启动8001,打开 http://eureka7001.com:7001/查看8001是否正常入驻,如果正常,那么再将8001服务停止,再次观察服务是否还在eureka服务中

  • 结果: 停用8001服务后, eureka中该服务立即被删除

学习链接网址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值