四畳半神话大系

Spring Cloud 疑难杂症(4): Feign 访问缓慢及调用出错

使用Feign调用其他微服务的方法时,有时会出现缓慢的情况。经过排查发现并不是被调用方法自身缓慢造成的,极有可能是在fegin连接其他微服务这一个过程花费较长时间。
可以进行如下优化

使用OkHttp3

替换掉原生HttpClient
引入新依赖

1
2
3
4
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>

配置文

1
2
3
4
5
6
7
8
9
10
11
12
feign:
httpclient:
enabled: false
okhttp:
enabled: true
hystrix:
enabled: true
client:
config:
default:
connectTimeout: 10000
readTimeout: 10000

注意 目前没有证据证明访问速度因为这个配置变快(2020-04-03)
Okhttp 参数配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@AutoConfigureBefore(FeignAutoConfiguration.class)
@Configuration
@ConditionalOnClass(Feign.class)
public class FeginOkHttpConfig {
private int feiginOkHttpReadTimeout = 60;
private int feignConnectTimeout = 60;
private int feignWriteTimeout = 120;

@Bean
public okhttp3.OkHttpClient okHttpClient() {
return new okhttp3.OkHttpClient.Builder()
.readTimeout(feiginOkHttpReadTimeout, TimeUnit.SECONDS)
.connectTimeout(feignConnectTimeout, TimeUnit.SECONDS)
.writeTimeout(feignWriteTimeout, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(10, 5L, TimeUnit.MINUTES))
.build();
}
}

Feign提前加载

feign是在使用时才进行加载,所以第一次访问时会有连接上的耗时,改成在程序启动时就进行加载可以加快连接速度

1
2
3
4
5
6
7
8
9
10
#ribbon的超时时间
ribbon:
eureka:
enabled: true
ReadTimeout: 10000
ConnectTimeout: 10000
eager-load:
enabled: true
# 调用的微服务名称
clients: deco-common-service

用户请求 content-length 覆盖到 微服务调用方法

Invalid character found in method name. HTTP method names must be tokens

遇到这里保存解决方法是情况外部请求头部中的 “content-type”, “content-length” 两个字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Slf4j
public class FeignConfiguration implements RequestInterceptor {
@Value("${rendering.token}")
private String token; // 验证是否是内部服务器发起的请求
private static final String X_CLIENT_TOKEN_USER = "x-service-token";

@Override
public void apply(RequestTemplate template) {
List<String> headNameList = Arrays.asList("content-type", "content-length");
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
template.header(X_CLIENT_TOKEN_USER, token);
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
// 如果透传了原来的content-length会导致长度不一致,从而服务提供方出现
// Invalid character found in method name. HTTP method names must be tokens
if (!headNameList.contains(name)) {
template.header(name, values);
}
}
log.debug("feign interceptor header:{}",template);
}
}
@Bean
public feign.Logger.Level feignLoggerLevel(){
return feign.Logger.Level.FULL;
}
}

专题:

本文发表于 2020-04-04,最后修改于 2020-04-04。

本站永久域名blog.amoyiki.com,也可搜索「 四畳半神话大系 」找到我。

期待关注我的 ,查看最近的文章和动态。


上一篇 « Spring Cloud 疑难杂症(3): docker swarm 环境下获取用户正确 IP 下一篇 » Spring Cloud 疑难杂症(5): docker swarm 环境下优雅更新服务

推荐阅读

Big Image