微服务系列:服务调用 Spring Cloud 之 OpenFeign 性能优化

2,496 阅读5分钟

上一篇文章:微服务系列:服务调用 Spring Cloud 之 OpenFeign 详细入门 我们已经能够学习到很多 OpenFeign 的入门知识,今天,我们来学习一下 OpenFeign 性能优化的相关配置。

话不多说,开始今天的学习。

日志增强

浏览器发起的请求可以通过F12查看请求和响应信息。如果想看微服务中每个接口我们可以使用日志配置方式进行查看详细信息。

OpenFeign 虽然提供了日志增强功能,但是默认是不显示任何日志的,不过开发者在调试阶段可以自己配置日志的级别。

OpenFeign 的日志级别如下:

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

配置如下:

1. 设置接口日志级别

application.yml 文件中

logging:
  level:
    com.ezhang.auth.service: debug

com.ezhang.auth.service: debug 是接口所在的包名

image.png

当然设置日志级别使用配置文件 logback.xml 设置也是一样的。

注:

关于 Spring Boot Logging 配置贴一篇其他大佬的文章详解 Spring Boot Logging 配置

2. 配置类中配置 OpenFeign 日志级别

自定义一个配置类,在其中设置日志级别,这样是全局的配置

@Configuration
public class FeignConfiguration {
    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}

局部配置,在客户端接口指定此配置

configuration = FeignConfiguration.class

@FeignClient(contextId = "remoteUserService", value = "cloud-system", fallbackFactory = RemoteUserFallbackFactory.class, configuration = FeignConfiguration.class)
public interface RemoteUserService {

    @GetMapping(value = "/user/getUserInfo")
    Map<String, Object> getUserInfo(@RequestParam("userId") int userId);

}

3. 效果

发送请求 http://localhost:9203/test/getUserInfo?userId=2,控制台上就可以看到详细的请求信息啦。

image.png

GZIP 压缩

介绍

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

能力

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

作用

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

OpenFeign 开启 GZIP 步骤:

1. 项目中启用 gzip 压缩

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

2. 在 Feign 服务提供方开启 gzip 压缩

feign:
  compression:
    request:
      # 开启请求压缩
      enabled: true
      # 配置支持压缩的 MINE TYPE
      mime-types: text/xml,application/xml,application/json
      # 配置压缩数据大小的下限
      min-request-size: 2048
    response:
      # 开启响应压缩
      enabled: true

3. 效果

上述配置完成后,发起请求,观察控制台日志:

image.png

Http 连接池

两台服务器建立HTTP连接的过程涉及到多个数据包的交换,很消耗时间。采用HTTP连接池可以节约大量的时间提示吞吐量。

FeignHTTP客户端支持3种框架:HttpURLConnectionHttpClientOkHttp

观察源码可以发现,Feign 默认是采用java.net.HttpURLConnection 的,每次请求都会建立、关闭连接。

首先查看 FeignRibbonClient 的自动配置类 FeignRibbonClientAutoConfiguration,该类在程序启动的时候注入一些 Bean,其中注入了一个 BeanName 为 feignClient 的 Client 类型的 Bean。在省缺配置 BeanName 为 FeignClient 的 Bean 的情况下,会自动注入 Client.Default 这个对象,跟踪Client.Default 源码, Client.Default 使用的网络请求框架是 HttpURLConnection,代码如下:

public static class Default implements Client {
    private final SSLSocketFactory sslContextFactory;
    private final HostnameVerifier hostnameVerifier;
    private final boolean disableRequestBuffering;
    
    public Response execute(Request request, Options options) throws IOException {
        HttpURLConnection connection = this.convertAndSend(request, options);
        return this.convertResponse(connection, request);
    }
    // 省略其他源码
}

为了性能考虑,我们可以引入httpclientokhttp作为底层的通信框架。

例如将 FeignHTTP 客户端工具修改为 HttpClient

1. 添加依赖

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

2. 配置文件中开启

feign:
  # 开启 httpclient
  httpclient:
    enabled: true

3. 如何验证

feign.SynchronousMethodHandler#executeAndDecode()这个方法中可以清楚的看出调用哪个 client。

在未替换 httpclient 之前,是这样的:

image.png

替换成功之后是这样的:

image.png

4. 源码分析

我们来查看下 HttpClientFeignLoadBalancedConfiguration 的源码:

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({ApacheHttpClient.class})
@ConditionalOnProperty(
    value = {"feign.httpclient.enabled"},
    matchIfMissing = true
)
@Import({HttpClientFeignConfiguration.class})
class HttpClientFeignLoadBalancedConfiguration {
    HttpClientFeignLoadBalancedConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean({Client.class})
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory, HttpClient httpClient) {
        ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
        return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
    }
}

@ConditionalOnProperty 注解可知,配置文件中开启 httpclient 可以不写,因为在默认情况下就为true。

@Import({HttpClientFeignConfiguration.class}) HttpClientFeignConfiguration 这个配置类感兴趣的小伙伴可以自己看看。

熔断降级

常见的熔断降级框架有HystrixSentinel,openFeign默认支持的就是Hystrix

其实在上一篇文章中已经有了熔断降级的实现 微服务系列:服务调用 Spring Cloud 之 OpenFeign 详细入门

fallbackFactory = RemoteUserFallbackFactory.class

这里就不再赘述了。包括可以换成集成 Sentinel 来实现熔断降级。

其实不管是Hystrix还是Sentinel对于Feign的支持,核心代码基本上是一致的,只需要修改依赖和配置文件即可。

其他

除了上面这些优化之外,还有个没有写,就是 请求超时配置,这个准备再整一篇文章写一写。因为感觉小篇幅还搞不定。。。

feign 可以设置请求超时时间,ribbon 可以设置,hystrix 也可以设置。

如何统筹考虑 ribbon、feign、hystrix 三者之间的关系,添加合适的配置,使得各个组件各司其职、协调合作, 是一个麻烦的问题。

想想就令人头秃。

PS: 都看到这里了,点个赞吧,彦祖!

文章参考:openFeign夺命连环9问,这谁受得了?