Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >干货|如何快速问题出在哪了?

干货|如何快速问题出在哪了?

作者头像
烟雨平生
发布于 2023-03-07 02:52:04
发布于 2023-03-07 02:52:04
27700
代码可运行
举报
文章被收录于专栏:数字化之路数字化之路
运行总次数:0
代码可运行

先从一个具体的问题说起。

背景

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

每次解决问题后,最好能复盘一下,总结下排查思路。

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

出现的问题

一个导出excel的功能,接入已有的下载中心模块。执行导出,全部失败了。

在日志平台中搜到的日志不全,没有找到导致异常的原因。

处理过程

涉及到的数据流:

导出功能涉及到的数据流

step1:分析日志

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

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

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

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

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

现在日志不全,且下载中心是初次接入,一下子想不到问题出在哪里

traceId丢失的原因: 请求“数据服务”的动作是由MQ的消费者发起的,这种场景,uat环境中的应用日志中的traceId为空 uat:User Acceptance Test,测试环境 想了解什么是traceId?见文章末尾

目前很可能“下载中心服务”出问题了。

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

搜不到日志有两种原因:

1、日志平台 有问题

2、搜索的关键词不合适

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

就目前的情况看,很难区分是日志平台出问题了,还是搜索的关键词不对。

毕竟是uat环境,有问题也不会花力气去处理。

step2: 阻塞了,陷入困境

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

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

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

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

有同学会问:为什么不在本地调一下? 因为uat环境和本地用的同一个MQ。 本地发的消息很可能让uat上的消费者消费了。 就是拼人品了,也蛮花时间的。

攻克问题的二波攻势

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

日志平台的数据流如下所求:

日志平台的数据流

排查的顺序:

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

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

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

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

有日志

日志是有的。

step2: 这个看不了。找有权限的同学查看了下,没有!!!约定好的目录下没有日志文件

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

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

如果知道是因为日志平台的问题,其它还有其它办法来锁定:

譬如可以查看是不是整个应用都没有日志

思考:

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

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

如何避免呢?

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

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

原因

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

小结

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

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

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

额外的收获

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

show the code:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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) {
    }
}

排查问题的速度又要提升了,开心。

补充:

什么是traceId:

traceId,可以唯一标记一次请求,可以根据traceId查看完整的调用链。

当用户的请求进入系统后,链接跟踪组件会在请求进入系统时生成一个全局唯一的标识,这个标识就是traceId。traceId会随着每一层的远程调用,不断往后传递,这样的话通过traceId就可以把一次用户请求在系统中调用的路径串联起来。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 的数字化之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
spring cloud feign log 实践
这篇文章,我们主要介绍一下spring cloud feign log的相关知识点~ 我们以具体项目中的实例来做以下说明:
xdd
2022/07/12
5450
spring cloud feign log 实践
Spring Cloud-Feign设计原理
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://louluan.blog.csdn.net/article/details/82821294
亦山
2019/05/25
2.7K0
Feign整合Ribbon和Hystrix源码解析
在上篇文章Feign自动装配中,我们提到了Feign的自动装配的原理,以及Feign整合Ribbon和Hystrix的核心在类FeignClientFactoryBean中,那么本篇文章就来揭开这个类的神秘面纱
Java学习录
2019/11/12
1K0
【一起学源码-微服务】Feign 源码三:Feign结合Ribbon实现负载均衡的原理分析
上一讲我们已经知道了Feign的工作原理其实是在项目启动的时候,通过JDK动态代理为每个FeignClinent生成一个动态代理。
一枝花算不算浪漫
2020/01/13
8560
【一起学源码-微服务】Feign 源码三:Feign结合Ribbon实现负载均衡的原理分析
【SpringCloud原理】OpenFeign原来是这么基于Ribbon来实现负载均衡的
大家好,前面我已经剖析了OpenFeign的动态代理生成原理和Ribbon的运行原理,这篇文章来继续剖析SpringCloud组件原理,来看一看OpenFeign是如何基于Ribbon来实现负载均衡的,两组件是如何协同工作的。
三友的java日记
2022/07/27
9590
【SpringCloud原理】OpenFeign原来是这么基于Ribbon来实现负载均衡的
[享学Feign] 四、原生Feign的核心API详解(二):Contract、SynchronousMethodHandler...
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
3.9K0
[享学Feign] 四、原生Feign的核心API详解(二):Contract、SynchronousMethodHandler...
spring cloud feign调用原理_vip解析的原理
Feign 是⼀个 HTTP 请求的轻量级客户端框架。通过 接口 + 注解的方式发起 HTTP 请求调用,面向接口编程,而不是像 Java 中通过封装 HTTP 请求报文的方式直接调用。服务消费方拿到服务提供方的接⼝,然后像调⽤本地接⼝⽅法⼀样去调⽤,实际发出的是远程的请求。让我们更加便捷和优雅的去调⽤基于 HTTP 的 API,被⼴泛应⽤在 Spring Cloud 的解决⽅案中。
全栈程序员站长
2022/11/10
5K0
spring cloud feign调用原理_vip解析的原理
Feign使用分析
在实现的效果上来说Feign = RestTemplate+Ribbon+Hystrix
zhaozhen
2021/08/06
5420
Feign其实也不是很难
Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求。Spring Cloud引入 Feign并且集成了Ribbon实现客户端负载均衡调用。
用户3467126
2021/08/05
5870
Spring Cloud openFeign学习【3.0.2版本】
内容分为openFeign大致的使用和源码的个人解读,里面参考了不少其他优秀博客作者的内容,很多地方基本算是拾人牙慧了,不过还是顺着源码读了一遍加深理解。
阿东
2021/08/16
1.7K0
Spring Cloud openFeign学习【3.0.2版本】
Spring Cloud Feign - 内部实现细节
Feign用于服务间调用,它的内部实现是一个包含Ribbon(负载均衡)的JDK-HttpURLConnection(Http)调用。虽然调用形式是类似于PRC,但是实际调用是Http,这也是为什么Feign被称为伪RPC调用的原因。 内部调用过程如下:
夹胡碰
2021/03/15
7070
一文看懂Openfeign服务调用原理
OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。
叔牙
2021/12/20
3.2K0
一文看懂Openfeign服务调用原理
再谈openfeign,聊聊它的源代码
1.下面的2个配置对单个接口超时并没有起作用,作为eureka客户端使用时,起作用的其实是默认超时时间,作为普通http客户端时,起作用的其实也是默认超时时间。
jinjunzhu
2020/11/19
7300
再谈openfeign,聊聊它的源代码
OpenFeign源码解读
前言: 参考学习链接: 1.https://www.bilibili.com/video/BV11D4y1C73V/?spm_id_from=333.1007.top_right_bar_window
小爽只会CRUD
2023/05/09
9820
OpenFeign源码解读
网关修改响应码,拯救业务不规范设计
可能是因为在项目开始前,并没有制定标准的规范,而且开发人员对Http基本知识了解。服务端无论有没有出现异常,又或者是权限不足,一律将Http的响应码设置为200,导致无法正常使用OpenFeign以及无法适配第三方应用(依赖Http响应码)。
阿珍
2024/08/27
1640
网关修改响应码,拯救业务不规范设计
网关修改响应码,拯救业务不规范设计
可能是因为在项目开始前,并没有制定标准的规范,而且开发人员对Http基本知识了解。服务端无论有没有出现异常,又或者是权限不足,一律将Http的响应码设置为200,导致无法正常使用OpenFeign以及无法适配第三方应用(依赖Http响应码)。
xcye
2024/07/20
2940
网关修改响应码,拯救业务不规范设计
面试系列之-Spring Cloud Feign
根据传入的Bean对象和注解信息,从中提取出相应的值,来构造Http Request 对象;
用户4283147
2023/11/20
3600
面试系列之-Spring Cloud Feign
聊聊feign的Retryer
feign-core-10.2.3-sources.jar!/feign/Retryer.java
code4it
2019/07/17
1.1K0
聊聊feign的Retryer
[享学Feign] 十一、Feign通过feign-slf4j模块整合logback记录日志
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
5.1K0
[享学Feign] 十一、Feign通过feign-slf4j模块整合logback记录日志
Java Web中日志跟踪的简单实现
在编码过程中,常常需要写打印日志语句,我们期望的是同一个业务的日志都在一块,在出问题的时候好根据日志来排查问题。而现实是在应用运行中,日志的输出常常来自不同线程,甚至是在不同微服务中,各种日志记录往往彼此穿插,很难串起来。所以往往在日志中手动增加一些关键字,来对接口的调用链路来进行跟踪。但这种手动增加关键字或唯一标识的做法在微服务场景下,很难在上下游应用的开发人员的编码风格形成统一的规范,并且手动编写也很难称得上优雅。
GreatSQL社区
2023/02/23
5080
相关推荐
spring cloud feign log 实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验