SpringCloud(H版&alibaba) Ribbon OpenFeign

本文详细介绍了SpringCloud中的Ribbon和OpenFeign组件,讲解了Ribbon的负载均衡原理和Rest调用,包括自定义负载均衡策略。接着探讨了OpenFeign的超时控制和日志增强功能,以及如何在微服务中实现服务调用的便捷性和优雅性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Ribbon OpenFeign

OpenFeign 点击跳转

Ribbon 的负载均衡 和 Rest调用

Spring Cloud Ribbon 是 Netflix Ribbon 实现的一套客户端 负载均衡工具

简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供 客户端的复杂就哼算法和服务调用。 Ribbon
客户端组件提供一系列完善的配置项如超时、重试等。简单的说,就是配置文件中列出 load Balancer (简称
LB)后面所有的机器,Ribbon 会自动的帮助你基于某种规则(如简单轮询,随机链接等)去链接这些机器。我们很容易使用 Ribbon
自定义的负载均衡算法。

  • 进程内 LB

    将 LB 逻辑集成到消费方,消费方从服务注册中心获取有哪些地址可用,然后自己再从这些地址中选择一个适合的服务器。

    Ribbon 就属于进程内 LB,它只是一个类库,集成于消费方进程,消费方通过它阿莱获取服务提供方的地址。

blog.csdnimg.cn/20200404201749875.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTQyMDIzMQ==,size_16,color_FFFFFF,t_70)

@Resource
private RestTemplate restTemplate;
*

restTemplate.getForEntity(PAYMENT_URL + “/payment/get/” + id, CommonResult.class);

在这里插入图片描述
entity.toString():

<200,CommonResult(code=200, message=查询成功 ,serverPort:8001, data={id=41, serial=999}),
Content-Type:"application/json", 
Transfer-Encoding:"chunked", 
Date:"Sat, 04 Apr 2020 06:23:09 GMT",
 Keep-Alive:"timeout=60", 
 Connection:"keep-alive"]>
 
换行
200

换行

在这里插入图片描述

Ribbon 负载规则的替换

IRule :
在这里插入图片描述

官方文档明确给出了警告:
这个自定义配置类不能放在 @CommpomentScan 所扫描的当前包下以及子包下,
否则我们自定义的这个规则类会被所有的 Ribbon 客户端共享,达不到特殊定制化的目的

在这里插入图片描述

2 主启动类添加 @RibbonClient
在启动该微服务的时候就能去加载我们的自定义 Ribbon 配置类,从而使配置生效


测试结果 : 随机
在这里插入图片描述

Ribbon 负载均衡算法的原理

**负载均衡算法:rest 接口第几次请求数 % 服务器集群总数量 = 时机调用服务器位置下标,每次服务重启后rest 接口技术求从1开始。

List instances = discoverClient.getInstances(“PAYMENT-SERVICE”);
如: List[0] instances = 127.0.0.1:8002
List[1] instances = 127.0.0.1:8001

8001 + 8002 组合为集群,他们共计2台服务器,集群总数为2 , 按照轮询算法原理:
当请求总数为1 时:1%2 = 1, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8001
当请求总数为2 时:2%2 = 0, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8002
当请求总数为3 时:2%2 = 1, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8001
依次类推 。。。。**

手写一个 负载均衡算法

在这里插入图片描述
2 LoadBalancer 接口
在这里插入图片描述
3. MyLb实现类

@Slf4j
@Component
public class MyLB implements LoadBalancer {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    private final int getAndIncrement() {
        int current;
        int next;
        do {
            current = this.atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current + 1;
        } while (this.atomicInteger.compareAndSet(current, next));
        log.info(" =====> 第几次访问 next: {}", next);
        return next;
    }

    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}

4.OrderController

 @Resource
    private DiscoveryClient discoveryClient;
    @Resource
    private LoadBalancer loadBalancer;

  * 路由规则:轮询
     * @param
     * @return
     */
    @GetMapping(value = "/cc/payment/lb")
    public String getPaymentLB(){
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PROVIDER-SERVICE");
        if(instances == null || instances.size() <= 0){
            return null;
        }

        ServiceInstance serviceInstance = loadBalancer.instances(instances);

        URI uri = serviceInstance.getUri();

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

5.测试
在这里插入图片描述
轮询出现,(没啥意义,默认也是这样的)

2. OpenFeign

标题0 //锚点设置
在这里插入图片描述
Feign 能干什么 ?

  • Feign 旨在使编写 Java HTTP 客户端变得更加容易。

    前面在使用 Ribbon + RestTemplate 时, 利用 RestTemplate
    请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,对于服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常会针对每个微服务自行封装一些客户端类来包装这些服务依赖的调用。

    所以,Feign 在此基础上除了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign
    的实现下,我们只需要创建一个可口,并使用注解的方式来配置它(以前是Dao 接口上main标注 Mapper
    注解,现在是一个微服务接口上面标注一个Feign 注解即可),即可完成对一个服务提供方的接口绑定,简化了使用 Spring cloud
    Ribbon 时, 自动封装服务调用客户端的开发量。

    Reign 集成了 Ribbon 利用 Ribbon 维护了服务方的服务列表信息,并且通过伦序实现了客户端的负载均衡,而 Ribbon
    不同的是,通过reign 只需要定义服务绑定接口且一声明式的方法,优雅而简单的实现了服务调用。

OpenFeign
openfeign 是 spring cloud 在 feign 的基础上支持 spring mvc 注解 ,如 @RequestMapping 等等,OpenFeign 的 @FeignClient 可以解析Spring MVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式生产实现类 ,实现类中做负载均衡并且用其他服务。
依赖

1.0 OpenFegin 的服务调用
在这里插入图片描述

  1. 新建 cloud-consumer-feign-order80

1.2 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-feign-order80</artifactId>

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

3. application.yml

server:
  port: 81
  
eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka

4. 主启动类

package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients //开启Feign
public class OrderFeignMain80 {

    public static void main(String[] args) {
        SpringApplication.run(OrderFeignMain80.class,args);
    }
}

5. 业务类
在这里插入图片描述


//业务逻辑接口 + @FeignClient 配置调用provider服务
package com.atguigu.springcloud.service;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;


@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")  //指定调用哪个微服务
public interface PaymentFeignService {

    @GetMapping(value = "/payment/get/{id}")    //哪个地址
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

}
package com.atguigu.springcloud.controller;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentFeignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;


@RestController
@Slf4j
public class OrderFeignController {

    @Resource
    private PaymentFeignService paymentFeignService;

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

6. 测试
先启动2个eureka集群 7001/7002
在启动2个微服务 8001/8002
启动OpenFeign 80

轮询出现
在这里插入图片描述
在这里插入图片描述
**

OpenFeign 超时控制

1.1 8001,8002 PaymenController 中添加 一个 超时 的方法

 @GetMapping(value = "/payment/feign/timeout")
    public String paymentTimeout(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return serverPort;
    }

1.2 在 PaymentFeignService 添加方法

@GetMapping(value = "/payment/feign/timeout")
    public String paymentTimeout();

在这里插入图片描述

1.3 Controller

 /**
     * feign  超时控制
     * @return
     */
    @GetMapping(value = "/consumer/payment/feign/timeout")
    public String paymentTimeout(){
        return paymentFeignService.paymentTimeout();
    }

整体图展示


在这里插入图片描述


1.4 测试
在这里插入图片描述

1.5 修改配置

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

再次 测试 ,即可以成功看到端口号

OpenFeign日志增强

openfeign提供了日志打印功能。
Logger有四种类型:NONE(默认)、BASIC、HEADERS、FULL,通过注册Bean来设置日志记录级别

1.0 配置 Bean

package com.atguigu.springcloud.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;       //全部日志信息
    }
}

2.0 yml

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

访问 : http://localhost:81/consumer/payment/get/31
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值