• SpringCloud-Eureka服务注册与发现


    SpringCloud-Eureka服务注册与发现

    1.Eureka 介绍

    1.说明

    1、Spring Cloud 组件选型- 图

    image-20220904073820202

    2、从上图可以看出, 目前主流的服务注册&发现的组件是 Nacos, 但是 Eureka 作为一个老牌经典的服务注册&发现技术还是有必要学习一下, 原因

    (1) 一些早期的分布式 微服务项目使用的是 Eureka

    (2) 后期的服务注册&发现组件/技术, 都参考了 Eureka 设计和理念

    2.从项目架构问题分析 -引出 Eureka

    image-20220904074134847

    问题分析

    1.在企业级项目中,服务消费访问请求会存在高并发

    2.如果只有一个会员中心-提供服务,可用性差

    3.所以,会员中心提供服务往往是一个集群,也就是说会有多个会员中心-提供服务微服务模块

    4.那么这个时候,就存在一个问题就是服务消费方,怎么去发现可以使用的服务

    5.当服务消费方,发现了可以使用的服务后(可能是多个,又存在一个问题就是到底调用 A 服务,还是 B 服务的问题,这就引出了服务注册和负载均衡)

    6.Eureka 就可以解决上述问题

    3.引入 Eureka 项目架构

    image-20220904074412294

    1. 会员中心-提供服务的,在项目中,会做成集群,提供高可用
    2. Eureka Server 有必要的话,也可以做成集群
    3. Eureka 包含两个组件∶Eureka Server 和 Eureka Client
    4. Eureka Server 提供注册服务, 各个微服务节点通过配置启动后,会在 Eureka Server 中进 行注册,这样 EurekaServer 中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
    5. EurekaClient 通过注册中心进行访问, 是一个 Java 客户端,用于简化 Eureka Server 的交 互,客户端同时也具备一个内置的、使用轮询(round-robin) 负载算法的负载均衡器。在应用启动后,将会向 Eureka Server 发送心跳(默认周期为 30 秒)。如果 Eureka Server 在多个 心跳周期内没有接收到某个节点的心跳,EurekaServer 将会从服务注册表中把这个服务节 点移除(默认 90 秒)

    4.服务治理介绍

    1. Eureka 实现服务治理
    2. 在传统的 rpc 远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理困难,所以 需要治理服务之间依赖关系
    3. 服务治理实现服务调用、负载均衡、容错等,实现服务发现与注册。
    4. 二说分布式开发: 什么是分布式开发?

    5.服务注册和发现

    –服务注册与发现

    image-20220904084330221

    ​ 1.Eureka采用了CS[client-server]的设计架构, Eureka Server 作为服务注册功能的服务器,它是服务注册中心。

    ​ 2.系统中的其他微服务,使用 Eureka的客户端连接到 Eureka Server并维持心跳连接, 通过 Eureka Server 来监控系统中各个微服务是否正常运行。

    ​ 3.在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息 比如服务地址通讯地址等以别名方式注册到注册中心上。

    ​ 4.服务消费者或者服务提供者,以服务别名的方式去注册中心上获取到实际的服务提供 者通讯地址,然后通过RPC调用服务。

    2.创建单机 Eureka Server-注册中心

    1.需求说明/图解

    image-20220904084645562

    2.实现步骤

    1.搭建工程

    说明:

    1.e-commerce-eureka-server-9001作为eureka-server

    2.e_commerce_center-common-api作为公共模块

    3.e-commerce-center作为父工程,指定依赖的版本利用maven依赖的传递性对子模块依赖版本进行统一管理

    4.member-service-consumer-80,调度会员中心-服务消费放

    5.member-service-provider-10000,会员中心-服务提供方;两个都作为eureka-client客户端,均需注入到eureka-server端

    image-20220904084835416

    2.引入相关依赖

    eureka-server服务端

    
    <dependency>
       <groupId>org.springframework.cloudgroupId>
       <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    eureka-client客户端

    
    <dependency>
       <groupId>org.springframework.cloudgroupId>
       <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.修改application.yml

    eureka-server服务端

    server:
      port: 9001
    
    #配置eureka-server
    eureka:
      instance:
        #服务实例名称|服务别名
        hostname: localhost
        #作为一个eureka-server为什么还需要配置client?因为后面eureka-server可能是集群会相互注册
      client:
        #配置不像注册中心注册自己
        register-with-eureka: false
        #表示自己就是注册中心,作用就是维护注册的服务实例,不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与eureka-server交互的模块,查询服务和注册都需要依赖的地址
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    eureka-client客户端

    #配置eureka-client
    eureka:
      client:
        #将自己注册到eureka-server
        register-with-eureka: true
        #表示从eureka-server获取注册信息
        #如果是单节点是可以不配置的,但如果是集群则必须配置为true,才能配合Ribbon实现负载均衡功能
        fetch-registry: true
        service-url:
          #表示将自己注册到哪个eureka-server
          defaultZone: http://localhost:9001/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.修改主启动

    eureka-server服务端

    //@EnableEurekaServer:表示该程序作为eureka-server
    @EnableEurekaServer
    @SpringBootApplication
    public class EurekaApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaApplication.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    eureka-client客户端

    //@EnableEurekaClient:表示该程序作为eureka-client
    @EnableEurekaClient
    @MapperScan(basePackages = {"com.llp.springcloud.dao"})
    @SpringBootApplication
    public class MemberApplication {
        public static void main(String[] args) {
            SpringApplication.run(MemberApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.完成测试

    1.服务名就是客户端注册到eureka-server指定的名称

    2.这里member-service-consumer-80和member-service-provider-10000两个服务对于eureka-server来说都是客户端,因此参考配置eureka-client即可

    image-20220904085801363

    3.Service Consumer 、Service Provider 、EurekaServer 的维护机制

    image-20220904090358086

    4.Eureka 自我保护模式

    1.自我保护模式理论
    1. 在默认情况下, Eureka 启动了自我保护模式(如图红字, 需要刷新页面, 可以看到)

    image-20220904091027880

    1. 自我保证机制/模式说明

    (1)默认情况下EurekaClient定时向EurekaServer端发送心跳包

    (2)如果Eureka在server端在一定时间内(默认90秒)没有收到EurekaClient发送心跳包, 便会直接从服务注册列表中剔除该服务

    (3)如果Eureka 开启了自我保护模式/机制, 那么在短时间(90秒中)内丢失了大量的服 务实例心跳,这时候EurekaServer会开启自我保护机制,不会剔除该服务(该现象可能出现在如果网络不通或者阻塞) 因为客户端还能正常发送心跳,只是网络延迟问题, 而保护机制是为了解决此问题而产生的

    1. 自我保护是属于 CAP 里面的 AP 分支, 保证高可用和分区容错性

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

    3. 测试 启动member-service-provider-10000 和 e-commerce-eureka-server-9001 ,让member-service-provider-10000 正确的注册,然后关闭member-service-provider-10000 ,观察注册的 member-service-provider-10000 服务是否还在.

    2.禁用自我保护模式(生产环境中, 一般不禁用)
    1. 说修改 e-commerce-eureka-server-9001 的 application.yml
    #配置eureka-server
    eureka:
      instance:
        #服务实例名称|服务别名
        hostname: localhost
        #作为一个eureka-server为什么还需要配置client?因为后面eureka-server可能是集群会相互注册
      client:
        #配置不像注册中心注册自己
        register-with-eureka: false
        #表示自己就是注册中心,作用就是维护注册的服务实例,不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与eureka-server交互的模块,查询服务和注册都需要依赖的地址
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      server:
        #禁用自我保护模式 false-禁用 true-开启
        enable-self-preservation: false
        #设置超时时间,在设置的时间(单位:毫秒)内,收不到心跳包就认为超时,默认90秒 如果超时就会将服务从eureka注册中心剔除
        eviction-interval-timer-in-ms: 2000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    1. 修改 member-service-provider-10000 的 application.yml
    #配置eureka-client
    eureka:
      client:
        #将自己注册到eureka-server
        register-with-eureka: true
        #表示从eureka-server获取注册信息
        #如果是单节点是可以不配置的,但如果是集群则必须配置为true,才能配合Ribbon实现负载均衡功能
        fetch-registry: true
        service-url:
          #表示将自己注册到哪个eureka-server
          defaultZone: http://localhost:9001/eureka/
      instance:
        #客户端像服务端发送心跳的间隔时间 默认30s
        lease-renewal-interval-in-seconds: 1
        #服务端收到最后一次心跳等待的时间上线,时间单位/s 默认90s 超时将剔除服务
        lease-expiration-duration-in-seconds: 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.启动测试

    可以看到eureka自我保护模式已经关闭了

    image-20220904103019531

    停止服务后,eureka将服务从注册中心剔除

    image-20220904103139730

    3.搭建 EurekaServer 集群- 实现负载均衡&故障容错

    1.为什么需要集群 Eureka Server

    image-20220904103510895

    1. 微服务 RPC 远程服务调用最核心的是实现高可用
    2. 如果注册中心只有 1 个,它出故障,会导致整个服务环境不可用
    3. 解决办法∶搭建 Eureka 注册中心集群,实现负载均衡+故障容错

    2.需求分析/图解

    image-20220904103550057

    3.搭建 Eureka Server 集群

    1.创建 e-commerce-eureka-server-9002 微服务模块[作为注册中心]

    image-20220904104516203

    2.引入依赖
    
    <dependency>
       <groupId>org.springframework.cloudgroupId>
       <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    3.修改yaml配置

    9001

    #配置eureka-server
    eureka:
      instance:
        #服务实例名称|服务别名
        hostname: eureka9001.com
        #作为一个eureka-server为什么还需要配置client?因为后面eureka-server可能是集群会相互注册
      client:
        #配置不像注册中心注册自己
        register-with-eureka: false
        #表示自己就是注册中心,作用就是维护注册的服务实例,不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与eureka-server交互的模块,查询服务和注册都需要依赖的地址
          defaultZone: http://eureka9002.com:9002/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    9002

    #配置eureka-server
    eureka:
      instance:
        #服务实例名称|服务别名
        hostname: eureka9002.com
        #作为一个eureka-server为什么还需要配置client?因为后面eureka-server可能是集群会相互注册
      client:
        #配置不像注册中心注册自己
        register-with-eureka: false
        #表示自己就是注册中心,作用就是维护注册的服务实例,不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与eureka-server交互的模块,查询服务和注册都需要依赖的地址
          defaultZone: http://eureka9001.com:9001/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    4.修改hosts文件

    说明:因为我们实在本机进行模拟,修该hosts文件,才能实现根据域名去本机查询ip地址(先在本机hosts文件查找,找不到再到DNS去查找)

    1. 文件: C:\Windows\System32\drivers\etc\host
    2. 文件可以先拷贝到桌面,修改后,再拷贝会去
    3. 加入内容:
    #配置eureka 主机和ip的映射
    127.0.0.1 eureka9001.com
    127.0.0.1 eureka9002.com
    
    • 1
    • 2
    • 3
    5.完成测试

    启动 e-commerce-eureka-server-9001、e-commerce-eureka-server-9002

    image-20220904110520525

    image-20220904110555963

    5.将 member-service-provider-10000 注册到 EurekaServer 集群

    1.修改 resources/application.yml

    #配置eureka-client
    eureka:
      client:
        #将自己注册到eureka-server
        register-with-eureka: true
        #表示从eureka-server获取注册信息
        #如果是单节点是可以不配置的,但如果是集群则必须配置为true,才能配合Ribbon实现负载均衡功能
        fetch-registry: true
        service-url:
          #表示将自己注册到哪个eureka-server
          #defaultZone: http://localhost:9001/eureka/
          #将本微服务注册到多个 eurekaServer, 使用逗号隔开
          defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.完成测试

    image-20220904113904463

    image-20220904113924720

    将 member-service-consumer-80 注册到 EurekaServer 集群(同上)

    4.搭建会员中心服务提供方-集群

    1.架构示意图

    image-20220904115404991

    2.创建 member-service-provider-10002

    image-20220904220424292

    修改端口号、主启动即可,其他同member-service-provider-10000

    server:
      port: 10002
    
    • 1
    • 2
    //@EnableEurekaClient:表示该程序作为eureka-client
    @EnableEurekaClient
    @MapperScan(basePackages = {"com.llp.springcloud.dao"})
    @SpringBootApplication
    public class MemberApplication10002 {
        public static void main(String[] args) {
            SpringApplication.run(MemberApplication10002.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.完成测试

    启动 eureka server 集群(目前 2 台)

    启动 member-service-provider-10000

    启动 member-service-provider-10002

    image-20220904221143425

    image-20220904221201581

    4.注意事项和细节
    1. 因为 member-service-provider-10000 和 member-service-provider-10002 作为一个集 群提供服务, 因此需要将 spring.application.name 进行统一
    2. 这样消费方通过统一的别名进行负载均衡调用

    5.配置服务消费端 member-service-consumer-80 使用会员中心服务集群

    image-20220904221356174

    @Configuration
    public class CustomizationBean {
    
        // 配置注入RestTemplate bean/对象
        //这里的@LoadBalanced 就是赋予 RestTemplate 负载均衡的能力
        //默认是使用轮询算法来访问远程调用接口/地址
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    @Slf4j
    @RestController
    @RequiredArgsConstructor
    public class MemberConsumerController {
    
        //定义一个服务端基础地址
        public static final String MEMBER_SERVICE_PROVIDER_URL = "http://MEMBER-SERVICE-PROVIDER";
    
        private final RestTemplate restTemplate;
    
        @PostMapping("/member/consumer/save")
        public Result save(Member member) {
            log.info("member:{}", member);
            /**
             * url:请求的完整地址
             * member:通过restTemplate发出的post请求携带的数据
             * Result.class: 返回对象类型
             * 注意:restTemplate底层发送数据是通过json字符串进行传输的,服务端接受数据需要加上@RequestBody注解才能解析数据
             * 传输的数据通过流进行传输,需要实现序列化接口
             */
            return restTemplate.postForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/save", member, Result.class);
        }
    
        @GetMapping("/member/consumer/get/{id}")
        public Result<Member> getMemberById(@PathVariable("id") Long id) {
            return restTemplate.getForObject(MEMBER_SERVICE_PROVIDER_URL + "/member//get/" + id, Result.class);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    交替访问member服务说明

    1. 注解@LoadBalanced 底层是Ribbon支持算法
    2. Ribbon和Eureka 整合后 consumer 直接调用服务而不用再关心地址和端口号,且该服务还有负载功能
    3. spring-cloud-starter-netflix-eureka-client 自 带 spring-cloud-starter-netflix-ribbon(如图)

    image-20220904223901646

    6.获取 Eureka Server 服务注册信息 -DiscoveryClient

    1.先看需求分析示意图

    image-20220904224213596

    1. 这里我们以服务消费方, 去获取 Eureka Server 的服务注册信息为例

    2. 当然也可以在服务提供方获取 Eureka Server 的服务注册信息

    MemberConsumerApplication主启动类添加@EnableDiscoveryClient注解

    @EnableEurekaClient
    @SpringBootApplication
    @EnableDiscoveryClient
    public class MemberConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(MemberConsumerApplication.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    MemberConsumerController

    //装配DiscoveryClient
    private final DiscoveryClient discoveryClient;
    
    @GetMapping("/member/consumer/discovery")
    public Object discovery() {
    
        List<String> services = discoveryClient.getServices();
        //遍历services
        for (String service : services) {
            log.info("服务名={}",service);
            List<ServiceInstance> instances = discoveryClient.getInstances(service);
            for (ServiceInstance instance : instances) {
                log.info("id={},host={},port={},uri={}",
                        instance.getServiceId(),instance.getHost(),instance.getPort(),instance.getUri());
    
            }
        }
        return discoveryClient;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    image-20220904224612462

    注意事项和细节说明

    1. 在引入 DiscoveryClient 时,不要引入错误的包

    正确的包: import org.springframework.cloud.client.discovery.DiscoveryClient;

    错误的包: import com.netflix.discovery.DiscoveryClient;

    ​ 2.在服务消费方使用 DiscoveryClient 来完成服务发现,同样在服务提供方/模块也 OK

    4.Eureka 后续说明

    1. Eureka 停更说明: Eureka停更
    2. 目前替代 Eureka 做服务注册和发现, 均衡负载的 最佳组件是 Spring Cloud Alibaba Nacos
    3. 虽然 Eureka 停更,目前用的不多,但是它的服务注册和发现, 均衡负载的思想是优先的
  • 相关阅读:
    钻石价格预测的ML全流程!从模型构建调优道部署应用!⛵
    【虚拟机开不了】linux、centOS虚拟机出现entering emergency mode解决方案
    前端开发面试题—Vue的生命周期
    代码随想录38——动态规划:动态规划理论基础、509斐波那契数列、70爬楼梯、746使用最小花费爬楼梯
    Linux运维基础知识大全
    03-关系和非关系型数据库对比
    如何通过NTC热敏电阻计算温度(一)---理论篇
    AI+视频技术助力保障校园安全,校园智能安防平台该如何建设?
    牛客多校十 - Shannon Switching Game (倒推,bfs)
    怎样优雅地增删查改(三):业务用户的增删查改
  • 原文地址:https://blog.csdn.net/qq_44981526/article/details/126696175