Spring Cloud

Spring Cloud Alibaba & H

1. 建表SQL

1.1 支付模块

1.1.1 payment

create table payment(
    id varchar(64) not null,
    serial varchar(200) default '',
    primary key(id)
);

1.1.2


2. Mybatis-Plus-Generator

2.1 使用要求

  • 尽量不自己写SQL
  • 使用plus提供的IService接口,通过门面IFacade接口调用
  • 业务逻辑在 FacadeImpl 实现类中写,Iservice实现类,Mapper接口不屑任何东西
  • 数据库实体对象是 XxxxxEntity
  • 输入对象为 BO
  • 返回对象为VO

3. 服务注册与发现

CAP理论

什么是CAP ?

  1. C : Consistency (强一致性)
  2. A : Availability (可用性)
  3. P : Partition tolerance (分区容错性)

Eureka , Zookeeper , Consul 比较

  • Eureka : AP
  • Consul : CP
  • Zookeeper : CP

3.1 Eureka 服务注册与发现

  1. Eureka Server

提供服务注册,各个服务启动后会在Server中进行注册,服务注册表将会存储所有可用服务节点的信息,可以在界面中看到。

  1. Eureka Client

    通过注册中心进行访问,客户端内置一个使用轮询(round-robin)算法的负载均衡器。在应用启动后会向Server发送默认周期为30秒的心跳包,如果Server在多个心跳周期内没有收到某个节点的心跳i,Server会将该节点从服务注册表中移除(一般默认90秒,3个心跳周期)。

  2. Eureka 集群

    • 修改 C/Windows/System32/drivers/etc/hosts 配置

      127.0.0.1  eureka7001.com
      127.0.0.1  eureka7002.com
      
    • 改写yml配置,eureka server互相注册

      • Eureka Server 7001

        server.port=7001
        spring.application.name=cloud-eureka-server7001
        
        eureka.instance.hostname=eureka7001.com
        # false 表示不想注册中心注册自己
        eureka.client.register-with-eureka=false
        # 表示我自己就是服务端,不需要取检索服务
        eureka.client.fetch-registry=false
        eureka.client.service-url.defaultZone=http://eureka7002.com:7002/eureka/
        
      • Eureka Server 7002

        server.port=7002
        spring.application.name=cloud-eureka-server7002
        
        eureka.instance.hostname=eureka7002.com
        # false 表示不想注册中心注册自己
        eureka.client.register-with-eureka=false
        # 表示我自己就是服务端,不需要取检索服务
        eureka.client.fetch-registry=false
        eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka/
        
    • cloud-provider-payment 服务注册到 Eureka Server 集群上

      eureka.client.register-with-eureka=true
      eureka.client.fetch-registry=true
      eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      
    • 支付模块10010 和 10011 两个服务注册发现,调用,服务名同一个

      • cloud-provider-payment10010

        server.port=10010
        spring.application.name=cloud-payment-service
        
      • cloud-provider-payment10011

        server.port=10011
        spring.application.name=cloud-payment-service
        
      • cloud-consumer-order 微服务单机版调用 cloud-provider-payment10010 服务

        public static final String PAYMENT_URL="http://localhost:10010";
        
            @Resource
            private RestTemplate restTemplate;
        
            @GetMapping("/consumer/payment/create/{serial}")
            public CommonResult create(@PathVariable("serial") String serial){
                return restTemplate.getForObject(PAYMENT_URL+"/payment/post/"+serial,CommonResult.class);
            }
        
      • 多个微服务调用模式:不能写死服务请求地址,可以通过服务名指定(多个微服务同一个服务名)

        @LoadBalanced 配置 RestTemplate 负载均衡:让应用知道如何调用多个微服务

        @Configuration
        public class ConsumerOrderConfig {
            @Bean
            @LoadBalanced
            public RestTemplate getRestTemplate(){
                return new RestTemplate();
            }
        }
        
        public static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";
        
    • 微服务界面展示的服务名,IP信息配置修改

      # eureka 管理界面 STATUS 栏展示的名称
      eureka.instance.instance-id=paymentService10010
      # 显示IP地址(鼠标浮动上去展示IP地址)
      eureka.instance.prefer-ip-address=true
      
  3. Eureka 服务发现 Discovery

    • 添加组件

      /**
      * 注入服务发现组件
      * import org.springframework.cloud.client.discovery.DiscoveryClient;
      */
      @Resource
      private DiscoveryClient discoveryClient;
      
    • 模拟 服务发现,打印获取到的服务信息

      @GetMapping("/payment/discovery")
          public Object discovery(){
              // 获取所有的微服务名
              List services = discoveryClient.getServices();
              for (String service : services) {
                  log.info("service=",service);
              }
              // 获取指定微服务名下的实例,如CLOUD-PAYMENT-SERVICE服务名下有两个实例微服务
              // cloud-provider-payment10010,cloud-provider-payment10011
              List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
              for (ServiceInstance instance : instances) {
                  log.info("instance=",instance);
                  log.info(instance.getInstanceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
              }
              return discoveryClient;
          }
      
    • 在主启动类上添加注解 @EnableDiscoveryClient , 开启服务发现机制。

  4. Eureka 自我保护理论

    • 自我保护模式下,服务一旦注册进服务注册表后,挂掉的服务不会立刻清掉。属于AP理论分支。

    • 如何禁止自我保护模式:

      1. Eureka-Server7001 的 yml配置

        # 关闭禁止自我保护模式
        eureka.server.enable-self-preservation=false
        eureka.server.eviction-interval-timer-in-ms=2000
        
      2. Eureka-Client :cloud-provider-payment10010 服务配置

        # 修改 Eureka 客户端向服务端发送心跳的时间间隔(默认30秒,改成1秒)
        eureka.instance.lease-renewal-interval-in-seconds=1
        # 收到最后一次心跳服务端等待的时间上限(默认是90秒,改成2秒)
        eureka.instance.lease-expiration-duration-in-seconds=2
        
    • Eureka 目前很少使用

3.2 Zookeeper 服务注册发现

  1. zookeeper 是什么 ?

    zookeeper是分布式协调工具,可以完成注册中心的功能。

  2. zookeeper 安装

    • centos7

    • zookeeper-3.4.9/bin

    • 基本操作

      # 关闭防火墙
      systemctl stop firewalld
      
  3. 服务提供者:新建 cloud-provider-payment10012模块,引入zookeeper客户端依赖

    
            
                org.springframework.cloud
                spring-cloud-starter-zookeeper-discovery
            
    
    如果提示 jar 包冲突错误,排除掉apache自带的zookeeper
    
                org.springframework.cloud
                spring-cloud-starter-zookeeper-discovery
                
                    
                        org.apache.zookeeper
                        zookeeper
                    
                
            
    
  4. 修改主启动类注解

    @EnableDiscoveryClient 该注解用于向consul或zookeeper作为注册中心时注册服务使用

    @SpringBootApplication
    @MapperScan("com.dc.scloud.mapper")
    @EnableDiscoveryClient
    public class ProviderPaymentApplication10012 {
        public static void main(String[] args) {
            SpringApplication.run(ProviderPaymentApplication10012.class);
        }
    }
    
  5. 修改 properties 文件

    # 安装 zookeeper工具的虚拟机IP
    spring.cloud.zookeeper.connect-string=192.168.111.144:2181
    
  6. 修改 controller

    @Slf4j
    @RestController
    public class PaymentController {
    
        @Autowired
        private IPaymentFacade iPaymentFacade;
    
        @Value("${server.port}")
        private String servicePort;
    
        @GetMapping("/payment/zk/list")
        public CommonResult paymentWithZK(){
            String msg="spring cloud payment service ,port="+servicePort+ ", "+UUID.randomUUID().toString();
            CommonResult stringCommonResult = new CommonResult<>(200,msg,msg);
            return stringCommonResult;
        }
    }
    
  7. 服务消费者:cloud-consumerzk-order10008

    • 启动类配置

      @SpringBootApplication
      @EnableDiscoveryClient
      public class ConsumerZKOrderApplication10008 {
          public static void main(String[] args) {
              SpringApplication.run(ConsumerZKOrderApplication10008.class);
          }
      }
      
    • controller

      @RestController
      @Slf4j
      public class OrderController {
      
          //public static final String PAYMENT_URL="http://localhost:10010";
          public static final String PAYMENT_URL="http://cloud-provider-payment10012";
      
          @Resource
          private RestTemplate restTemplate;
      
          @GetMapping("/consumer/payment/query/{id}")
          public CommonResult queryPayment(@PathVariable("id") String id){
             return restTemplate.getForObject(PAYMENT_URL+"/payment/zk/list",CommonResult.class);
          }
      }
      
    • zookeeper 中的服务名区分大小写的

3.3 Consul 服务注册与发现

  1. 什么是 Consul ?

    consul是一套分布式服务发现和配置管理系统,提供了服务之间的服务治理,配置中心,控制总线等。

  2. 服务提供者注册进consul:cloud-providerconsul-payment10016

    • pom.xml

      
                  org.springframework.cloud
                  spring-cloud-starter-consul-discovery
              
      
    • application.properties

      server.port=10016
      spring.application.name=cloud-payment-service10016
      
      # 单机
      spring.cloud.consul.host=localhost
      spring.cloud.consul.port=8500
      spring.cloud.consul.discovery.service-name=${spring.application.name}
      
    • controller

      @Slf4j
      @RestController
      public class PaymentController {
      
          @Value("${server.port}")
          private String servicePort;
      
          @GetMapping("/payment/consul/list")
          public CommonResult paymentWithZK(){
              String msg="spring cloud payment service ,port="+servicePort+ ", "+UUID.randomUUID().toString();
              CommonResult stringCommonResult = new CommonResult<>(200,msg,msg);
              return stringCommonResult;
          }
      }
      
    • 启动类

      @SpringBootApplication
      @EnableDiscoveryClient
      public class ProviderConsulPayment10016 {
          public static void main(String[] args) {
              SpringApplication.run(ProviderConsulPayment10016.class);
          }
      }
      
  3. 服务消费者注册进consul:cloud-consumerconsul-order10008

    • pom.xml

      
                  org.springframework.cloud
                  spring-cloud-starter-consul-discovery
              
      
    • properties

      server.port=10008
      spring.application.name=cloud-consumerconsul-order10008
      
      # 单机
      spring.cloud.consul.host=localhost
      spring.cloud.consul.port=8500
      spring.cloud.consul.discovery.service-name=${spring.application.name}
      
    • controller

      @RestController
      @Slf4j
      public class OrderController {
      
          //public static final String PAYMENT_URL="http://localhost:10010";
          public static final String PAYMENT_URL="http://cloud-payment-service10016";
      
          @Resource
          private RestTemplate restTemplate;
      
          @GetMapping("/consumer/consul/query")
          public CommonResult queryPayment(){
             return restTemplate.getForObject(PAYMENT_URL+"/payment/consul/list",CommonResult.class);
          }
      }
      
    • MainApplication.class

      @SpringBootApplication
      @EnableDiscoveryClient
      public class ProviderConsulPayment10016 {
          public static void main(String[] args) {
              SpringApplication.run(ProviderConsulPayment10016.class);
          }
      }
      

4. Ribbon 负载均衡 cloud-consumer-order

4.1 理论

  • Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡的工具。提供客户端的软件负载均衡算法和服务调用。

  • LB 负载均衡(Load Balance)是什么?

    1. 将用户的请求平摊到多个服务上,常见的负载软件有:Nginx,LVS;硬件F5等。

    2. Ribbon是本地负载均衡

      在调用微服务接口时,会在注册中心上获取注册信息服务列表缓存到JVM本地,在本地实现RPC远程服务调用技术。

    3. Nginx是服务端负载均衡

      所有的请求都交给Nginx,由Nginx实现请求转发。

4.2 ribbon负载均衡和Rest调用

  1. spring-cloud-starter-netflix-eureka-client 已经集成了 ribbon 依赖

  2. Ribbon 默认时 轮询机制

    
                org.springframework.cloud
                spring-cloud-starter-netflix-eureka-client
            
    

4.3 ribbon 替换负载规则

  1. Ribbon 规则替换配置类不能在主启动类所在包及其子包路径下。

  2. 新建包:package com.dc.myrule;

  3. 随机算法:自定义配置类

    @Configuration
    public class MyRibbonRule {
        /**
         * 配置随机算法进行负载
         * @return
         */
        @Bean
        public IRule myRule(){
            return new RandomRule();
        }
    }
    
  4. @RibbonClient 主启动类指定对某个微服务设置某种负载策略

    @SpringBootApplication
    @EnableEurekaClient
    @RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyRibbonRule.class)
    public class ConsumerOrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerOrderApplication.class);
        }
    }
    

4.4 轮询算法原理 RoundRobinRule

  1. 负载均衡算法:
    • rest接口第几次请求数 % 服务器集群总数 = 实际调用服务器位置下标 ;
    • 每一次服务重启后rest接口计数从1开始;

5. OpenFeign

5.1 什么是 Feign ?

  1. Feign 是一个声明式WebService客户端。使用方法是:定义一个服务接口,然后在其上添加注解。Feign也支持可插拔式的编码器和解码器。Spring Cloud 对Feign进行了封装,使其支持了SpringMVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用支持负载均衡。

  2. Feign 与 OpenFeign 的比较

    Feign OpenFeign
    OpenFeign是 SpringCloud在Feign基础上支持了SpringMVC的注解。
    org.springframework.cloud spring-cloud-starter-feign org.springframework.cloud spring-cloud-starter-openfeign

5.2 Feign 服务调用

  1. 新建 cloud-consumeropenfeign-order10008 微服务

  2. 注入依赖pom

     
                org.springframework.cloud
                spring-cloud-starter-openfeign
            
    
            
                org.springframework.cloud
                spring-cloud-starter-netflix-eureka-client
            
    
  3. 开启 Feign

    @SpringBootApplication
    @EnableFeignClients
    public class ConsumerOpenFeignOrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerOpenFeignOrderApplication.class);
        }
    }
    
  4. 定义业务类的接口

    @Component
    @FeignClient("CLOUD-PAYMENT-SERVICE")   // 指定请求调用哪一个微服务
    public interface IPaymentFeignService {
    
        @GetMapping(value = "/payment/list/{id}")  // CLOUD-PAYMENT-SERVICE mapper 地址
        public CommonResult getParmentById(@PathVariable("id") String id);
    
    }
    
  5. 定义Controller 层

    @ResponseBody
    @RestController
    @Slf4j
    public class FeignOrderController {
        @Resource
        private IPaymentFeignService iPaymentFeignService;
    
        @GetMapping(value = "/consumer/order/feign/list/{id}")
        public CommonResult getPaymentVOById(@PathVariable("id") String id){
            return iPaymentFeignService.getParmentById(id);
        }
    }
    

5.3 Feign 超时控制

默认Feign客户端只等待1秒,但是服务端处理时间超过1秒,直接发会报错。

在 properties 中配置默认设置:

ribbon.ReadTimeout=5000
ribbon.ConnectTimeout=5000

5.4 Feign 日志增强

  1. 自定义配置类

    @Configuration
    public class FeignConfig {
        @Bean
        Logger.Level feignLoggerLevel(){
            return Logger.Level.FULL;
        }
    }
    
  2. 配置 yml / properties

    # 开启 feign 日志 : 以哪一种日志级别监控哪一个feign接口
    logging.level.com.dc.scloud.service.IPaymentFeignService=debug
    

你可能感兴趣的:(Spring Cloud)