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


    Eureka集群的构建

    • 原理说明
    1. Eureka的原理说明
    2. 微服务rpc远程服务调用中最重要的是什么?
      • 高可用, 试想假如只有一个注册中心, 一旦出故障, 则所有服务全部失效.
    3. 解决的方法就是搭建Eureka注册中心集群, 实现负载均衡+故障容错.
      • 集群对外暴露注册中心, 向内各个机器之间互相注册, 相互守望.
    • 集群环境构建步骤
    1. 新建cloud-eureka-server7002工程, 内容和cloud-eureka-server7001一致.
    2. 修改映射配置
      • 找到C:WindowsSystem32driversetc路径下的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()+"	"+instance.getHost()+"	"+instance.getPort()+"	"+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停更说明

  • 相关阅读:
    实验四 代码审查
    结对编程——阶段二
    实验二—结对编程第一环节
    实验一 GIT 代码版本管理
    实验五 单元测试
    实验四 代码评审
    实验三 UML建模工具的安装与使用
    实验二 结对编程第二阶段
    实验二 结对编程——第一阶段
    软件工程 实验一 GIT代码版本管理
  • 原文地址:https://www.cnblogs.com/binwenhome/p/13179227.html
Copyright © 2020-2023  润新知