标签 Debug 下的文章 - 第 5 页 - 酷游博客
首页
关于
友链
Search
1
阿里的简历多久可以投递一次?次数多了有没有影响?可以同时进行吗?
45 阅读
2
Java中泛型的理解
40 阅读
3
Java 14 发布了,再也不怕 NullPointerException 了!
38 阅读
4
Java中的可变参数
37 阅读
5
该如何创建字符串,使用" "还是构造函数?
29 阅读
技术
登录
/
注册
找到
22
篇与
Debug
相关的结果
- 第 5 页
2025-01-22
阿里开源那个牛哄哄问题排查工具竟然不会用?最佳实践来了!
作者:汪吉 入门步骤 安装 https://arthas.gitee.io/install-detail.html 上述命令会下载启动脚本文件 as.sh 到当前目录,执行方式: curl -L https://alibaba.github.io/arthas/install.sh | sh as.sh 启动 : curl -sk https://arthas.gitee.io/arthas-boot.jar -o ~/.arthas-boot.jar && echo "alias as.sh='java -jar ~/.arthas-boot.jar --repo-mirror aliyun --use-http'" >> ~/.bashrc && source ~/.bashrc 在线教程体验 https://alibaba.github.io/arthas/arthas-tutorials?language=cn 当然也可以自己本地体验一下~自己通过下载一个 arthas-idea-plugin的体验demo 直接本地上手 https://github.com/WangJi92/arthas-plugin-demo 全局命令说明: -x 是展示结果属性遍历深度,默认为 1 -n 是执行的次数 ,q 退出 -c classloader 的hash值 退出 q ,关闭 stop 了解最常用的trace、watch的功能 watch和trace 是arthas 诊断中对于开发人员解决线上的问题最常用的功能! trace 基本示例: trace com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger -n 5 '1==1' https://arthas.gitee.io/trace.html 性能优化~ 调用的这个方法,走的具体流程是咋样的!可以通过调用链看出来。 有异常了可以查看异常的堆栈 高级的功能: trace命令只会trace匹配到的函数里的子调用,并不会向下trace多层。因为trace是代价比较贵的,多层trace可能会导致最终要trace的类和函数非常多。 示例: trace -E xxxClassA|xxxClassB method1 | method2 如: trace -E com.wangji92.arthas.plugin.demo.controller.CommonController|com.wangji92.arthas.plugin.demo.service.ArthasTestService traceE|doTraceE -n 5 '1==1' watch https://arthas.gitee.io/watch.html wathc 从字面上理解就是观察值的信息,可以查看入参、返回值、异常、可以执行表达式获取静态变量、target.xxx调用目标实施的字段、方法等等都行~只要你想得到没有做不到的~ 基本示例: watch com.wangji92.arthas.plugin.demo.controller.CommonController traceE '{params,returnObj,throwExp}' -n 5 -x 3 '1==1' arthas 表达式核心变量 public class Advice { private final ClassLoader loader; private final Class clazz; private final ArthasMethod method; private final Object target; private final Object[] params; private final Object returnObj; private final Throwable throwExp; private final boolean isBefore; private final boolean isThrow; private final boolean isReturn; // getter/setter } 从watch 和 trace 中看到 后面的 ‘1==1’ 执行的是一个条件表达式 当值为true 的时候通过执行了一个ognl 表达式 ,watch 观察 params,returnObj,throwExp 入参、返回值、是否异常 这个也是一个表达式,那么这个到底是咋回事? spring el 表达式 没有学习过ognl 使用多年的spring 一定知道他的el 表达式,el 表达式中也有一种概念叫做【Context 上下文,和表达式】 如下所示,因为有了simple这个上下文 才能解析 “booleanList[0]” 这个脚本的含义~ 这个很熟悉,很好理解,那么ognl 表达式一样不难了。 class Simple { public List booleanList = new ArrayList(); } Simple simple = new Simple(); simple.booleanList.add(true); StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple); // false is passed in here as a string. SpEL and the conversion service will // correctly recognize that it needs to be a Boolean and convert it parser.parseExpression("booleanList[0]").setValue(simpleContext, "false"); // b will be false Boolean b = simple.booleanList.get(0); ognl 表达式 arthas 也是一样的,只是使用了一个叫做ognl的脚本,核心变量就是他的上下文,可以直接获取到这些字段。watch 观察的这几个字段 params,returnObj,throwExp 也就是我们所谓的上下文的概念,观察参数、返回值、和异常的信息。 如下是arthas 源码中 表达式评估和watch 观察值执行的代码!Advice 就是一个上下文,这里还增加了一个变量 const。知道了这些那不是很简单?? com.taobao.arthas.core.advisor.ReflectAdviceListenerAdapter#isConditionMet /** * 判断条件是否满足,满足的情况下需要输出结果 * @param conditionExpress 条件表达式 * @param advice 当前的advice对象 * @param cost 本次执行的耗时 * @return true 如果条件表达式满足 */ protected boolean isConditionMet(String conditionExpress, Advice advice, double cost) throws ExpressException { return StringUtils.isEmpty(conditionExpress) || ExpressFactory.threadLocalExpress(advice).bind(Constants.COST_VARIABLE, cost).is(conditionExpress); } protected Object getExpressionResult(String express, Advice advice, double cost) throws ExpressException { return ExpressFactory.threadLocalExpress(advice) .bind(Constants.COST_VARIABLE, cost).get(express); } 表达式实践 arthas 群经常有人问重载方法如何判断,无非就是评估条件? 参数的个数、第一个参数是什么?返回值的类型等等都可以作为你评估的条件。如下的watch 前面的一段是观察的值、后面这一段是表达式评估 ,满足了条件才执行。 入参长度大于0: watch com.wangji92.arthas.plugin.demo.controller.CommonController traceE '{params,returnObj,throwExp}' -n 5 -x 3 'params.length >0' 返回值为String 且长度大于5: watch com.wangji92.arthas.plugin.demo.controller.CommonController traceE '{params,returnObj,throwExp}' -n 5 -x 3 'returnObj instanceof java.lang.String && returnObj.length>5' 条件表达式+异步任务 只有特定的场景才会有bug ,如何排查bug? 一天只出现一两次如何解决? 条件表达式主要是用来过滤使用,比如某些场景只是在特定的参数才会出现,肯能会花费很多的时间去等待,这个时候可以使用条件表达式过滤 +异步任务 ognl 表达式 https://arthas.gitee.io/ognl.html 从上面看,ognl 在watch、trace上面无所不能啊,其实还有tt 也是 使用ognl 表达式执行逻辑的. @xxxClas@xxxStaticField 是静态变量的语法糖 ognl的,好好看一下官方的文档。 OGNL特殊用法请参考:https://github.com/alibaba/arthas/issues/71 获取静态变量 静态变量由于 一个jvm 中可能被多个classloader加载,jvm 认定为一个实例是一个classloader加载哦,所以需要知道当前静态类的hash 值(sc -d com.wangji92.arthas.plugin.demo.controller.StaticTest)可以通过这个命令获取。 ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_DOUBLE' -c e374b99 调用spring 方法? watch 执行ognl 语法中获取spring context 然后进行调用bean的方法 watch -x 3 -n 1 org.springframework.web.servlet.DispatcherServlet doDispatch '@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()).getBean("commonController").getRandomInteger()' ognl 执行静态的一个spring context 然后调用bean 的方法 ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").getRandomInteger()' -c e374b99 有没有起飞的感觉,无所不能!前提是你要掌握一些ognl的一些简单的语法! 完毕 对于线上排查问题,我感觉这几个命令够你用了,还有一些其他的反编译、火焰图、.. 时间隧道、logger 等级修改,jvm环境信息等等感觉是有频率都没有上面的高,毕竟jvm信息有专门的监控~即使没有arthas 你也可以找到更好的工具去分析堆栈,jvm故障。 一些特殊的用户案列值得学习思考: https://github.com/alibaba/arthas/issues?q=label%3Auser-case 完了? 啊?这么多命令 记不住啊 还有一些高级的ognl的语法凉了… 让你获取一下所有的spring的环境变量咋办?trace、watch 这两个命令我还没有体验够呢?更加高级的让我如何是好啊!好了,请看下文。 进阶 前提 前提是你对于arthas 有了大概的理解,基本上的命令都有点概念了,ognl 简单的语法能够看懂了.. 简单的条件表达式会用了。 之前我们所过arthas的命令这么多 要记住小本本少不了啊!难受想哭~ 不要急,汪小哥来给你解决问题。 目前Arthas 官方的工具还不够足够的简单,需要记住一些命令,特别是一些扩展性特别强的高级语法,比如ognl获取spring context 为所欲为,watch、trace 不够简单,需要构造一些命令工具的信息,因此只需要一个能够简单处理字符串信息的插件即可使用。当在处理线上问题的时候需要最快速、最便捷的命令,因此arthas idea 插件还是有存在的意义和价值的。 arthas idea plugin 这个插件的意义不是处理协议层面的问题,主要解决命令生成的问题,由于工程在idea 里面管理,你想想你要watch 哪个类,这个插件是知道的,帮助你更方便、更加快捷的构建命令。使用arthas idea 插件 这一点一定要理解哦!主要解决你如何构造命令的问题  解决的问题 spring 环境变量优先级问题 获取静态变量 火焰图集成 logger 命令集成 反编译集成 trace -E 集成 tt 集成 ……. 基本上你能够在arths 上面看到的功能都集成到了这个上面!直接在idea 里面搜索arths idea 即可安装。 常用特殊用法问题 静态变量 可以直接获取 ognl 获取 ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_DOUBLE' -c e374b99 可以通过watch 获取 (光标放置在字段上) watch com.wangji92.arthas.plugin.demo.controller.StaticTest * '{params,returnObj,throwExp,@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_DOUBLE}' -n 5 -x 3 '1==1' 一般的变量 可以通过spring context.getBean().field 获取(这个是要配置一个静态的spring context 看使用文档) tt 、watch 也是可以的哦~ 一样的原理 ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("staticTest").filedValue' -c e374b99 watch 获取 放置在字段上即可 watch com.wangji92.arthas.plugin.demo.controller.StaticTest * '{params,returnObj,throwExp,target.filedValue}' -n 5 -x 3 'method.initMethod(),method.constructor!=null || !@java.lang.reflect.Modifier@isStatic(method.method.getModifiers())' 选择的配置项的值 springContext.getEnvironment() (这个是要配置一个静态的spring context 看使用文档) ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getEnvironment().getProperty("custom.name")' -c e374b99 获取所有的配置项的值 watch 获取spring context tt 、static 也是可以的哦~ 一样的原理 watch -x 3 -n 1 org.springframework.web.servlet.DispatcherServlet doDispatch '#springContext=@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()),#allProperties={},#standardServletEnvironment=#propertySourceIterator=#springContext.getEnvironment(),#propertySourceIterator=#standardServletEnvironment.getPropertySources().iterator(),#propertySourceIterator.{#key=#this.getName(),#allProperties.add(" "),#allProperties.add("------------------------- name:"+#key),#this.getSource() instanceof java.util.Map ?#this.getSource().entrySet().iterator.{#key=#this.key,#allProperties.add(#key+"="+#standardServletEnvironment.getProperty(#key))}:#{}},#allProperties' 插件地址: https://plugins.jetbrains.com/plugin/13581-arthas-idea Arthas征文地址:https://open.atatech.org/articles/175082
技术
# Debug
酷游
1月22日
0
7
0
2025-01-22
面试官:线上服务器CPU占用率高如何排查定位问题?
国外开发者平台 HankerRank 发布的 2018 年开发者技能调查报告中有一项关于”雇主最看重哪些核心能力”的调查,结果显示如下:  排名前几的比较受重视的能力分别为:解决问题、编程语言熟练程度、Debug、系统设计和性能优化。 解决问题的能力以超高比例排名第一,这也是为什么很多面试过程中,面试官都喜欢问如下问题: 1、你这个项目遇到的最大挑战是什么?如何解决的? 2、如果线上发生了报警你回如何排查呢? 3、你有解决过什么线上问题吗? 4、能列举几个你知道的排查Linux服务器线上问题的命令吗? 这些,都是比较常见的问题,还有一些比较具体的问题也是建议很多开发者都需要掌握的,如: 1、线上服务器Load飙高如何排查? 2、线上服务器CPU占用率高如何排查? 3、线上服务器频繁发生Full GC如何排查? 4、线上服务器发生死锁如何排查? 这些问题的回答,一方面考察了面试者是否具有很强的实战经验,另外一方面也能体现出其解决问题的能力。 毋庸置疑,作为开发人员来说,定位并解决问题的能力是至关重要的。因为一旦线上发生了问题,如CPU占用率高,如果不及时结局,很容易导致网站响应慢、服务器宕机等问题。 那么,书归正传,本文我们就来简单介绍一下,如果线上服务器发生CPU占用率过高的问题时,应该如何排查并定位问题。 问题发现 本文整理自一个真实的案例,是楼主负责的业务,在一次大促之前的压测时发现了这个问题。 在每次大促之前,我们的测试人员都会对网站进行压力测试,这个时候会查看服务的cpu、内存、load、rt、qps等指标。 在一次压测过程中,测试人员发现我们的某一个接口,在qps上升到500以后,CPU使用率急剧升高。 CPU利用率,又称CPU使用率。顾名思义,CPU利用率是来描述CPU的使用情况的,表明了一段时间内CPU被占用的情况。使用率越高,说明你的机器在这个时间上运行了很多程序,反之较少。 问题定位 遇到这种问题,首先是登录到服务器,看一下具体情况。 定位进程 登录服务器,执行top命令,查看CPU占用情况: $top PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1893 admin 20 0 7127m 2.6g 38m S 181.7 32.6 10:20.26 java top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。 通过以上命令,我们可以看到,进程ID为1893的Java进程的CPU占用率达到了181%,基本可以定位到是我们的Java应用导致整个服务器的CPU占用率飙升。 定位线程 我们知道,Java是单进程多线程的,那么,我们接下来看看PID=1893的这个Java进程中的各个线程的CPU使用情况,同样是用top命令: $top -Hp 1893 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4519 admin 20 0 7127m 2.6g 38m R 18.6 32.6 0:40.11 java 通过top -Hp 1893命令,我们可以发现,当前1893这个进程中,ID为4519的线程占用CPU最高。 定位代码 通过top命令,我们目前已经定位到导致CPU使用率较高的具体线程, 那么我么接下来就定位下到底是哪一行代码存在问题。 首先,我们需要把4519这个线程转成16进制: $printf %x 4519 11a7 接下来,通过jstack命令,查看栈信息: $sudo -u admin jstack 1893 |grep -A 200 11a7 "HSFBizProcessor-DEFAULT-8-thread-5" #500 daemon prio=10 os_prio=0 tid=0x00007f632314a800 nid=0x11a2 runnable [0x000000005442a000] java.lang.Thread.State: RUNNABLE at sun.misc.URLClassPath$Loader.findResource(URLClassPath.java:684) at sun.misc.URLClassPath.findResource(URLClassPath.java:188) at java.net.URLClassLoader$2.run(URLClassLoader.java:569) at java.net.URLClassLoader$2.run(URLClassLoader.java:567) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findResource(URLClassLoader.java:566) at java.lang.ClassLoader.getResource(ClassLoader.java:1093) at java.net.URLClassLoader.getResourceAsStream(URLClassLoader.java:232) at org.hibernate.validator.internal.xml.ValidationXmlParser.getInputStreamForPath(ValidationXmlParser.java:248) at org.hibernate.validator.internal.xml.ValidationXmlParser.getValidationConfig(ValidationXmlParser.java:191) at org.hibernate.validator.internal.xml.ValidationXmlParser.parseValidationXml(ValidationXmlParser.java:65) at org.hibernate.validator.internal.engine.ConfigurationImpl.parseValidationXml(ConfigurationImpl.java:287) at org.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:174) at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:111) at com.test.common.util.BeanValidator.validate(BeanValidator.java:30) 通过以上代码,我们可以清楚的看到,BeanValidator.java的第30行是有可能存在问题的。 问题解决 接下来就是通过查看代码来解决问题了,我们发现,我们自定义了一个BeanValidator,封装了Hibernate的Validator,然后在validate方法中,通过Validation.buildDefaultValidatorFactory().getValidator()初始化一个Validator实例,通过分析发现这个实例化的过程比较耗时。 我们重构了一下代码,把Validator实例的初始化提到方法外,在类初始化的时候创建一次就解决了问题。 总结 以上,展示了一次比较完成的线上问题定位过程。主要用到的命令有:top 、printf 和 jstack 另外,线上问题排查还可以使用Alibaba开源的工具Arthas进行排查,以上问题,可以使用一下命令定位: thread -n 3 //查看cpu占比前三的线程 以上,本文介绍了如何排查线上服务器CPU使用率过高的问题,如果大家感兴趣,后面可以再介绍一些关于LOAD飙高、频繁GC等问题的排查手段。 关于本次问题排查,你有什么想说的呢?欢迎交流。
技术
# Debug
酷游
1月22日
0
19
0
上一页
1
...
4
5
易航博客