五、Eureka服务注册与发现

Eureka基础知识

服务治理

在这里插入图片描述

服务注册

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

Eureka两组件

在这里插入图片描述

单机Eureka构建步骤

IDEA生成eurekaServer端服务注册中心

1. 建module

cloud-eureka-server7001

2. 改pom

server端依赖对比:
在这里插入图片描述
在pom中添加

  <dependencies>
      <!-- eureka-server -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      </dependency>
      <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
      <dependency>
          <groupId>com.angenin.springcloud</groupId>
          <artifactId>cloud-api-commons</artifactId>
          <version>${project.version}</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>
          <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>
  </dependencies>
3. 写yml

在resources目录下新建application.yml文件

server:
  port: 7001

eureka:
  instance:
    hostname: localhost  #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己(想注册也可以,不过没必要)
    register-with-eureka: false
    #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4. 主启动

在java包下新建com.angenin.springcloud.EurekaMain7001

@EnableEurekaServer //表示此项目是eureka的服务注册中心
@SpringBootApplication
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class, args);
    }
}
5. 测试

启动项目,在浏览器输入http://localhost:7001/
在这里插入图片描述

将EurekaClient端8001注册进EurekaServer成为服务提供者provider

client端依赖对比
在这里插入图片描述

  1. 引入依赖

     <!-- eureka-client -->
     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
     </dependency>
    
  2. 在yml文件中添加

    eureka:
      client:
        #true表示向注册中心注册自己,默认为true
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://localhost:7001/eureka
    
  3. 在主配置类上加上@EnableEurekaClient注解,表示这个项目是eureka的客户端。

  4. 启动项目,然后刷新页面,成功注册进注册中心。
    在这里插入图片描述
    在yml文件中application.name就是注册进注册中心时的应用名。
    在这里插入图片描述

将EurekaClient端80注册进EurekaServer成为服务消费者consumer

  1. 引入依赖

     <!-- eureka-client -->
     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
     </dependency>
    
  2. 在yml文件中添加

    spring:
      application:
        name: cloud-order-service
    
    eureka:
      client:
        register-with-eureka: true
        fetch-registry: true
        service-url:
          defaultZone: http://localhost:7001/eureka
    
  3. 在主配置类上加上@EnableEurekaClient注解。

  4. 启动项目,刷新页面
    在这里插入图片描述

集群Eureka构建步骤

原理说明

在这里插入图片描述
搭建Eureka注册中心集群,实现负载均衡+故障容错。

Eureka集群:相互注册,相互守望
在这里插入图片描述

构建eurekaServer集群环境

  1. 参照cloud-eureka-server7001新建cloud-eureka-server7002和cloud-eureka-server7003。
  2. Windows系统的兄弟就跟着老师修改hosts文件,因为我的是mac系统的,接下来写的步骤是mac的。
    打开终端,输入sudo vim /etc/hosts来修改hosts文件。(权限不够需要加上sudo并输入密码)
    在最后一行加入:
    127.0.0.1       eureka7001.com
    127.0.0.1       eureka7002.com
    127.0.0.1		eureka7003.com
    
    然后:wq!保存退出。
  3. 修改7001的yml文件
    eureka:
      instance:
        hostname: eureka7001.com  #eureka服务端的实例名称
      client:
        register-with-eureka: false
        fetch-registry: false
        service-url:
    #      单机
    #      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
          #集群版  相互注册,相互守望
          defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/ 
          
    #    defaultZone是固定写法,如果想自定义,需要按以下写法才行:
    #    region: eureka-server
    #    availability-zones:
    #      eureka-server: server1,server2
    #    service-url:
    #      server1: http://eureka7002.com:7002/eureka/
    #      server2: http://eureka7003.com:7003/eureka/
    
  4. 修改7002的yml文件
    eureka:
      instance:
        hostname: eureka7002.com  #eureka服务端的实例名称
      client:
        register-with-eureka: false
        fetch-registry: false
        service-url:
          #集群版  相互注册,相互守望
          defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7003.com:7003/eureka/ #相互注册,相互守望
    
  5. 修改7003的yml文件
    eureka:
      instance:
        hostname: eureka7003.com  #eureka服务端的实例名称
      client:
        register-with-eureka: false
        fetch-registry: false
        service-url:
          #集群版  相互注册,相互守望
          defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/ #相互注册,相互守望
    
  6. 然后启动这三个项目
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

将支付服务8001和订单服务80微服务发布到集群配置中

把两个项目的yml文件中的defaultZone改为:

      #集群版
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka

启动5个项目进行测试:(先启动集群,再启动8001,最后启动80)
集群后台截图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

构建支付服务提供者集群环境

  1. 按照8001新建8002(只多建了一个提供者,建多了怕电脑受不了)。(除了要yml文件中需要改端口号和主配置类,其他直接复制8001的,yml文件中的应用名不需要改,因为是集群,所以应用名需要一致)

  2. 分别在所有的提供者的PaymentController中加入:(这个@Value是spring的注解)
    在这里插入图片描述

  3. 修改消费者的OrderController,把写死的url改为服务名称:

       	public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
    
  4. 然后在消费者的ApplicationContextConfig里的restTemplate方法上加上@LoadBalanced,开启负载均衡功能。

  5. 启动eurekaServer集群,启动提供者集群,启动消费者。
    如果启动提供者后出现,这个错误:Public Key Retrieval is not allowed
    请在yml文件中的datasource.datasource.url后加上&allowPublicKeyRetrieval=true即可解决。
    在这里插入图片描述
    另外两个eurekaserver也一样,就不截图。
    在浏览器中输入http://localhost/consumer/payment/get/1,多次刷新可以看到,提供服务的应用在不同的切换,实现负载均衡的效果。
    在这里插入图片描述
    在这里插入图片描述

actuator微服务信息完善

修改三个微服务的yml文件:

#######8001#######
# client:	
#	 ...	instance要和client对齐
  instance:
    instance-id: payment8001
    prefer-ip-address: true   #访问路径可以显示ip地址

#######8002#######
  instance:
    instance-id: payment8002   #修改显示的主机名
    prefer-ip-address: true   #访问路径可以显示ip地址
    
#######80#######
  instance:
    instance-id: consumer80   #修改显示的主机名
    prefer-ip-address: true   #访问路径可以显示ip地址

修改前:
在这里插入图片描述
修改后:
在这里插入图片描述

服务发现Discovery

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

修改提供者集群的controller
  1. 在主配置类上加上@EnableDiscoveryClient注解,启用发现客户端。

  2. 在两个提供者的PaymentController中加入:


    @Resource
    private DiscoveryClient discoveryClient;	//springframework的DiscoveryClient(不要导错包了)
    

    @GetMapping("/payment/discovery")
    public Object discovery(){
        //获取服务列表的信息
        List<String> services = discoveryClient.getServices();
        for (String element : services) {
            log.info("*******element:" + element);
        }

        //获取CLOUD-PAYMENT-SERVICE服务的所有具体实例
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance instance : instances) {
            //getServiceId服务器id getHost主机名称 getPort端口号  getUri地址
            log.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
        }

        return this.discoveryClient;
    }

}
测试

对8001进行测试
,在浏览器输入:http://localhost:8001/payment/discovery
在这里插入图片描述
在这里插入图片描述

Eureka自我保护

概述

在这里插入图片描述

导致原因

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
只有在一定时间内丢失大量服务的心跳才开启自我保护模式。

禁止自我保护

先把cloud-eureka-server7001和cloud-provider-payment8001都切回单机版测试禁止自我保护。

cloud-eureka-server7001的yml文件:

#  client
#  	...		server与client对齐
  server:
    #关闭自我保护,默认为true
    enable-self-preservation: false
    #心跳的间隔时间,单位毫秒
    eviction-interval-timer-in-ms: 2000

cloud-provider-payment8001的yml文件:

    #Eureka客户端向服务端发送心跳的时间间隔,单位秒(默认30秒)
    lease-renewal-interval-in-seconds: 1
    #Eureka服务端在收到最后一次心跳后等待的时间上限,单位秒(默认90秒),超时剔除服务
    lease-expiration-duration-in-seconds: 2

启动注册中心和提供者:
在这里插入图片描述
然后关闭提供者(模拟网络延时),提供者直接被剔除。
在这里插入图片描述

六、Zookeeper服务注册与发现

注册中心Zookeeper

在这里插入图片描述

关闭linux的防火墙:

systemctl stop firewalld
systemctl status firewalld

在这里插入图片描述
使用docker启动Zookeeper:(docker的操作可以看这篇:Docker基础入门学习笔记

#拉取Zookeeper镜像
docker pull zookeeper

#启动Zookeeper
docker run --name zk01 -p 2181:2181 --restart always -d zookeeper
服务节点是临时节点还是持久节点?

zookeeper也是有心跳机制,在一定时间能如果一直没心跳返回,Zookeeper就会把服务节点剔除掉。所以在Zookeeper上的服务节点是临时节点

服务提供者

为了区分,中间空个8003。

  1. 新建工程cloud-provider-payment8004

  2. pom

    <!--因为接下来不会用到数据库,所以不导入数据库相关的依赖(防止没配置而报错)-->
    
    	<!--替换掉eureka依赖,其他直接复制8001-->
            <!--SpringBoot整合Zookeeper客户端-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <!--        <exclusions>-->
                <!--先排除自带的zookeeper3.5.3-->
    <!--            <exclusion>-->
    <!--                <groupId>org.apache.zookeeper</groupId>-->
    <!--                <artifactId>zookeeper</artifactId>-->
    <!--            </exclusion>-->
    <!--        </exclusions>-->
            </dependency>
    
            <!--添加zookeeper3.4.9版本(引入对应版本的依赖)-->
    <!--        <dependency>-->
    <!--            <groupId>org.apache.zookeeper</groupId>-->
    <!--            <artifactId>zookeeper</artifactId>-->
    <!--            <version>3.4.9</version>-->
    <!--        </dependency>-->
    
  3. yml

    #端口号
    server:
      port: 8004
    
    
    spring:
      application:
        #服务别名——注册到zookeeper注册中心的名称
        name: cloud-provider-payment
      cloud:
        zookeeper:
          connect-string: 10.211.55.17:2181 #linux的ip加暴露的端口号
    
  4. 主启动类

    @EnableDiscoveryClient	//该注解用于向使用consul或者Zookeeper作为注册中心时注册服务
    @SpringBootApplication
    public class PaymentMain8004 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8004.class, args);
        }
    }
    
  5. controller
    新建controller.PaymentController

    @Slf4j
    @RestController
    public class PaymentController {
    
        @Value("${server.port}")        //获取端口号
        private String serverPort;
    
        @RequestMapping("/payment/zk")
        public String paymentzk(){
            return "springcloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
        }
    
    }
    
  6. Zookeeper容器
    默认已经帮我们启动了服务端和客户端,如果想进去容器的话,使用下面的命令。

    #查看正在运行的容器(查看Zookeeper容器的id)
    docker ps
    
    #进入zookeeper容器
    docker exec -it 容器ID /bin/bash
    
    #退出容器(或者按快捷键ctrl+P+Q退出)
    exit
    #启动容器
    docker start 容器ID
    #关闭容器
    docker stop 容器ID
    
  7. 启动8004项目,浏览器输入http://localhost:8004/payment/zk
    在这里插入图片描述

  8. 进入Zookeeper容器(成功注册进注册中心)
    在这里插入图片描述
    在这里插入图片描述
    https://tool.lu/json/
    在这里插入图片描述

服务消费者

  1. 新建消费者模块cloud-consumerzk-order80。

  2. pom和yml直接复制8004。(yml中端口号改为80,应用名改为cloud-consumer-order,其他都相同)

  3. 主启动类。(与8004相同)

  4. 在springcloud包下新建config.ApplicationContextConfig

    @Configuration
    public class ApplicationContextConfig {
    
        @Bean
        @LoadBalanced   //负载均衡
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    
    }
    
  5. 新建controller.OrderZKController

    @RestController
    @Slf4j
    public class OrderZKController {
    
        public static final String INVOKE_URL = "http://cloud-provider-payment";
    
        @Resource
        private RestTemplate restTemplate;
    
        @RequestMapping("/consumer/payment/zk")
        public String paymentInfo(){
            String result = restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class);
            return result;
        }
    
    }
    
  6. 启动项目
    在这里插入图片描述
    http://localhost/consumer/payment/zk
    在这里插入图片描述

七、Consul服务注册与发现

Consul官网:https://www.consul.io/
Consul中文文档:https://www.springcloud.cc/spring-cloud-consul.html

简介

Consul是一种服务网格解决方案,提供具有服务发现,配置和分段功能的全功能控制平面。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建完整的服务网格。Consul需要一个数据平面,并支持代理和本机集成模型。Consul附带了一个简单的内置代理,因此一切都可以直接使用,还支持Envoy等第三方代理集成。
在这里插入图片描述

主要特点

  • 服务发现:Consul的客户端可以注册服务,例如 api或mysql,其他客户端可以使用Consul来发现给定服务的提供者。使用DNS或HTTP,应用程序可以轻松找到它们依赖的服务。

  • 健康检测:领事客户端可以提供任意数量的运行状况检查,这些检查可以与给定服务(“ Web服务器是否返回200 OK”)或本地节点(“内存利用率低于90%”)相关。操作员可以使用此信息来监视群集的运行状况,服务发现组件可以使用此信息将流量从不正常的主机发送出去。

  • KV存储:应用程序可以将Consul的分层键/值存储用于多种目的,包括动态配置,功能标记,协调,领导者选举等。简单的HTTP API使其易于使用。

  • 安全的服务通信:领事可以为服务生成并分发TLS证书,以建立相互TLS连接。 意图 可用于定义允许哪些服务进行通信。可以使用可以实时更改的意图轻松管理服务分段,而不必使用复杂的网络拓扑和静态防火墙规则。

  • 多数据中心:Consul开箱即用地支持多个数据中心。这意味着Consul的用户不必担心会构建其他抽象层以扩展到多个区域。

Consul旨在对DevOps社区和应用程序开发人员友好,使其非常适合现代,灵活的基础架构。

在docker上安装启动consul

#拉取consul镜像
docker pull consul

#启动consul
docker run -d  -p 8500:8500/tcp --name myConsul  consul agent -server -ui -bootstrap-expect=1 -client=0.0.0.0

然后在浏览器输入http://http://10.211.55.17/:8500(linux的IP地址加上冒号8500)
在这里插入图片描述

服务提供者

  1. 新建服务提供者cloud-provider-consul-payment8006。

  2. pom复制8004。(用下面的依赖替换Zookeeper的依赖)

 <!--SpringCloud consul-server-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-consul-discovery</artifactId>
  </dependency>
  1. yml
server:
  port: 8006


spring:
  application:
    name: consul-provider-payment
  cloud:
    consul:
      host: 10.211.55.17  #用linux的ip地址(consul在本机就填localhost)
      port: 8500
      discovery:
        service-name: ${spring.application.name}
  1. 主启动类(与8004相同)

  2. controller

    @RestController
    @Slf4j
    public class PaymentController {
    
        @Value("${server.port}")        //获取端口号
        private String serverPort;
    
        @RequestMapping("/payment/consul")
        public String paymentConsul(){
            return "springcloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
        }
    
    }
    
  3. 启动项目
    在这里插入图片描述
    http://localhost:8006/payment/consul
    在这里插入图片描述

服务消费者

  1. 新建模块cloud-consumer-consul-order80

  2. pom(与8006相同)

  3. yml(端口号为80,应用名为consul-consumer-order,其他和8006相同)

  4. 主启动类(与8006相同)

  5. config(和zk的消费者相同)

  6. controller.OrderConsulController

    @RestController
    @Slf4j
    public class OrderConsulController {
    
        public static final String INVOKE_URL = "http://consul-provider-payment";
    
        @Resource
        private RestTemplate restTemplate;
    
        @RequestMapping("/consumer/payment/consul")
        public String paymentInfo(){
            String result = restTemplate.getForObject(INVOKE_URL + "/payment/consul", String.class);
            return result;
        }
    
    }
    
  7. 启动项目
    在这里插入图片描述
    http://localhost/consumer/payment/consul
    在这里插入图片描述

三者的异同点

在这里插入图片描述

CAP:(只能二选一)
A:可用性
C:一致性
P:分区容错性(微服务架构必须保证有P)

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

下一篇笔记:最新的SpringCloud(H版&Alibaba)技术(8-9初级部分,服务调用【Ribbon与OpenFeign】)

学习视频(p15-p35):https://www.bilibili.com/video/BV18E411x7eT?p=15

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐