1. Ribbon

  1. Ribbon概述
    Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。

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

ribbon 英 [ˈrɪbən] 美 [ˈrɪbən] n. (用于捆绑或装饰的)带子;丝带;带状物;狭长的东西;绶带;勋带

Github - Ribbon
Ribbon目前也进入维护模式。
Ribbon未来可能被Spring Cloud LoadBalacer替代,但因为ribbon技术成熟稳定的特点目前流行使用的仍是Ribbon

LB负载均衡(Load Balance)是什么
简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高可用)。
常见的负载均衡有软件Nginx,LVS,硬件F5等。

Ribbon本地负载均衡客户端VS Nginx服务端负载均衡区别
Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求。即负载均衡是由服务端实现的。
Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。

  • 集中式LB:即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方;
  • 进程内LB:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

前面我们讲解过了消费端80通过轮询负载访问8001/8002,一句话:负载均衡+RestTempldate

2. Ribbon的负载均衡和Rest调用

1. 架构说明

Ribbon其实就是一个软负载均衡的客户端组件,它可以和其他所需请求的客户端结合使用,和Eureka结合只是其中的一个实例
image.png
Ribbon在工作时分成两步:

  • 第一步先选择EurekaServer,它优先选择在同一个区域内负载较少的server
  • 第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址

其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权

2. pom.xml

先前工程项目没有引入spring-cloud-starter-ribbon也可以使用ribbon。

  1. <dependency>
  2. <groupld>org.springframework.cloud</groupld>
  3. <artifactld>spring-cloud-starter-netflix-ribbon</artifactld>
  4. </dependency>

这是因为spring-cloud-starter-netflix-eureka-client自带了spring-cloud-starter-ribbon引用
image.png

3. 二说RestTemplate的使用

RestTemplate Java Doc
RestTemplate中内置了两类方法

  • getForObject():返回对象为响应体中数据转化成的对象,基本上可以理解为Json
  • gostForEntity():返回对象为ResponseEntity对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等

update the Controller in Consumer

@GetMapping("/getForEntity/{id}")
public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
    ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL + "/payment/getByid/" + id, CommonResult.class);

    if (entity.getStatusCode().is2xxSuccessful()) {
        return entity.getBody();//getForObject()
    } else {
        return new CommonResult<>(444, "操作失败");
    }
}

3. Ribbon默认自带的负载规则

lRule:根据特定算法中从服务列表中选取一个要访问的服务四、服务调用 - 图3

IRule 接口源码

public interface IRule {
    Server choose(Object var1);

    void setLoadBalancer(ILoadBalancer var1);

    ILoadBalancer getLoadBalancer();
}

image.png

4. Ribbon负载规则替换

修改cloud-consumer-order80,自定义IRule负载均衡规则

1. 注意事项

官方文档明确给出了警告:
这个自定义配置类不能放在 @ComponentScan 所扫描的当前包下以及子包下,
否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了(也就是说不要将Ribbon配置类与主启动类同包

2. 新建package - com.gmf.myrule

image.png

3. 自定义负载均衡规则配置类

package com.gmf.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MySelfRule {
    /**
     * @param
     * @return com.netflix.loadbalancer.IRule
     * @description 配置自定义的负载均衡规则
     */
    @Bean
    public IRule myRule(){
        //设置规则为随机
        return new RandomRule();
    }
}

注意:类名不能为MyRule(与IOC容器组件冲突)

4. 主启动类声明负载均衡规则

import com.gmf.myrule.MySelfRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@SpringBootApplication
@EnableEurekaClient
//添加该注解声明服务使用指定的负载均衡规则
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class ConsumerMain80 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerMain80.class, args);
    }
}

5. 测试

开启cloud-eureka-server7001,cloud-eureka-server7002,cloud-consumer-order80,cloud-provider-payment8001,cloud-provider-payment8002
浏览器访问:http://localhost/consumer/payment/getForEntity/1
发现在通过服务负载均衡访问8001和8002时,不存在任何规律随机访问

5. Ribbon默认负载轮询算法原理

默认负载轮训算法: rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始
List instances = discoveryClient.getInstances(“CLOUD-PAYMENT-SERVICE”);

For Example:

  • 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,则获得服务地址为127.0.0.1:8002
  • 当总请求数位3时:3%2=1对应下标位置为1,则获得服务地址为127.0.0.1:8001
  • 当总请求数位4时:4%2=О对应下标位置为0,则获得服务地址为127.0.0.1:8002
  • 如此类推…

6. RoundRobinRule源码分析

IRule接口源码

public interface IRule{
    /*
     * choose one alive server from lb.allServers or
     * lb.upServers according to key
     * 
     * @return choosen Server object. NULL is returned if none
     *  server is available 
     */

    //重点关注这方法
    public Server choose(Object key);

    public void setLoadBalancer(ILoadBalancer lb);

    public ILoadBalancer getLoadBalancer();    
}

IRule 接口实现类 RoundRobinRule 源码

package com.netflix.loadbalancer;

import com.netflix.client.config.IClientConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * The most well known and basic load balancing strategy, i.e. Round Robin Rule.
 *
 * @author stonse
 * @author Nikos Michalakis <nikos@netflix.com>
 *
 */
public class RoundRobinRule extends AbstractLoadBalancerRule {

    private AtomicInteger nextServerCyclicCounter;
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;

    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public RoundRobinRule() {
        //原子整数初始化为0
        nextServerCyclicCounter = new AtomicInteger(0);
    }

    public RoundRobinRule(ILoadBalancer lb) {
        this();
        setLoadBalancer(lb);
    }

    //重点关注这方法。
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            //获取所有的服务
            List<Server> reachableServers = lb.getReachableServers();
            //获取所有可用的服务
            List<Server> allServers = lb.getAllServers();
            //获取服务数量
            int upCount = reachableServers.size();
            int serverCount = allServers.size();

            //如果不存在可用的服务则提示用户并返回false
            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

            //获取下一个被调用的服务接口索引(关注点,查看下方详细代码)
            int nextServerIndex = incrementAndGetModulo(serverCount);
            //通过索引获取指定的服务接口
            server = allServers.get(nextServerIndex);

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

    /**
     * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
     *
     * @param modulo The modulo to bound the value of the counter.
     * @return The next value.
     */
    private int incrementAndGetModulo(int modulo) {
        //CAS算法自旋锁
        for (;;) {
            //获取当前服务被调用的次数
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;//求余法
            //查看CAS知识内容
            if (nextServerCyclicCounter.compareAndSet(current, next))
                return next;
        }
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

7. Ribbon之手写轮询算法

自己试着写一个类似RoundRobinRule的本地负载均衡器

1. 7001/7002集群启动

2. 8001/8002微服务改造-controller

@Slf4j
@RestController
@RequestMapping("/payment")
public class PaymentController {

    //获取配置文件中的端口设置,用作展示区分
    @Value("${server.port}")
    private String port;

    ...

    /**
     * @param
     * @return java.lang.String
     * @description 测试手写轮询功能
     */
    @GetMapping("/lb")
    public String getPaymentLB(){
        return port;
    }
}

3. 消费端80微服务改造

ApplicationContextConfig去掉注解@LoadBalanced,主启动类去掉注解@RibbonClient

@SpringBootApplication
@EnableEurekaClient
//添加该注解声明服务使用指定的负载均衡规则
//@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class ConsumerMain80 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerMain80.class, args);
    }
}

@Configuration
public class ApplicationContextConfiguration {
    /**
     * @param  
     * @return org.springframework.web.client.RestTemplate
     * @description 配置类中注册RestTemplate,通过其进行远程调用
     */
    @Bean
    //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
    //@LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

4. 消费端创建LoadBalancer接口,及其实现类

LoadBanlancer.java

/**
 * @className: LoadBalancer
 * @description 负载均衡轮询规则获取调用服务
 * @author GMF
 * @date 2021/3/30
 * @time 18:12
*/
public interface LoadBalancer {
    /**
     * @param serviceInstances
     * @return org.springframework.cloud.client.ServiceInstance
     * @description 该方法实现从服务中使用轮询规则获取指定调用接口
     */
    ServiceInstance getServiceInstance(List<ServiceInstance> serviceInstances);
}

LoadBanlancerImpl.java

@Component //需要跟主启动类同包,或者在其子包下
public class LoadBalancerImpl implements LoadBalancer {
    //CAS自旋锁
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    private final int getAndIncrement() {
        int current;
        int next;
        do {
            current = atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current + 1;
        } while (!atomicInteger.compareAndSet(current, next));
        System.out.println("*****第几次访问,次数next: " + next);
        return next;
    }

    @Override
    public ServiceInstance getServiceInstance(List<ServiceInstance> serviceInstances) {
        //负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标  ,每次服务重启动后rest接口计数从1开始
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}

5. 修改消费端Controller

@RestController
@RequestMapping("/consumer/payment")
public class ConsumerController {
    @Autowired
    RestTemplate restTemplate;

    @Autowired
    private LoadBalancer loadBalancer;

    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * @param
     * @return java.lang.String
     * @description 使用RestTemplate向服务接口发送请求,使用自定义的轮询负载均衡规则
     */
    @GetMapping("/lb")
    public String getPaymentLB(){
        //通过服务名获取所有的服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        //使用自定义负载均衡轮询规则获取提供服务的实例
        ServiceInstance serviceInstance = loadBalancer.getServiceInstance(instances);
        //获取提供服务实例的URI网址(http://192.168.31.140:800x)
        URI uri = serviceInstance.getUri();
        System.out.println(uri);
        return restTemplate.getForObject(uri+"/payment/lb",String.class);
    }
}

6. 测试

浏览器多次访问http://localhost/consumer/payment/lb 可以看到8001/8002交替出现
查看控制台打印
image.png

2. OpenFeign

1. OpenFeign概述

官方文档
Github地址

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka, as well as Spring Cloud LoadBalancer to provide a load-balanced http client when using Feign. link

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

Feign能干什么

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

前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。

feign 英 [feɪn] 美 [feɪn] v. 假装,装作,佯装(有某种感觉或生病、疲倦等)

Feign集成了Ribbon

利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。

Feign和OpenFeign两者区别

Feign:是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

OpenFeign:是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@Feignclient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2. OpenFeign服务调用

使用微服务调用接口 + @FeignClient实现OpenFeign服务调用

1. 新建cloud-consumer-feign-order80

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>SpringCloud</artifactId>
        <groupId>org.gmf</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <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>org.gmf</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</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>

发现在OpenFeign中也集成了Ribbon
image.png

3. application.yaml

server:
  port: 80

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

4. 主启动类

@SpringBootApplication
@EnableFeignClients  //开启Feign客户端功能
public class OrderFeignMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderFeignMain80.class, args);
    }
}

5. Service业务逻辑接口+@FeignClient注解调用provider服务

新建PaymentFeignService接口并新增注解@FeignClient

import com.gmf.springcloud.entity.CommonResult;
import com.gmf.springcloud.entity.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Service
@FeignClient(";")
@RequestMapping("/payment")
public interface PaymentFeignService {
    @GetMapping("/getByid/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

6. Controller

@Slf4j
@RestController
@RequestMapping("/consumer/payment")
public class OrderFeignController {
    @Autowired
    private PaymentFeignService paymentFeignService;

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

7. 测试

先启动2个eureka集群7001/7002,再启动2个微服务8001/8002,启动OpenFeign启动
浏览器访问http://localhost/consumer/payment/getByid/1
显示结果:8001/8002服务实例轮流调用
总结:客户消费端接口使用@FeignClient注解,通过指定的服务名称去调用服务侧所能提供的服务实例方法,并且发现Feign自带负载均衡配置项

3. OpenFeign超时控制

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


1. 服务提供方8001/8002故意写暂停程序
@Slf4j
@RestController
@RequestMapping("/payment")
public class PaymentController {
    //获取配置文件中的端口设置,用作展示区分
    @Value("${server.port}")
    private String port;

    @GetMapping("/timeout")
    public String paymentFeignTimeout(){
        //程序耗时3秒
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return port;
    }

    ...
}


2. 消费端业务调用接口PaymentFeignService添加超时方法
@Service
@FeignClient("CLOUD-PAYMENT-SERVICE")
@RequestMapping("/payment")
public interface PaymentFeignService {
    ...

    @GetMapping("/timeout")
    public String paymentFeignTimeout();
}


3. 消费端OrderFeignController添加超时方法
@Slf4j
@RestController
@RequestMapping("/consumer/payment")
public class OrderFeignController {
    @Autowired
    private PaymentFeignService paymentFeignService;

    ...

    @GetMapping(value = "/feign/timeout")
    public String paymentFeignTimeout(){
        //Feign客户端一般默认等待1秒
        return paymentFeignService.paymentFeignTimeout();
    }
}

4. 测试

开启集群服务
浏览器访问超时controller:http://localhost/consumer/payment/feign/timeout
将会跳出错误Spring Boot默认错误页面,主要异常:feign.RetryableException:Read timed out executing GET http://CLOUD-PAYMENT-SERVCE/payment/feign/timeout
image.png
原因:微服务远程调用处理超时,而OpenFeign默认等待1秒钟,超过后报错

解决方法:YML文件里需要开启OpenFeign客户端超时控制

application.yaml中添加如下配置

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

设置完成后重新测试,成功返回数据

4. OpenFeign日志增强

日志打印功能

Feign提供了日志打印功能,我们可以通过配置来调整日恙级别,从而了解Feign 中 Http请求的细节。
说白了就是对Feign接口的调用情况进行监控和输出

日志级别

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
  • FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据

配置日志Bean

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

@Configuration
public class FeignConfiguration {
    /**
     * @param
     * @return feign.Logger.Level
     * @description 配置日志监控级别
     */
    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}

或者使用yaml文件配置

feign:
  client:
    config:
      default:
        #yaml文件配置日志级别
        loggerlevel: FULL

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

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

后台日志查看

启动集群服务,浏览器访问:http://localhost/consumer/payment/getByid/1 查看后台日志
image.png