线上基础问题排查常用手册

线上基础问题排查常用手册

问题分类

业务问题

性能问题


实施手段

日志排查

阿里云

参考: https://help.aliyun.com/document_detail/29060.html?spm=5176.2020520112.2.1.28bb34c0daZmJB

短语查询
	查询包含foo的词
	"foo"
使用模糊查询	
	查询包含foo前缀的词	
	foo*
使用全文查询	
	查询任何字段中包含foot的日志	
	foot
使用字段查询	
	查询message字段包含foot的日志	
	message:foot
使用数字范围查询	
	查询status范围在400(包含)到499(包含)
	(注意,数值查询,需要把字段定义成long或double类型)	
	status in [400 499] 或者 status ≥400 and status ≤499
组合查询	
	查询status范围在400(包含)到499(包含),并且message包含foot	
	status ≥400 and status ≤499 and message:foot

在这里插入图片描述

本地日志
# 本地日志可能非常大,所以正常需要根据需要来过滤数据
# 如果直接打开超大文件,可能会导致一些问题,比如: 假死
# 指定显示行数
cat test.log | tail -n 20 # 显示20行
# 查找包括Exception字符串的行
cat test.log | grep "Exception"
# 指定行数,避免过大
cat test.log | grep "Exception" | tail -n 20
# and 查找包括Exception与java:81
cat test.log | grep "Exception" | grep "java:81"
# or 查找包括Exception或RequestMappingHandlerAdapter
cat test.log | grep -E "Exception|RequestMappingHandlerAdapter"
# 统计相关
# 统计Exception数量 
cat test.log | grep "Exception" | wc -l

代码逻辑排查

本地代码
  • 单元测试
  • 请求回放
  • 断点
线上代码
# arthas 下载&安装祥见附录1
# jad 参考: https://arthas.gitee.io/jad.html
# 功能:反编译代码。 可以直观的确认当前运行版本代码
# 解决:提交了,不知道为什么没有作用?
jad com.nascent.ecrpsaas.openapi.interceptor.APIHandlerInterceptor
# 将编译代码输出
jad com.nascent.ecrpsaas.openapi.interceptor.APIHandlerInterceptor > /tmp/APIHandlerInterceptor.java

配置排查

# arthas 下载&安装祥见附录1
# 解决:配置没有生效? 现在有配置是什么样的?
静态配置类&枚举类
# arthas 下载&安装祥见附录1
# ognl 参考: https://arthas.gitee.io/ognl.html
ognl "@com.nascent.ecrpsaas.openplatform.enums.GlobalsEnums@SYSTEM_ERROR.getMsg()"
获取SpringBean对象

比如项目中,配置了一个SpringBean对象

<!-- activeMq的连接池 -->
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
    <property name="connectionFactory" ref="targetConnectionFactory"/>
    <!--连接池的最大连接数-->
    <property name="maxConnections" value="${activemq.pool.max-connections}"/>
</bean>

获取对应的pooledConnectionFactory当前配置

# 获取任何一个请求对象,因为都会存在对应的SpringContext容器
tt -n 1 -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
# 特别强调: 这里在正式环境中,添加-n来指定次数,且应该设置成1。
# 否则当你执行一个调用量不高的方法时可能你还能有足够的时间用 CTRL+C 中断 tt 命令记录的过程,但如果遇到调用量非常大的方法,瞬间就能将你的 JVM 内存撑爆。
# 通过tt的回放能力,获取容器内的Bean
# 随意请求一个地址,只需要被Spring拦截
# 如:http://localhost:9091/openApi/sentinel/flowRules

在这里插入图片描述

此时,如果使用ognl可以得到target(当前被调用对象)。因为这个对象是由SpringContext管理的,所以可以获取得容器信息。

tt -i 1003 -w 'target.getApplicationContext().getBean("pooledConnectionFactory")'
# 获取最大连接数
tt -i 1003 -w 'target.getApplicationContext().getBean("pooledConnectionFactory").maxConnections'

接口问题

响应时间
# arthas 下载&安装祥见附录1
# 解决:接口响应慢?哪个环节慢?
# trace 参考: https://arthas.gitee.io/trace.html
trace com.nascent.ecrpsaas.openapi.interceptor.APIHandlerInterceptor preHandle -n 1
# 特别强调: 这里在正式环境中,添加-n来指定次数

在这里插入图片描述

# 根据方法用时过滤
trace com.nascent.ecrpsaas.openapi.interceptor.APIHandlerInterceptor preHandle -n 1 '#cost>10'
# 该过滤是过滤整个方法的用时,而不是指过滤方法内的调用方法用时

trace 的问题在于,

  • 无法支持重载方法
  • 无法直接定位方法下的方法
入参与响应结果跟踪
# arthas 下载&安装祥见附录1
# 解决:调用参数与响应结果跟踪。
# tt 参考: https://arthas.gitee.io/tt.html
# 表达式变量祥见附录2
tt -n 1 -t com.nascent.ecrpsaas.openapi.controller.customer.CustomerController getCustomerInfo4ThirdParty
# 请求参数
tt -i <tt-index> -w 'params'
# 响应结果
tt -i <tt-index> -w 'returnObj'

JVM问题

CPU
查看CPU占用
top

在这里插入图片描述

如果CPU一直过高,并且不见回落。则需要排查进程要关线程的状态。

线程跟踪
# 查看进程内最耗费CPU的线程
top -Hp <pid>

在这里插入图片描述

如何排查对应的线程问题? 需要结合jstack

jstack
跟踪所有线程
jstack 1 | more

在这里插入图片描述

该命令可以查看出当前JVM中的线程情况。

主要关注以下三个状态:

• WAITING:进入等待状态
    • 方式:wait/join/park方法进入无限等待,通过notify/notifyAll/unpark唤醒;
• TIMED_WAITING:与WAITING类似。
	• 方式:a. 给定等待时间的wait/join/park
	• 方法;b. sleep方法;
• BLOCKED:被动进入等待状态
	• 方式:进入Synchronized块;
线程状态数量统计
jstack 1 | grep "State: WAITING" | wc -l
查看特定线程的状态信息

查看线程Id=65的线程信息

# 转义进程Id为16进制
printf '%x\n' 65 # 41
jstack 1 | grep 41

在这里插入图片描述

jstack排查死循环线程Demo
package com.nascent.test.thread;

public class DeadLockTest {
   

    private static final Object obj1 = new Object();
    private static final Object obj2 = new Object();

    public static void main(String[] args) {
   
        Thread thread = new Thread(() -> {
   
            synchronized (obj1) {
   
                try {
   
                    Thread.sleep(200);
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }
                synchronized (obj2) {
   
                    System.out.println("t1");
                }
            }
        });
        Thread thread2 = new Thread(() 
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值