解决问题的思路和方法和步骤,解决问题的思维导图

首页 > 育儿 > 作者:YD1662022-12-17 03:09:40

解决问题的思路和方法和步骤,解决问题的思维导图(1)

思考的过程比结论更重要

背景

遇到问题,有时候很难找到原因,然后就卡在一个地方无法推进。

需要总结下排查思路,提升排查问题的效率。

比如从全链路的视角来分析问题、从数据流动的方向去逐个排查

出现的问题

一个导出excel的功能,接入已有的下载中心模块后,状态一直是失败。

在日志平台中也搜不到相关的日志,正常的日志打印和异常的都没有。

处理过程

涉及功能的数据流如下所示:

解决问题的思路和方法和步骤,解决问题的思维导图(2)

导出功能涉及到的数据流

step1:分析日志

发现导出没有成功后,就到日志平台上查日志。

可以找到“数据服务”打印的日志;

没有找到“下载中心服务”的日志;

从已有的应用日志来看,“数据服务”是正常的。

由于没有traceId,就没有办法筛选出整个请求过程的所有应用日志信息。

traceId丢失的原因:请求“数据服务”的动作是由MQ的消费者发起的,这种场景,uat【User Acceptance Test】环境中的应用日志中的traceId为空

那么问题很可能是在“下载中心服务”。

现在这个服务又搜不到日志,怎么办?

搜不到日志有两种原因:

1、日志平台 有问题

2、搜索的关键词不合适

日志平台是基于ES实现,搜索结果与分词器、关键词 关系密切相关, 有时候关键词不对也查不到日志。

就目前的情况看,很难区分是日志平台出问题了,还是搜索的关键词不对。毕竟是uat环境,有问题也不会花力气去处理。

step2: 阻塞了,陷入困境

数据已经取到了,为什么状态一直是失败呢?

排查一下子陷入困境。想进一步排查需要看日志,目前没搜到日志。

要想解决目前的问题,需要先解决眼前的新的问题:为什么在日志平台搜不到日志?

感觉这个问题有些花时间,且眼前还有别的问题,就没有继续排查。

有同学会问:为什么不在本地调一下?

因为uat环境和本地用的同一个MQ。本地发的消息很可能让uat上的消费者消费了。

就是拼人品了,也蛮花时间的。

攻克问题的二波攻势

“日志平台”有没有问题?

梳理下日志平台收集数据的原理,顺着数据流排查一下。

解决问题的思路和方法和步骤,解决问题的思维导图(3)

日志平台的数据流

排查的顺序:

1、应用打印日志的配置是否正常

2、应用打印的日志是否在约定的目录

3、应用的日志是否被收集到日志平台

step1:直接去uat环境上查看日志打印。由于是uat环境出问题了,本地正常不等于uat正常

解决问题的思路和方法和步骤,解决问题的思维导图(4)

有日志

日志是有的。

step2: 这个看不了。找有权限的同学查看了下,没有!!!

指定的目录为什么没有日志文件?

这个文件是在应用中指定的。在应用中重新指定,然后发版,发现日志平台上已经可以搜到日志了。

思考:

第一次遇到这种问题时,没有往日志平台异常的方向上想,觉得这个地方已经running了这么久了,不会有问题的。

这个思考的方向,会影响到问题解决的过程,多走一些弯路。

如何避免呢?

按经验初步判断后,如果一击不中。那就按照数据流动的方向,逐个节点排查

这个办法看着比较笨,但整体上看,是可以提升解决的效率。

原因

导出失败的原因,是接入下载中心的方式错误,根据错误日志fix下接入的姿势就好了。

小结

在排查问题时按经验初步判断后,如果一击不中。说明问题常常在意想不到的地方

按照数据流动的方向,逐个节点排查,反而是最高效,也是最有效的。

只要给时间,没有那个问题是解决不了的。

额外的收获

给Feign添加的access log也是有效的。之前没有日志平台上没搜到,还以为是Open Feign的新版本有变化。

show the code:

import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { @Bean public Logger.Level loggerLevel() { return Logger.Level.BASIC; } } import feign.Logger; import feign.request; import feign.Response; import feign.Util; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.io.IOException; import static feign.Util.UTF_8; import static feign.Util.decodeOrDefault; @Slf4j @Component public class AdminFeignLogger extends Logger { @Value("${log.threshold.cost.s:3}") private long logWarnTagThreshold; @Override protected void log(String configKey, String format, Object... args) { log.info("FeignLogger {} {} ", configKey, String.format(format, args)); } @Override protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime) throws IOException { if (response == null) { return null; } String responseContent = ""; if (response.body() != null) { byte[] bodyData = Util.toByteArray(response.body().asInputStream()); int length = bodyData.length; if (length > 0) { responseContent = decodeOrDefault(bodyData, UTF_8, "Binary data"); log(response, elapsedTime, responseContent); return response.toBuilder().body(bodyData).build(); } } log(response, elapsedTime, responseContent); return response; } private void log(Response response, long elapsedTime, String responseContent) { Request feignRequest = response.request(); String httpMethodName = feignRequest.httpMethod().name(); String url = feignRequest.url(); String requestBody = transferRequestBody(feignRequest); int status = response.status(); if (elapsedTime > logWarnTagThreshold * 1000) { log.info("FeignLogger 慢接口 【 TODOLIST 】 大于3秒 cost:[{}]ms, status {} \n{} {} \nrequest:{} \nresponse:{}", elapsedTime, status, httpMethodName, url, requestBody, responseContent); } else { log.info("FeignLogger cost:[{}]ms, status {} \n{} {} \nrequest:{} \nresponse:{}", elapsedTime, status, httpMethodName, url, requestBody, responseContent); } } private String transferRequestBody(Request request) { if (request.body() != null) { return request.charset() != null ? new String(request.body(), request.charset()) : ""; } return ""; } @Override protected void logRetry(String configKey, Level logLevel) { log.info("FeignLogger {} {} ---> RETRYING", logLevel.name(), configKey); } @Override protected IOException logIOException(String configKey, Level logLevel, IOException ioe, long elapsedTime) { log.info("FeignLogger {} {} cost {} {} ", logLevel.name(), configKey, elapsedTime, ioe.getMessage()); return ioe; } @Override protected void logRequest(String configKey, Level logLevel, Request request) { } }

又提升了排查问题的速度,节省了时间。

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.