现象
在SDMK的管理后台的订单管理模块中,发现获取订单列表数据的延迟非常高。经过测试,发现该接口在生产环境中的延迟竟然达到2.5S左右。
因此,我开始排查测试环境的接口,发现测试环境的接口稳定在500ms左右。说明这两个环境可能存在某种差异。这两个环境代码一致,环境配置一致,说明可能是哪个环节出现了问题。
慢慢开始排查这个接口的调用链信息,因为我们用的是微服务架构,每个接口可能会涉及多个模块。所以要在每个调用处添加日志打印以及记录调用接口调用时间。
比如:
long start = System.currentTimeMillis();
//接口调用
long end = System.currentTimeMillis();
invokeLogger.info("该接口耗时:{} ms", (end - start));
类似这样的代码添加在了多处调用点。
在测试环境,数据库请求在10ms以内,网络接口请求在20ms左右,并没有发现任何异常信息。
因此,想着在生产环境的一个节点部署下该版本,查验下究竟是哪里出现了问题。
果不其然,发现在请求官网账户中心的接口时,发现该接口不稳定,一直维持在90ms~200ms之间。
既然发现了问题所在,就要着手去解决。要解决这个问题有两种方案:
- 给官网账户中心提需求,优化该接口。
- 根据我们的业务需求,绕过请求官网账户中心。
目前来看第二种比较现实一点,因为第一种,需要跟他们沟通、提需求,这些都是时间成本,因此还不如自己动手来的快。
最后经过优化、改善,接口的调用稳定在200ms。
回顾
回顾这次问题。我们不难发现,在微服务架构中,多个服务相互调用的情况很常见。因此,服务间的调用日志、监控必不可少。难道我们需要像前面那样,每处网络调用都要加这几行代码么?先不说繁琐,万一漏掉了某处,恰好这处出现了问题,到时候排查问题的时候可能会更麻烦。
因此,可以从网络请求处着手,我们一般都是用的第三方客户端比如apache的httpClient。我们可以借此封装自己的客户端,在网络的请求以及响应处添加自己的业务逻辑。这样就可以监控到每一处的网络请求。
我们的项目中有些是用SpringBoot框架,其中基本上都是用的spring提供的RestTemplate。因此,我对它做了点小小的添加,来达到我监控网络请求的目的。
RestTemplate自己提供了添加拦截器的方法。
/**
* Sets the request interceptors that this accessor should use.
*/
public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
this.interceptors = interceptors;
}
因此,我们实现相应的拦截器就好了。
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor{
final private Logger invokeLogger = LoggerFactory.getLogger("invokeLog");
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
return writeLog(request, body, execution);
}
private ClientHttpResponse writeLog(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
long start = System.currentTimeMillis();
ClientHttpResponse response = execution.execute(request, body);
long end = System.currentTimeMillis();
InvokeLog invokeLog = new InvokeLog(request.getURI().toString(), (end-start), response.getRawStatusCode());
invokeLogger.info(invokeLog.toString());
return response;
}
}
然后在配置RestTemplate的时候添加上该拦截器:
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add( new LoggingRequestInterceptor());
restTemplate.setInterceptors(interceptors);
这就简单的实现了在SpringBoot框架下实现了网络请求的统一监控。
但是这仅仅是只是监控某个服务的网络调用。并无法来监控整个调用链的。如果想尝试针对整个调用链的监控,可以试试zipkin。
网友评论