现象:
网关服务调用业务服务检查健康状态,如果业务服务异常会等60s后才会超时,大量请求阻塞,导致网关服务不能正常响应。
排查日志:
requestid:8614012eb9d342ae83c4a8c0eb7203c1
选择服务节点5100-->服务不可用-->选择服务节点5101
判断服务可用性耗时60s,查看相关代码
@Override
public boolean isServerAvailable(Server server) {
boolean isAvailable = false;
// target 链接目标feign,并指定访问域名
QuillFeignClient client = FeignClientUtil.getFeignClient(QuillFeignClient.class,
"http://" + server.getId());
try {
String resp = client.getHealthInfo();
if (resp != null) {
JSONObject obj = JSONObject.parseObject(resp);
if ("up".equals(obj.getString("status"))) {
isAvailable = true;
}
}
} catch (Exception e) {
logger.info("服务不可用:" + server);
}
return isAvailable;
}
/**
* 统一的 feign 接口实现类获取逻辑
*/
public static final <T> T getFeignClient(Class<T> clazz, String url) {
T feignClient = Feign.builder()
// 默认 http
.client(new Client.Default(null, null))
//3s超时,1次重试
.retryer(new Retryer.Default(3000, 3000, 1))
.target(clazz, url);
return feignClient;
}
new Client.Default 默认options构造器
82e97738-934c-4d18-a6a3-1ba61b4fedee.png
readTimeout默认耗时60s
调整超时时间:
/**
* 统一的 feign 接口实现类获取逻辑
*/
public static final <T> T getFeignClient(Class<T> clazz, String url) {
T feignClient = Feign.builder().options(new Request.Options(2L, TimeUnit.SECONDS, 2L, TimeUnit.SECONDS, true))
// 默认 http
.client(new Client.Default(null, null))
.target(clazz, url);
return feignClient;
}
connectTimeout: 2s ; readTimeout: 2s
去除重试逻辑,异常时客户端正常失败重试即可。
验证readTime,单元测试
调用方:
@Test
void getFeignClient() {
QuillFeignClient client = FeignClientUtil.getFeignClient(QuillFeignClient.class,"http://localhost:8084");
System.out.println(JSON.toJSONString(client.test()));
}
被调用方:
@ApiOperation("test")
@GetMapping("/test")
public RtData test(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ResponseBuilder.success("666");
}
结果:
feign.RetryableException: Read timed out executing GET http://localhost:8084/api/test
at feign.FeignException.errorExecuting(FeignException.java:249)
可以验证参数配置生效