Feign声明式服务调用

Feign声明式服务调用

1.理解Feign

**Feign 是 Spring Cloud Netflix 组件中的一个轻量级 RESTful 的 HTTP 服务客户端,实现了负载均衡和 Rest 调用的开源框架,封装了 Ribbon 和 RestTemplate,**实现了 WebService 的面向接口编程,进一步降低了项目的耦合度。

Feign 内置了 Ribbon,用来做客户端负载均衡调用服务注册中心的服务

Feign 本身并不支持 Spring MVC 的注解,它有一套自己的注解,为了更方便的使用,Spring Cloud 孵化了 OpenFeign。

Feign 是一种声明式、模板化的 HTTP 客户端(仅在 Consumer 中使用)。

Feign 支持的注解和用法请参考官方文档: https://github.com/OpenFeign/feign 或 spring.io 官网文档

Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

2.Feign功能

Feign 旨在使编写 JAVA HTTP 客户端变得更加容易,Feign 简化了 RestTemplate 代码,实现了

Ribbon 负载均衡,使代码变得更加简洁,也少了客户端调用的代码,使用 Feign 实现负载均衡是首选方案。只需要你创建一个接口,然后在上面添加注解即可。

Feign 是声明式服务调用组件,其核心就是:像调用本地方法一样调用远程方法,无感知远程 HTTP 请求。

​ 它解决了让开发者调用远程接口就跟调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。无需关注与远程的交互细节,更无需关注分布式环境开发。

​ 它像 Dubbo 一样,Consumer 直接调用 Provider 接口方法,而不需要通过常规的 Http Client 构造请求再解析返回数据。

3.Feign&OpenFeign区别

OpenFeign 是 Spring Cloud 在 Feign 的基础上支持了 Spring MVC 的注解,如 @RequesMapping@Pathvariable 等等。

OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用服务。

4.Feign案例

在聚合的项目Eureka注册中心来添加消费者来更了解Feign

服务消费者添加:

  • Feign 依赖;
  • 创建业务层接口,添加 @FeignClient 注解声明需要调用的服务;业务层抽象方法使用 SpringMVC 注解配置服务地址及参数;启动类添加 @EnableFeignClients 注解激活 Feign 组件。
创建项目(service-consumer)

pom父工程可以看Eureka注册中心项目,就是改变消费服务

添加依赖
  <!-- 继承父依赖 -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>feign-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <properties>
        <!-- 项目打包和编译使用的编码字符集以及 jdk 版本 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <!-- 项目依赖 -->
    <dependencies>
        <!-- netflix eureka client 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- spring cloud openfeign 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- spring boot web 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok 依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- feign apache httpclient 依赖 -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>10.7.0</version>
        </dependency>

        <!-- spring boot test 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
配置文件
spring:
  application:
    name: service-consumer # 应用名称

# 端口
server:
  port: 8080
  compression:

# 配置 Eureka Server 注册中心
eureka:
  client:
    register-with-eureka: false         # 是否将自己注册到注册中心,默认为 true
    registry-fetch-interval-seconds: 10 # 表示 Eureka Client 间隔多久去服务器拉取注册信息,默认为 30 秒
    service-url:                        # 设置服务注册中心地址
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
消费服务
package com.example.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {

    private Integer id;
    private String username;
    private Integer age;

}
**
 * 用户管理
 */
// 声明需要调用的服务
@FeignClient("service-provider")
public interface UserService {

    /**
     * 查询用户列表
     *
     * @return
     */
    // 配置需要调用的服务地址及参数
    @GetMapping("/user/list")
    List<User> selectUserList();
}
控制层
/**
 * 用户管理
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 查询用户列表
     *
     * @return
     */
    @GetMapping("/manage")
    public List<User> userManage() {
        return userService.selectUserList();
    }
}
启动类
@SpringBootApplication
// 开启 FeignClients 注解
@EnableFeignClients
public class ServiceConsumerApplication {

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

访问: http://localhost:8080/user/manage

5.Feign请求传参

GET

使用 @PathVariable 注解或 @RequestParam 注解接收请求参数。

服务提供者
  /**
     * 根据主键查询用户
     * @param id
     * @return
     */
    User selectUserById(Integer id);
 /**
     * 根据主键查询参数
     *
     * @param id
     * @return
     */
    @Override
    public User selectUserById(Integer id) {
        return new User(1,"张三",20);
    }
 /**
     * 根据主键查询用户id
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public User selectUserById(@PathVariable("id") Integer id){
        return userService.selectUserById(id);
    }

服务消费者
// 声明需要调用的服务
@FeignClient("service-provider")
public interface UserService {

/**
     * 根据主键查询用户
     * @param id
     * @return
     */
    @GetMapping("/user/{id}")
    User selectByUserId(@PathVariable("id") Integer id);
}
 /**
     * 根据主键查询用户
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public User selectByUsername(@PathVariable("id") Integer id){
       return userService.selectByUserId(id);
    }

访问:: http://localhost:8080/user/1

POST

使用 @RequestBody 注解接收请求参数。

服务提供者
 /**
     * 根据用户名查询用户
     * @param username
     * @return
     */
    User selectUserByUsername(String username);

    /**
     * 新增用户
     * @param user
     * @return
     */
    Map<Object,Object> createUser(User user);

/**
     * 根据用户名查询用户
     * @param username
     * @return
     */
    @Override
    public User selectUserByUsername(String username) {
        return new User(1,username,20);
    }

    /**
     * 新增用户
     * @param user
     * @return
     */
    @Override
    public Map<Object, Object> createUser(User user) {
        System.out.println(user);
        return new HashMap<Object, Object>(){{
            put("code",200);
            put("message","新增成功");
        } };
    }
 /**
     * 根据用户名查询用户
     * @param username
     * @return
     */
    @PostMapping("/single")
    public  User selectUserByUsername(@RequestBody String username){
        return userService.selectUserByUsername(username);
    }

    /**
     * 新增用户
     * @param user
     * @return
     */
    @PostMapping("/save")
    public Map<Object,Object> createUser(@RequestBody  User user){
        return userService.createUser(user);
    }

服务消费者
 
// 声明需要调用的服务
@FeignClient("service-provider")
public interface UserService {
/**
     * 根据用户名查询用户
     * @param username
     * @return
     */
    @PostMapping("/user/single")
    User selectUserByUsername(String username);

    /**
     * 新增用户
     * @param user
     * @return
     */
    @PostMapping("/user/save")
    Map<Object,Object> createUser(User user);
}
  /**
     * 根据用户名来查询用户
     * @param username
     * @return
     */
    @PostMapping("/info")
    public User selectUserByUsername(String username){
        return userService.selectUserByUsername(username);
    }

    /**
     * 新增用户
     * @param user
     * @return
     */
    @PostMapping("/save")
    public Map<Object,Object> createUser(User user){
        return userService.createUser(user);
    }

访问: http://localhost:8080/user/info参数username=李四

http://localhost:8080/user/save参数 id=10&username=张三&age=20

6.Feign性能优化

Gzip压缩

gzip 介绍:gzip 是一种数据格式,采用 deflate 算法压缩数据;gzip 是一种流行的文件压缩算法,应用十分广泛,尤其是在 Linux 平台。

gzip 能力:当 Gzip 压缩一个纯文本文件时,效果是非常明显的,大约可以减少 70**%** 以上的文件大小。

gzip 作用:网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是 Gzip 与搜索引擎的抓取工具有着更好的关系。例如 Google 就可以通过直接读取 gzip 文件来比普通手工抓取更快地检索网页。

Http协议关于压缩传输的规定
  1. 客户端向服务器请求中带有: Accept-Encoding:gzip , deflate 字段,向服务器表示客户端支持的压缩格式(gzip 或者 deflate),如果不发送该消息头,服务端默认是不会压缩的。

  2. 服务端在收到请求之后,如果发现请求头中含有 Accept-Encoding 字段,并且支持该类型压缩,就会对响应报文压缩之后返回给客户端,并且携带 Content-Encoding:gzip 消息头,表示响应报文是根据该格式进行压缩的。

  3. 客户端接收到请求之后,先判断是否有 Content-Encoding 消息头,如果有,按该格式解压报文。否则按正常报文处理。

Gzip压缩案例

局部

只配置 Consumer 通过 Feign 到 Provider 的请求与相应的 Gzip 压缩。

服务消费者application.yml

# Feign gzip 压缩
feign:
 	compression:
    request:
      mime-types: text/xml,application/xml,application/json # 配置压缩支持的 MIME TYPE
      min-request-size: 512                                 # 配置压缩数据大小的最小阀值,默认 2048
      enabled: true                                         # 请求是否开启 gzip 压缩
    response:
      enabled: true                                         # 响应是否开启 gzip 压缩

全局

对客户端浏览器的请求以及 Consumer 对 Provider 的请求与响应都实现 Gzip 压缩。

服务消费者 application.yml

# 端口
server:
  port: 8080
  compression:
    # 是否开启压缩
    enabled: true
    # 配置压缩支持的 MIME TYPE
    mime-types: application/json,application/xml,text/html,text/xml,text/plain

访问:http://localhost:8080/user/manage

Http连接池
HTTP 的背景原理

​ 两台服务器建立 HTTP 连接的过程是很复杂的一个过程,涉及到多个数据包的交换,很耗时间。

HTTP 连接需要的 3 次握手 4 次挥手开销很大,这一开销对于大量的比较小的 HTTP 消息来说更大。

解决方法

Feign 的 HTTP 客户端支持 3 种框架: HttpURLConnection 、 HttpClient 、 OkHttp ;默认是 HttpURLConnection 。可以通过查看源码

org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration.ja va 得知。

​ 传统的 HttpURLConnection 是 JDK 自带的,并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。对于网络请求这种底层相对复杂的操作,如果有可用的其他方案,没有必要自己去管理连接对象。

HttpClient 相比传统 JDK 自带的 HttpURLConnection,它封装了访问 HTTP 的请求头,参数,内容

体,响应等等;它不仅使客户端发送 HTTP 请求变得容易,而且也方便了开发人员测试接口(基于 HTTP 协议的),既提高了开发的效率,又提高了代码的健壮性;另外高并发大量的请求网络的时候,也是用“连接池”提升吞吐量。

HttpClient

将 Feign 的 Http 客户端工具修改为 HttpClient。
添加依赖

 <!-- feign apache httpclient 依赖 -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>10.7.0</version>
        </dependency>

配置文件

feign:
  httpclient:
    enabled: true  #开启httpclient
服务提供者
 /**
     * 根据用户查询用户-接收用户对象参数
     * @param user
     * @return
     */
    User selectUserByPojo(User user);
  /**
     * 根据用户查询用户-接收用户对象参数
     * @param user
     * @return
     */
    @Override
    public User selectUserByPojo(User user) {
        System.out.println(user);
        return user;
    }
  @GetMapping("/single/pojo")
    public User selectUserByPojo(@RequestBody User user){
        return userService.selectUserByPojo(user);
    }
服务消费者
// 声明需要调用的服务
@FeignClient("service-provider")
public interface UserService {

/**
     *  根据用户名查询用户-接收用户对象参数
     * @param user
     * @return
     */
    @GetMapping("/user/single/pojo")
    User selectUserByPojo(User user);
}
    /**
     *  根据用户名查询用户-接收用户对象参数
     * @param user
     * @return
     */
    @GetMapping("/info/pojo")
    public User selectUserByPojo(User user){
        return userService.selectUserByPojo(user);
    }

访问:http://localhost:8080/user/info/pojo?id=10&username=zhangsan&age=20

状态查看

浏览器发起的请求我们可以借助 F12 Devtools 中的 Network 来查看请求和响应信息。对于微服务中每个接口我们又该如何查看URL,状态码和耗时信息?我们可以使用配置日志的方式进行查看。

添加logback.xml

Consumer项目添加logback.xml日志文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
    <!-- 日志上下文名称 -->
    <contextName>my_logback</contextName>
    <!-- name的值是变量的名称,value的值是变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="${catalina.base}/service-consumer/logs"/>

    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 输出到文件 -->
    <!-- 时间滚动输出 level为 DEBUG 日志 -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_debug.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志归档 -->
            <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 每个日志文件最大100MB -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
            <!-- 日志量最大 10 GB -->
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 对于类路径以 com.example.logback 开头的Logger,输出级别设置为warn,并且只输出到控制台 -->
    <!-- 这个logger没有指定appender,它会继承root节点中定义的那些appender -->
    <!-- <logger name="com.example.logback" level="warn"/> -->

    <!--通过 LoggerFactory.getLogger("myLog") 可以获取到这个logger-->
    <!--由于这个logger自动继承了root的appender,root中已经有stdout的appender了,自己这边又引入了stdout的appender-->
    <!--如果没有设置 additivity="false" ,就会导致一条日志在控制台输出两次的情况-->
    <!--additivity表示要不要使用rootLogger配置的appender进行输出-->
    <logger name="myLog" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>

    <!-- 日志输出级别及方式 -->
    <root level="DEBUG">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="DEBUG_FILE"/>
        <appender-ref ref="INFO_FILE"/>
        <appender-ref ref="WARN_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>

</configuration>

请求超时

Feign 的负载均衡底层用的就是 Ribbon,所以这里的请求超时配置其实就是配置 Ribbon。

分布式项目中,服务压力比较大的情况下,可能处理服务的过程需要花费一定的时间,而默认情况下请求超时的配置是 1s 所以我们需要调整该配置延长请求超时时间。

全局

Consumer 项目中配置请求超时的处理。

ribbon:
  ConnectTimeout: 5000 # 请求连接的超时时间 默认的时间为 1 秒
  ReadTimeout: 5000    # 请求处理的超时时间
局部

一般我们会根据服务的压力大小配置不同的服务超时处理,使用局部配置。

# service-provider 是需要调用的服务名称
service-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    OkToRetryOnAllOperations: true  # 对所有请求都进行重试
    MaxAutoRetries: 2               # 对当前实例的重试次数
    MaxAutoRetriesNextServer: 0     # 切换实例的重试次数
    ConnectTimeout: 3000            # 请求连接的超时时间
    ReadTimeout: 3000               # 请求处理的超时时间
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 创作都市 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读