SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)

服务调用

  • 一、Ribbon 负载均衡调用
    • 概述
      • (1) 是什么
      • (2) 官网资料
      • (3) 能干嘛
    • Ribbon 负载均衡演示
      • (1) 架构说明
      • (2) POM
      • (3) 二说RestTemplate的使用
        • ① 官网
        • ② getForObject方法 / getForEntity方法 (Get 请求方法)
    • Ribbon 核心组件 IRule
      • (1) IRule:根据特定算法从服务列表中选取一个要访问的服务
      • (2) 如何替换
        • ① 修改cloud-consumer-order80
        • ② 注意配置细节
        • ③ 新建包 myrule
        • ④ 新建类 MySelfRule
        • ⑤ 主启动类添加@RibbonClient
    • Ribbon 负载均衡算法
      • (1) 原理
      • (2) 手写轮询算法
        • ① 7001/7002集群 和 8001/8002集群启动
        • ② 80订单微服务改造
  • 二、OpenFeign服务接口调用
    • 概述
      • (1) OpenFeign 是什么
      • (2) OpenFeign 能干嘛
      • (3) Feign和OpenFeign两者区别
    • OpenFeign 使用步骤
      • (1) 接口+注解
      • (2) 新建模块 cloud-consumer-feign-order80
      • (3) 配置 pom.xml
      • (4) 配置 application.xml
      • (5) 创建主启动类
      • (6) 编写业务类
        • ① Service层:PaymentFeignService
        • ② Controller层:OrderFeignController
      • (7) 测试
      • (8) 小总结
    • OpenFeign 超时控制
      • (1) 超时设置,故意设置超时演示出错情况
        • ① 服务提供方8001故意写暂停程序
        • ② 服务消费方80添加超时方法PaymentFeignService
        • ③ 服务消费方80添加超时方法OrderFeignController
        • ④ 测试
      • (2) 超时的原因:
      • (3) 解决方法:
    • OpenFeign 日志打印功能
      • (1) 是什么
      • (2) 日志级别
      • (3) 配置日志bean:FeignConfig
      • (4) YML文件里需要开启日志的Feign客户端
      • (5) 测试


一、Ribbon 负载均衡调用

概述

(1) 是什么

在这里插入图片描述

(2) 官网资料

https://github.com/Netflix/ribbon/wiki/Getting-Started

Ribbon目前也进入维护模式,未来的替换方案如下
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第1张图片

(3) 能干嘛

LB (负载均衡)
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第2张图片

  • 集中式LB在这里插入图片描述

  • 进程内LB在这里插入图片描述

前面的80通过轮询负载访问8001/8002,即 负载均衡 + RestTemplate调用


Ribbon 负载均衡演示

(1) 架构说明

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第3张图片
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第4张图片
总结 : Ribbon其实就是一个软负载均衡的客户端组件, 他可以和其他所需请求的客户端结合使用,和eureka结合只是其中一个实例


(2) POM

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第5张图片
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第6张图片

(3) 二说RestTemplate的使用

① 官网

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第7张图片

② getForObject方法 / getForEntity方法 (Get 请求方法)

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第8张图片
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第9张图片
还有 postForObject / postForEntity (Post 请求方法)


Ribbon 核心组件 IRule

(1) IRule:根据特定算法从服务列表中选取一个要访问的服务

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第10张图片

  • com.netflix.loadbalancer.RoundRobinRule — 轮询
  • com.netflix.loadbalancer.RandomRule — 随机
  • com.netflix.loadbalancer.RetryRule — 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务
  • WeightedResponseTimeRule — 对RoundRobinRule的扩展,响应速度越快的实例选择权重越多大,越容易被选择
  • BestAvailableRule — 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  • AvailabilityFilteringRule — 先过滤掉故障实例,再选择并发较小的实例
  • ZoneAvoidanceRule — 默认规则,复合判断server所在区域的性能和server的可用性选择服务器

(2) 如何替换

① 修改cloud-consumer-order80

② 注意配置细节

在这里插入图片描述
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第11张图片
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第12张图片

③ 新建包 myrule

根据前面说的官方文档中的警告,不要被@ComponentScan扫描到,否则达不到特殊化定制的目的

而springboot项目中的@ComponentScan就在主启动类上的@SpringBootApplication中(源码中可以看到),所以为了避免被扫到,就不要和主启动类在同一个包下

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第13张图片

④ 新建类 MySelfRule

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第14张图片

@Configuration
public class MySelfRule {
     
    @Bean
    public IRule myRule() {
     
        // 将默认的轮换算法替换为随机算法
        return new RandomRule();
    }
}

⑤ 主启动类添加@RibbonClient

@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第15张图片


Ribbon 负载均衡算法

(1) 原理

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第16张图片

(2) 手写轮询算法

① 7001/7002集群 和 8001/8002集群启动

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第17张图片

② 80订单微服务改造

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第18张图片
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第19张图片

创建接口: LoadBalancer

public interface LoadBalancer {
     
    // 从服务集群中选择出本次来提供服务的一个service
    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}

创建 LoadBalancer 接口的实现类 MyLB

@Component
public class MyLB implements LoadBalancer {
     

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    // 提供服务的次数
    public final int getAndIncrement() {
     
        int current;
        int next;

        do {
     
            current = this.atomicInteger.get();
            next = (current+1) % Integer.MAX_VALUE;
        }while(!this.atomicInteger.compareAndSet(current, next));
        System.out.println("-------第" + next +  "次访问");
        return next;
    }


    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
     
        // 轮询,需要提供服务的实例下标
        int index = getAndIncrement() % serviceInstances.size();

        // 返回该服务实例
        return serviceInstances.get(index);
    }
}

在 8001 和 8002的 PaymentController 上增加逻辑代码 (添加相同的代码)

@GetMapping("/payment/lb")
public String getPaymentLB() {
     
    return serverPort;
}

在 80 的 OrderController 添加业务逻辑

// 注意别导错包
@Resource
private DiscoveryClient discoveryClient;

// 注入的是接口,不是实现类
@Resource
private LoadBalancer loadBalancer;

@GetMapping("/consumer/payment/lb")
public String getPaymentLB() {
     

    // 获取服务名为:cloud-payment-service 的所有实例
    List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service");

    if (instances == null || instances.size() <= 0) {
     
        return null;
    }

    // 调用方法,得到本次提供服务的实例
    ServiceInstance instance = loadBalancer.instances(instances);

    URI uri = instance.getUri();

    return restTemplate.getForObject(uri + "/payment/lb", String.class);
}

二、OpenFeign服务接口调用

概述

(1) OpenFeign 是什么

https://github.com/spring-cloud/spring-cloud-openfeign

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第20张图片

(2) OpenFeign 能干嘛

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第21张图片

(3) Feign和OpenFeign两者区别

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第22张图片

OpenFeign 使用步骤

(1) 接口+注解

微服务调用接口 + @FeignClient

(2) 新建模块 cloud-consumer-feign-order80

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第23张图片

(3) 配置 pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2020artifactId>
        <groupId>com.atguigu.springcloudgroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>cloud-consumer-feign-order80artifactId>

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
        dependency>
        <dependency>
            <groupId>com.atguigu.springcloudgroupId>
            <artifactId>cloud-api-commonsartifactId>
            <version>${project.version}version>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <scope>runtimescope>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>com.atguigu.springcloudgroupId>
            <artifactId>cloud-api-commonsartifactId>
            <version>1.0-SNAPSHOTversion>
            <scope>compilescope>
        dependency>
    dependencies>

project>

(4) 配置 application.xml

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

(5) 创建主启动类

@SpringBootApplication
@EnableFeignClients // 开启FeignClient功能,后面使用@FeignClient注解才有效
public class OrderFeignMain80 {
     
    public static void main(String[] args) {
     
        SpringApplication.run(OrderFeignMain80.class, args);
    }
}

(6) 编写业务类

① Service层:PaymentFeignService

@Component
//可以远程调用该服务名的controller
@FeignClient("CLOUD-PAYMENT-SERVICE") 
public interface PaymentFeignService {
     

    @GetMapping("/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

}

② Controller层:OrderFeignController

@RestController
@Slf4j
public class OrderFeignController {
     
    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
     
        return paymentFeignService.getPaymentById(id);
    }
    
}

(7) 测试

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第24张图片

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第25张图片
SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第26张图片

(8) 小总结

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第27张图片


OpenFeign 超时控制

(1) 超时设置,故意设置超时演示出错情况

① 服务提供方8001故意写暂停程序

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第28张图片

@GetMapping("/payment/Feign/Timeout")
public String paymentFeignTimeout() throws InterruptedException {
     
    // 延迟3s
    TimeUnit.SECONDS.sleep(3000);

    return serverPort;
}

② 服务消费方80添加超时方法PaymentFeignService

@GetMapping("/payment/Feign/Timeout")
public String paymentFeignTimeout();

③ 服务消费方80添加超时方法OrderFeignController

@GetMapping("/consumer/payment/Feign/Timeout")
public String paymentFeignTimeout() {
     
    return paymentFeignService.paymentFeignTimeout();
}

④ 测试

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第29张图片


(2) 超时的原因:

OpenFeign默认等待1秒钟,超过后报错

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第30张图片

(3) 解决方法:

#设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位:毫秒)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第31张图片


OpenFeign 日志打印功能

(1) 是什么

在这里插入图片描述

(2) 日志级别

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第32张图片

(3) 配置日志bean:FeignConfig

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第33张图片

@Configuration
public class FeignConfig {
     
    // feignClient配置日志级别
    @Bean
    public Logger.Level feignLoggerLevel() {
     
        // 请求和响应的头信息,请求和响应的正文及元数据
        return Logger.Level.FULL;
    }
}

(4) YML文件里需要开启日志的Feign客户端

logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.atguigu.springcloud.service.PaymentFeignService: debug

(5) 测试

SpringCloud 【三】 --- 服务调用 (Ribbon,OpenFeign)_第34张图片

你可能感兴趣的:(springcloud,分布式,springcloud,Ribbon)