是谁的请求导致我的系统一直抛异常?

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 在线上环境中,请求错综复杂,如果有某个请求出现了不符合预期的情况,我们往往会先需要确定这个请求在实际环境中是由哪个 Controller 来处理的。通常情况下,我们需要去查阅文档或是代码,这个过程往往比较繁琐,并且不一定是准确的,可能由于一些问题会导致我们的请求没有被预期的 Controller 处理。而借助微服务洞察的能力,能够快速地定位特定的请求在真实环境中是由哪个 Controller 处理的。

作者:屿山、十眠


在线上环境中,请求错综复杂,如果有某个请求出现了不符合预期的情况,我们往往会先需要确定这个请求在实际环境中是由哪个 Controller 来处理的。通常情况下,我们需要去查阅文档或是代码,这个过程往往比较繁琐,并且不一定是准确的,可能由于一些问题会导致我们的请求没有被预期的 Controller 处理。而借助微服务洞察的能力,能够快速地定位特定的请求在真实环境中是由哪个 Controller 处理的。


流程分析

本文的 demo 包含 log-demo-spring-cloud-zuul、log-demo-spring-cloud-a、log-demo-spring-cloud-b、log-demo-spring-cloud-c 四个应用,采用最简单的 Spring Cloud 标准用法依次调用,可以直接在项目上查看源码。 https://github.com/aliyun/alibabacloud-microservice-demo/tree/master/mse-simple-demo  


以 SpringCloud 为例,请求到达后会由 org.springframework.web.servlet.DispatcherServlet#doDispatch 方法处理请求的整体流程。


  protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
      ModelAndView mv = null;
      Exception dispatchException = null;
      try {
        processedRequest = checkMultipart(request);
        multipartRequestParsed = (processedRequest != request);
        // Determine handler for the current request.
        mappedHandler = getHandler(processedRequest);
        if (mappedHandler == null) {
          noHandlerFound(processedRequest, response);
          return;
        }
        // Determine handler adapter for the current request.
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        // Process last-modified header, if supported by the handler.
        ……
        // Actually invoke the handler.
        ……
      }
    }
  }


可以看到决定由哪个 handler 来处理请求的功能由 org.springframework.web.servlet.DispatcherServlet#getHandler 方法负责。该方法所返回的 org.springframework.web.servlet.HandlerExecutionChain 类的实例,就是最后实际处理该请求的 handler。也就是说我们只需要借助微服务洞察的能力观测这个方法的返回值即可。


微服务洞察


首先,简单介绍一下要使用的微服洞察能力,该能力基于规则的模型,以动态增强的方式为我们获取真实的现场信息。它的规则模型如下图所示:


1.png


Target:


  • ResourceTarget: 目标接口,支持 Web、Rpc、SQL 以及任意的自定义方法
  • WorkloadTarget: 目标实例,可以选择所有机器或指定机器 IP
  • TrafficCondition: 是否仅针对异常、慢调用、全链路灰度标签 


Action:


  • 相关上下文诊断信息的收集,参数、返回值、线程上下文、Target 对象、类加载器信息等
  • 后续链路是否日志打印
  • 流量染色、限流降级等治理动作 


在本文的场景中,我们需要将 org.springframework.web.servlet.DispatcherServlet#getHandler 设为我们的 Target,目标实例为默认的全部,不添加流量过滤条件。


2.png


随后,我们选择想要打印的内容,在这个场景中我们所需要是该方法的返回值,其他的内容可以根据需要选择。


3.png


在开启规则之后,我们可以在控制台中看到如图的调用链展示,可以看到/a 这个请求在 log-demo-spring-cloud-a 中的调用栈在基础的框架记录中新增了我们所选择的方法 org.springframework.web.servlet.DispatcherServlet#getHandler 的相关记录,从右侧的 Attributes 中的 mse.return 字段中可以看到该请求会由 java.lang.String com.alibabacloud.mse.demo.AApplication$AController.a 来处理。


4.png


辅助异常分析


线上的请求出现了异常,在定位问题的过程中,我们往往会需要知道调用的堆栈信息,进而去排查堆栈上的方法。借助微服务洞察的能力,我们也可以很方便的进行这些操作。


场景在前文的 Demo 中增加了对数据库的访问,使用了 Druid 作为连接池组件。


当发现某个 url 的请求部分报错,但我们并没有预先编写能够记录有效信息的日志,这时我们就可以通过一条规则来打印现场的堆栈信息,以获取我们需要排查的方法列表,再进一步对逐个方法进行分析。假设是/sql 的请求出现了部分报错,我们选择/sql 作为 Target,如果不知道具体的接口,也可以选择全部。


5.png


由于我们只需要分析错误的请求,所以在过滤规则条件中开启异常过滤,在打印内容中选中调用堆栈,其他的内容可以根据需要选择。


6.png


开启该规则后,可以在控制台看到堆栈信息。


7.png


at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:989)
  at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:213)
  at com.alibabacloud.mse.demo.service.DruidCon.doCommond(DruidCon.java:57)
  at com.alibabacloud.mse.demo.service.DruidService.query(DruidService.java:15)
  at com.alibabacloud.mse.demo.BApplication$AController.sql(BApplication.java:89)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)


截取其中一部分可以发现 com.alibabacloud.mse.demo.service.DruidCon.doCommond 以及 com.alibabacloud.mse.demo.service.DruidService.query 都是我们自身的业务逻辑方法,也是我们需要关注的方法,我们可以继续借助微服务洞察的能力,去获取这些方法的现场信息,比如参数、返回值、类加载器等等。


这边以获取 com.alibabacloud.mse.demo.service.DruidCon.doCommond 方法的参数信息为例。同样只需要一条规则,类似前文,将该方法设为 Target,打开异常过滤标签,在打印内容中选中请求参数,开启规则后,便可以在控制台看到该方法的参数信息。


8.png


以上只是简单的例子,但是能够由此发现,微服务洞察的能力能够让我们在 Java 方法任意点位收集信息,将排查工作变成零代码且动态的,由于不需要在测试环境中重复增加日志代码并不断重启应用,能够大大减小某些难以在测试环境中复现的问题的排查难度。


在非预期的情况下,工作在最优解


微服务洞察能力提供了 Java 方法任意点位的可观测能力,本文通过该能力演示了:观测请求的匹配、观测异常场景下请求的上下文等场景,可以帮助我们在系统出现异常时进行问题定位,除了本文的场景还有很多微服务的场景能够借助微服务洞察能力来观测,将原本复杂且交织的微服务场景清晰地展现在我们面前。微服务洞察能力我们还在持续地打磨与完善,而发现并定位问题并不是目的,对于系统稳定来说只是迈出了第一步,我们还需要进一步结合治理能力才能够真正让系统稳定运行,比如本文的场景中可以针对异常的请求进行限流,或是快速地隔离故障,或是针对不稳定的服务进行容错降级等等,从而保护我们的系统。


在真实环境中,系统的不稳定性不仅仅来自于我们自身的业务逻辑错误,还有很多可能比如突发的大流量,上下游的不稳定等等。而这些问题都可以交给 MSE,使系统在非预期的情况下仍能工作在最优解。


9.png


相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
7月前
|
安全 Java 编译器
异常的讲解
异常的讲解
52 1
|
安全
异常
异常
75 0
|
存储 监控 Java
认识异常【超详细】
认识异常【超详细】
47 0
|
Java 程序员 测试技术
C++11 异常(下)
C++11 异常(下)
63 0
|
C++ Windows
有趣的异常
有趣的异常
一日一技:不使用 try...except 掩盖一些已知异常
一日一技:不使用 try...except 掩盖一些已知异常
75 0
|
Java 索引
05-异常
异常:Java代码在运行时期发生的问题叫做异常,当发生问题时,就会创建异常对象并抛出异常信息(异常的原因及位置)
115 0
05-异常
|
Java 程序员 编译器
理解并处理异常
理解并处理异常
88 0
理解并处理异常
|
SQL Cloud Native druid
是谁的请求导致我的系统一直抛异常?
微服务引擎MSE面向业界主流开源微服务项目, 提供注册配置中心和分布式协调(原生支持Nacos/ZooKeeper/Eureka)、云原生网关(原生支持Ingress/Envoy)、微服务治理(原生支持Spring Cloud/Dubbo/Sentinel,遵循 OpenSergo 服务治理规范)能力。
是谁的请求导致我的系统一直抛异常?