关于java:Java不停机监控热操作

148次阅读

共计 2851 个字符,预计需要花费 8 分钟才能阅读完成。

引言

在应用 Arthas 的过程中, 感觉有些性能很好用,然而命令行的用起来会比拟麻烦,, 本着学习的态度, 本人设计了一套 无需停机, 埋点,热修复,监控等性能 的利用,并提供了 WEB 页面进行操作, 并且会一直集成一些罕用的性能 .

1. 曾经反对的操作

  • 监控 JVM、GC、启动参数、线程、零碎参数等大盘信息
  • 对于正在运行中的程序, 动静给某个办法织入代码, 获取某个函数的执行工夫
  • 对于正在运行中的程序, 动静给某个办法织入代码, 获取某个 controller 办法申请参数和返回值
  • 对于正在运行中的程序, 获取全副线程占有 CPU 工夫百分比,并反对查看指定线程运行的堆栈信息
  • 热修复, 通过反编译导出 java 文件, 批改后再导入通过 classload 重载入实现热编译(实用于空指针等 bug,大量批改代码就可解决问题时应用
  • 因为应用 web 页面操作,ip 须要改为指标过程机器 ip(默认是 localhost 如果是本地运行无需批改

关键技术

技术名称 作用
Javaagent 在运行前加载,或在运行中对字节码进行操作
VirtualMachine 在运行中附着到指标过程上, 并调用 agent

架构局部

工程 技术
web Vue + Ant design
server Springboot+Websocket(当前可能弃用 Springboot 改为 NettyServer)
agent netty + Javassist + cfr + JavaCompiler

2. 如何装置应用?

  1. 去阿里云 Maven 仓库下载 Jar 包即可

(maven 默认国外仓库)

(阿里云 Maven 仓库) 举荐应用!

Github 源码

搜寻 nobugboy 或 ETrace 即可

获取到下载地址,他这个链接会动静刷新,所以须要本人去搜寻下再下载。

  1. 获取到连贯后
1\. win 间接点击连贯下载,mac/linux wget 连贯
2\. 将文件改名为 ETrace-1.2.4.jar (点连贯下载不必改)
  1. 运行
linux/macos 具体由你配置的环境变量名称作为值,个别为 $JAVA_HOME
windows $JAVA_HOME 间接替换为 javahome 的相对目录即可
java -jar -Xbootclasspath/a:$JAVA_HOME/lib/tools.jar ETrace-1.2.4.jar

3. gif 演示操作

  1. 演示大盘和线程追踪,点击线程间接能够获取以后堆栈信息(定位高 CPU 起因)

  1. 演示织入打印执行工夫(为了难看我睡眠了 1s)

  1. 演示织入打印参数返回值

4. 热修复, 这个性能录制太繁琐, 间接图文吧

场景:一个同学提交了空指针异样的代码到了生产环境,测试没有笼罩到。

 @GetMapping(value = "/get/{id}",name = "依据 id 获取用户")
    public User test(@PathVariable(value = "id",name = "id") String id){
        User user = null;
        user.setName("测试");
        return user;
    }

 #调用一下试试

 curl localhost:8080/get/1

 出错了!exception is java.lang.NullPointerException
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-5.3.6.jar:5.3.6]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.6.jar:5.3.6]

此时服务曾经在运行状态,在不能重启服务的状况下咱们来修复, 先将须要批改的类门路找到,输入到桌面(输入门路肯定要在最初加 /

批改空指针问题,编辑导出的文件


/*
 * Decompiled with CFR.
 * 
 * Could not load the following classes:
 *  com.example.springboottestdemo.controller.User
 */
package com.example.springboottestdemo.controller;

import com.example.springboottestdemo.controller.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController(value="\u7528\u6237\u76f8\u5173\u63a5\u53e3")
public class TestController {@GetMapping(value={"/last"}, name="get\u8bf7\u6c42\u6d4b\u8bd5\u53c2\u6570\u63cf\u8ff0")
    public User test2(User user) {return user;}

    @PostMapping(value={"/post"}, name="post\u8bf7\u6c42\u6d4b\u8bd5\u53c2\u6570\u63cf\u8ff0")
    public User test1(@RequestBody User user) {System.out.println((Object)user);
        return user;
    }

    @GetMapping(value={"/get/{id}"}, name="\u6839\u636eid\u83b7\u53d6\u7528\u6237")
    public User test(@PathVariable(value="id", name="id") String id) {
        // 将此处修复
        User user = new User();
        user.setName("\u6d4b\u8bd5");
        return user;
    }
}

看到控制台 “compiler ok” 字样代表编译实现,接下来从新 load 进去

看到控制台 “redefine successful !” 字样代表 load 胜利,此时咱们再次申请方才报错的接口,谬误隐没代表胜利修复。

curl localhost:8080/get/1
{"id":null,"name":"测试","us":null,"type":null}%

正文完
 0