记一次使用阿里arthas的一次java异常诊断

Arthas 是Alibaba开源的Java诊断工具

JSON解析异常问题

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('ä' (code 228)): was expecting comma to separate Object entries; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('ä' (code 228)): was expecting comma to separate Object entries
at [Source: (PushbackInputStream); line: 1, column: 264]

Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('ä' (code 228)): was expecting comma to separate Object entries
at [Source: (PushbackInputStream); line: 1, column: 264]

看到上面的异常信息我们已经很明确的知道了是接口调用方传入的JSON字符串有问题,从而导致后端解析JSON失败。但是,具体请求的是哪个接口异常中并未打印出来。这时候犯难了。不可能去让接口调用方一个一个的去找(没有足够的证据可能还会被diss一通)。正当一筹莫展的时候想到了之前用阿里开源的Arthas诊断线上内存泄漏问题时的经历,感觉它面对这个也应该是可以的,于是乎就有如下尝试。

  1. 因为使用的是docker 所以直接使用了如下命令进入容器:

     docker exec -it  ${containerId} /bin/bash -c "wget https://alibaba.github.io/arthas/arthas-boot.jar && java -jar arthas-boot.jar"
    

    不料官方原版tomcat镜像找不到pid

     [INFO] arthas-boot version: 3.4.4
     [INFO] Can not find java process. Try to pass <pid> in command line.
     Please select an available pid.
    

    算了,直接用外部jdk 查看容器挂载外部目录信息docker inspect --format "{{.Config.Volumes}}" ${containerId},直接把下载好的jdk解压放入其中一个目录中。下载arthas-boot.jar:

      curl -O https://alibaba.github.io/arthas/arthas-boot.jar
    

    同样放入在挂载目录下。 注意:外部的JDk bin目录下文件最好都加上可执行权限chmod -R 777 bin

     #${dir} 为外部文件挂载在容器内的目录
     docker exec -it ${containerId} /bin/bash -c "/${dir}/jdk/bin/java -jar /${dir}/arthas-boot.jar"
     #或者通过
     docker exec -it ${containerId} bash # 进入之后cd 到 ${dir}  执行命令
    
  2. 进入容器后使用 watch 命令来查看调用接口以及参数

    观察入参:

     watch org.springframework.web.servlet.DispatcherServlet doDispatch  'params[0]' -x 3 -b -n 2
     # 通过查看 HttpServletRequest 里面的请求,来得到信息
     #java 8 直接获取到POST body 里面的参数
     watch org.springframework.web.servlet.DispatcherServlet doDispatch  'params[0].getReader().lines().collect(@java.util.stream.Collectors@joining(@java.lang.System@lineSeparator()))' -x 3 -b -n 2
     ## 注意流在这里被读取之后,后面的方法就没法处理了
    
  3. 如上大概就可以知道调用方入参的原始数据了,根据原始数据就可以去说理了!!但是,以上只能用于 应急测试环境,如果线上环境还得重新考虑。

结束、也未结束

这只是一个开始,方法还得完善。

上一篇:K8S+Docker理论与实践深度集成,搞懂这些直接来阿里入职


下一篇:是谁在调用我?使用 arthas+jprofiler 做复杂链路分析