面试题答案
一键面试网络层面优化
- 设置合适的超时时间
- 在Feign客户端配置中设置连接超时(
connectTimeout
)和读取超时(readTimeout
)。在application.yml
文件中可以这样配置:
feign: client: config: default: connectTimeout: 5000 readTimeout: 10000
- 源码角度:
FeignClientProperties
类负责读取这些配置属性,FeignClientFactoryBean
在创建Feign.Builder
时会根据这些配置设置超时时间。例如在FeignClientFactoryBean
的build
方法中:
feignBuilder.options(new Options(this.properties.getConnectTimeout(), this.properties.getReadTimeout()));
- 在Feign客户端配置中设置连接超时(
- 启用HTTP/2
- 对于Spring Boot应用,首先确保引入了支持HTTP/2的依赖,如
spring-boot-starter-webflux
(对于基于Reactor的应用)。然后在配置中启用HTTP/2,在application.yml
中:
server: http2: enabled: true
- Feign默认支持HTTP/2,当底层HTTP客户端(如OkHttp)配置为支持HTTP/2时,Feign会自动使用。从源码看,
OkHttpFeign
类在构建OkHttpClient
时可以通过配置启用HTTP/2,例如:
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); clientBuilder.protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1));
- 对于Spring Boot应用,首先确保引入了支持HTTP/2的依赖,如
连接管理优化
- 使用连接池
- 使用OkHttp连接池:引入
feign-okhttp
依赖,在application.yml
中配置:
feign: okhttp: enabled: true
- 源码层面,
OkHttpFeign
类在创建OkHttpClient
时会默认创建一个连接池。OkHttpClient.Builder
的connectionPool
方法用于设置连接池,默认连接池配置为:
即最大空闲连接数为5,连接存活时间为5分钟。public ConnectionPool() { this(5, 5, TimeUnit.MINUTES); }
- 使用OkHttp连接池:引入
- 优化连接参数
- 对于OkHttp连接池,可以进一步优化连接参数。例如,增加最大空闲连接数和连接存活时间:
这样可以根据实际业务流量更好地管理连接,减少连接创建和销毁的开销。OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); clientBuilder.connectionPool(new ConnectionPool(10, 10, TimeUnit.MINUTES));
请求重试优化
- 启用重试机制
- 引入
spring-retry
依赖,在application.yml
中配置Feign的重试:
feign: client: config: default: retryer: feign.Retryer.Default
- 源码角度,
Retryer.Default
类实现了重试逻辑。Retryer.Default
构造函数接受初始重试间隔、重试间隔乘数、最大重试次数等参数。默认配置为:
默认初始重试间隔为100毫秒,最大重试间隔为1000毫秒,最大重试次数为5次。public Default(int period, int maxPeriod, int maxAttempts) { this.period = period; this.maxPeriod = maxPeriod; this.maxAttempts = maxAttempts; }
- 引入
- 自定义重试策略
- 可以继承
Retryer
接口自定义重试策略。例如,根据不同的HTTP状态码决定是否重试:
然后在public class CustomRetryer implements Retryer { private int attempt; private final int period; private final int maxPeriod; private final int maxAttempts; public CustomRetryer(int period, int maxPeriod, int maxAttempts) { this.attempt = 0; this.period = period; this.maxPeriod = maxPeriod; this.maxAttempts = maxAttempts; } @Override public void continueOrPropagate(RetryableException e) { if (attempt++ >= maxAttempts) { throw e; } if (e.httpStatus() == 500 || e.httpStatus() == 502 || e.httpStatus() == 503) { long interval = Math.min(period * (1 << attempt), maxPeriod); try { Thread.sleep(interval); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); throw new RuntimeException("Retry interrupted", ignored); } } else { throw e; } } @Override public Retryer clone() { return new CustomRetryer(period, maxPeriod, maxAttempts); } }
application.yml
中指定自定义的重试器:
这样可以根据业务需求更灵活地控制重试行为,提高微服务在复杂网络环境下的稳定性。feign: client: config: default: retryer: com.example.CustomRetryer
- 可以继承