springcloud-Eureka服务注册发现02(二)

Eureka集群的构建

  • 原理说明
  1. Eureka的原理说明
  2. 微服务rpc远程服务调用中最重要的是什么?
    • 高可用, 试想假如只有一个注册中心, 一旦出故障, 则所有服务全部失效.
  3. 解决的方法就是搭建Eureka注册中心集群, 实现负载均衡+故障容错.
    • 集群对外暴露注册中心, 向内各个机器之间互相注册, 相互守望.
  • 集群环境构建步骤
  1. 新建cloud-eureka-server7002工程, 内容和cloud-eureka-server7001一致.
  2. 修改映射配置
    • 找到C:\Windows\System32\drivers\etc路径下的hosts文件
    • 增加如下内容
  3. 写yml
    • cloud-eureka-server7001
      server:
        port: 7001
      
      eureka:
        instance:
          hostname: eureka7001.com
        client:
          register-with-eureka: false
          fetch-registry: false
          service-url:
            defaultZone: http://eureka7002.com:7002/eureka/
    • cloud-eureka-server7002
      server:
        port: 7002
      
      eureka:
        instance:
          hostname: eureka7002.com
        client:
          register-with-eureka: false
          fetch-registry: false
          service-url:
            defaultZone: http://eureka7001.com:7001/eureka/
  • 将订单/支付这两个微服务注册进eureka集群
    • 只需修改一个地方, 即eureka.client.service-url.defaultZone
      <!-- 注册到集群的所有机器中 -->
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
  • 支付微服务8001的集群配置
  1. 结构图示
  2. 参考cloud-provider-payment8001创建cloud-provider-payment8002, 注意修改端口号.
  3. 修改PaymentController.java
    @RestController
    @Slf4j
    public class PaymentController {
    
        @Resource
        private PaymentService paymentService;
    
        @Value("${server.port}")
        private String serverPort;
    
        @PostMapping(value = "/payment/create")
        public CommonResult create(@RequestBody Payment payment) {
            int result = paymentService.create(payment);
            log.info("插入结果: " + result + "aaa");
            if (result > 0) {
                return new CommonResult(200, "插入数据库成功, serverPort:"+serverPort, result);
            }
            return new CommonResult(444, "插入数据库失败");
        }
    
        @GetMapping(value = "/payment/get/{id}")
        public CommonResult getPaymentById(@PathVariable("id") Long id) {
            Payment payment = paymentService.getPaymentById(id);
            log.info("插入结果: " + payment + "haha");
            if (payment != null) {
                return new CommonResult(200, "查询成功, serverPort:"+serverPort, payment);
            }
            return new CommonResult(444, "没有对应记录, 查询ID:" + id);
        }
    }
  • 负载均衡
  1. 完成以上步骤后, 我们使用发现始终调用8001, 这是因为订单服务访问地址写死了.
    • 在cloud-consumer-order80中, 把原先的地址+端口号改为服务名
      @RestController
      @Slf4j
      public class OrderController {
      
          //private static final String PAYMENT_URL = "http://localhost:8001";
          private static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
      
          @Resource
          private RestTemplate restTemplate;
      
          //浏览器只能发get请求, 但下面调用的实质是post请求
          @GetMapping("/consumer/payment/create")
          public CommonResult<Payment> create(Payment payment) {
      
              log.info(payment.toString());
              String url = PAYMENT_URL + "/payment/create";
              return restTemplate.postForObject(url, payment, CommonResult.class);
          }
      
          @GetMapping("/consumer/payment/get/{id}")
          public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
      
              String url = PAYMENT_URL + "/payment/get/" + id;
              return restTemplate.getForObject(url, CommonResult.class);
          }
      }
    • 服务名在这里看
  2. 但此时我们访问: http://localhost/consumer/payment/get/1 报错了.
    • 因为服务名下可能有多个地址, 系统不知道改访问哪个.
    • 所以我们需要加入负载均衡功能告诉系统选哪个.
  3. 使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
    • 默认采取轮循机制
      @Configuration
      public class ApplicationContextConfig {
      
          //使用@LoadBalanced注解赋予了RestTemplate负载均衡的能力
          @LoadBalanced
          @Bean
          public RestTemplate getRestTemplate() {
              return new RestTemplate();
          }
      }
      • 实际上这是Ribbon的负载均衡功能, 同时, Ribbon和Eureka整合后Consumer可以直接调用服务而不用关心地址和端口号.

actuator微服务信息完善

  1. 必须导入如下依赖
        <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>
  2. 主机名称: 服务名称修改
    • 修改yml文件
      eureka.instance.instance-id: payment8001
      
      ---
      
      eureka.instance.instance-id: payment8002
    • 效果
  3. 访问信息有ip信息提示
    • 修改yml文件
      eureka.instance.prefer-ip-address: true
    • 鼠标放到上图的服务名时会有其ip提示.

服务发现Discovery

  1. 对于注册到Eureka的微服务, 可以通过服务发现来获得该服务的信息
  2. 以cloud-provider-server8001为例
    • 修改其controller
          @Resource
          private DiscoveryClient discoveryClient;
      
          @GetMapping(value = "/payment/discovery")
          public CommonResult discover() {
              List<String> services = discoveryClient.getServices();
              for(String element : services) {
                  log.info(element);
              }
      
              List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
              for(ServiceInstance instance : instances) {
                  log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
              }
              return new CommonResult(200, "DiscoveryClient结果", discoveryClient);
          }
    • 在主启动类加注解@EnableDiscoveryClient
      @EnableDiscoveryClient
      //表示这是一个Eureka客户端
      @EnableEurekaClient
      @SpringBootApplication
      public class PaymentMain8001 {
      
          public static void main(String[] args) {
              SpringApplication.run(PaymentMain8001.class, args);
          }
      }
  3. 测试: http://localhost:8001/payment/discovery

Eureka自我保护机制

  • 概述
  1. 保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护.
  2. 一旦进入保护模式, Eureka Server将尝试保护其服务注册表中的信息, 不再删除服务注册表中的数据, 即不会注销任何微服务.
  3. 如果在Eureka Server的首页看到如下提示, 则说明Eureka进入了保护模式
  4. 一句话理解, 就是某时刻某一个微服务不可用了, Eureka不会立即清理, 依旧会对该微服务的信息进行保存.
  • 为什么会产生Eureka自我保护机制?
  1. 防止EurekaClient可以正常运行, 但是与Eureka Server网络不通情况下, Eureka Server不会立刻剔除EurekaClient服务.
  2. 这种模式是一种应对网络异常的安全保护措施, 它的架构哲学是宁可同时保留所有微服务, 也不盲目注销任何健康的微服务.
  3. 使用自我保护模式, 可以让Eureka集群更健壮, 稳定.
  4. 这属于CAP理论中的AP分支
  • 禁止自我保护(一般生产环境不会禁止自我保护)
  1. 以cloud-eureka-server7001和cloud-provider-server8001为例
  2. 注册中心Eureka Server端7001
    • 默认自我保护机制是开启的
    • 关闭自我保护机制(application.yml中配置)
      eureka.server.enable-self-preservation=false
      eureka.server.eviction-interval-timer-in-ms: 2000 #修改心跳时间为2000ms
  3. 生产者客户端EurekaClient8001
    • 默认
      eureka.instance.lease-renewal-interval-in-seconds=30 #Eureka客户端向服务端发送心跳的时间间隔, 单位为秒(默认30秒)
      eureka.instance.lease-expiration-duration-in-seconds=90 #Eureka服务端在收到最后一次心跳后等待时间上限, 单位为秒(默认90秒), 超时将剔除服务

Eureka停更说明

posted @ 2020-06-22 21:24  yellowstreak  阅读(202)  评论(0编辑  收藏  举报