整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

一个轻量的企业级Web的控制终端程序

个轻量的企业级Web的控制终端程序,汇集了大多数同类产品优点于一身,支持SSH2/lrzsz、(RDP/RFB/Telnet)、审计和录屏等

快速开始

1. 安装

git clone https://github.com/wl4g/xcloud-webconsole.git # 上游,最新
# git clone https://gitee.com/wl4g/xcloud-webconsole.git
cd xcloud-webconsole/scripts
./build.sh  # 交叉编译为Windows程序
# build.bat # 交叉编译为Linux程序

2. 部署到nginx支持https. (可选)

因为webconsole是基于HTML的,浏览器的复制和粘贴功能受到安全机制的限制,只能在HTTPS下使用,当然若不想麻烦,也可忽略此步骤,直接使用HTTP本地测试,只是不能使用浏览器的复制和粘贴功能。

2.1 添加hosts

127.0.0.1   webconsole.wl4g.debug
sudo mkdir -p /etc/nginx/conf.d && \
cat > /etc/nginx/conf.d/webconsole.conf <<EOF
# Generated by WebConsole docs sample.

# WebConsole Webapps pages.
server {
    listen 443;
    server_name webconsole.sunwuu.fat;
    ssl on;
    ssl_certificate   certs/_wildcard.wl4g.debug.pem;
    ssl_certificate_key  certs/_wildcard.wl4g.debug-key.pem;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    location / {
       root /usr/share/nginx/html/webconsole;
       index index.html;
    }
}

# WebConsole APIs.
server {
    listen 26088 ssl;
    server_name  webconsole.sunwuu.fat;
    ssl_certificate   certs/_wildcard.wl4g.debug.pem;
    ssl_certificate_key  certs/_wildcard.wl4g.debug-key.pem;
    ssl_session_timeout  5m;
    ssl_prefer_server_ciphers    on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;         
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    location / {
        proxy_http_version 1.1;    
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";     
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_pass http://127.0.0.1:16088;
    }
}
EOF

sudo chmod 755 /etc/nginx/conf.d/webconsole.conf
sudo systemctl restart nginx

2.2. 安装测试CA跟证书 (可选, 跟随步骤2)

  • 将CA跟证书安装到系统及chrome,使其受信任. 例如在Chrome84.x中:
chrome://settings/security

管理证书 -> 受信任的根证书颁发机构 -> 导入 然后重启chrome浏览器尝试访问: https://webconsole.wl4g.debug

特性

  • 它被设计成一个原生JavaScript类库,可以很容易地与React/Vue/AngularJS和其他框架集成
  • 它可以运行在 Android iOS 和任何其他可以呈现HTML的终端上。它几乎可以完全取代基于安装程序的shell客户端
  • 完全支持 lrzsz 命令集(基于zmodem实现)
  • 增强了对移动终端的复制、粘贴、快进、后退等按键组合命令的支持,用户友好的操作习惯
  • 无缝对接 prometheus 度量采集

度量及指标

curl http://localhost:16089/metrics

# HELP goroutines_num Number of goroutines
# TYPE goroutines_num gauge
goroutines_num 16
# HELP mysql_active_conn Current active connections of MySQL
# TYPE mysql_active_conn gauge
mysql_active_conn{dbconnectstr="gzsm:******@tcp(10.0.0.160:3306)/devops_dev?charset=utf8",host="10.0.0.172"} 1
# HELP ssh2_active_dispatch_channels Current active channels of SSH2 dispatcher
# TYPE ssh2_active_dispatch_channels gauge
ssh2_active_dispatch_channels{host="10.0.0.172",user="admin"} 0
# HELP threads_num Number of threads
# TYPE threads_num gauge
threads_num 8
# HELP virtual_free_memory Size of virtual free memory
# TYPE virtual_free_memory gauge
virtual_free_memory 1.731424256
# HELP virtual_total_memory Size of virtual total memory
# TYPE virtual_total_memory gauge
virtual_total_memory 8.50089984

运行环境

  • 客户端建议使用 Chrome 40+、Firefox 38+、Safari 9+
  • 二次开发建议基于 Golang 1.13+ 构建
  • 本程序只能对 Unix/Linux 类的操作系统的 SSH 协议的 OS 远程操作(Windows RDP支持需参考具体发行版是否有RDP实现)

运行截图

说明:界面未设置css样式的最精简测试页面

主要依赖项目

  • 日志框架 go.uber.org/zap
  • 通用web框架 github.com/gin-gonic/gin
  • 普罗米修斯 github.com/prometheus
  • 主机指标采集 github.com/shirou/gopsutil
  • JSON序列化 github.com/json-iterator/go
  • Websocket处理 github.com/gorilla/websocket

其他说明(如果需要)

  • 生成临时调试https SSL证书

待办清单

  • [√] 完全统一每个组件的日常输出,如“gin”框架。
  • [√] 增强webconsole服务的管理员功能,例如自身的health/metrics/indicator(CPU/Mem/Network/Connections…)和更详细的指示器
  • Canvas + Object Storage 审计录屏功能
  • 为了实现与windows RDP(远程桌面协议)兼容的基于Web的远程图像UI控制协议, 以及RFB/Telnet等

自定义开发指南

  • 推荐IDE使用 VSCode 进行二次开发,因为项目根目录已包含 .vscode 编辑器配置文件
  • 修改数据库配置: resources/webconsole.yml#datasource.mysql.dbconnectstr,也可以使用环境变量:.vscode/launch.json => WEBCONSOLE_DATASOURCE_MYSQL_DBCONNECTSTR
  • 配置文件说明:本项目使用viper配置框架,加载优先级依次为:Set()/Flags/Env/Config/Default
  • 如果需要添加新的配置项,则必须使用config_generator.go 生成和xxx-config.go 对应的默认配置项webconsole.default.yml.go,参考命令:

背景

是不是在实际开发工作当中经常碰到自己写的代码在开发、测试环境行云流水稳得一笔,可一到线上就经常不是缺这个就是少那个反正就是一顿报错抽风似的,线上调试代码又很麻烦,让人头疼得抓狂;而且debug不一定是最高效的方法,遇到线上问题不能debug了怎么办。原先我们Java中我们常用分析问题一般是使用JDK自带或第三方的分析工具如jstat、jmap、jstack、 jconsole、visualvm、Java Mission Control、MAT等。但此刻的你没有看错,还有一款神器Arthas工具着实让人吃惊,可帮助程序员解决很多繁琐的问题,使得加班解决线上问题成为过去的可能性大大提高。

定义

Arthas是一个Java诊断工具,由阿里巴巴中间件团队开源,目前已在Java开发人员中被广泛采用。Arthas能够分析,诊断,定位Java应用问题,例如:JVM信息,线程信息,搜索类中的方法,跟踪代码执行,观测方法的入参和返回参数等等。并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法的出入参,异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。简单的话:就是再不重启应用的情况下达到排查问题的目的。

特性

  • 仪表盘实时查看系统的运行状态。
  • OGNL表达式查看参数和返回值/例外,查看方法参数、返回值和异常。
  • 通过jad/sc/redefine实现在线热插拔。
  • 快速解决类冲突问题,定位类加载路径。
  • 快速定位应用热点和生成火焰图。
  • 支持在线诊断WebConsole。
  • Arthas对应用程序没有侵入(但对宿主机jvm有侵入),代码或项目中不需要引入jar包或依赖,因为是通过attach的机制实现的,我们的应用的程序和arthas都是独立的进程,arthas是通过和jvm底层交互来获取运行在其上的应用程序实时数据的,灵活查看运行时的值,这个和hickwall,jprofiler等监控软件的区别(JPofiler也有这样的功能,但是是收费的)动态增加aop代理和监控日志功能,无需重启服务,而且关闭arthas客户端后会还原所有增强过的类,原则上是不会影响现有业务逻辑的。
  • 对应用程序所在的服务器性能的影响,个别命令使用不当的话,可能会撑爆jvm内存或导致应用程序响应变慢,命令的输出太多,接口调用太频繁会记录过多的数据变量到内存里,比如tt指令,建议加 -n 参数 限制输出次数,sc * 通配符的使用不当,范围过大,使用异步任务时,请勿同时开启过多的后台异步命令,以免对目标JVM性能造成影响,一把双刃剑(它甚至可以修改jdk里的原生类),所以在线上运行肯定是需要权限和流程控制的。

使用场景

在日常开发中,当我们发现应用的某个接口响应比较慢,这个时候想想要分析一下原因,找到代码中耗时的部分,比较容易想到的是在接口链路的 IO 操作上下游打印时间日志,再根据几个时间点的日志算出耗时长的 IO 操作。这种方式没有问题,但是加日志需要发布,既繁琐又低效,这个时候可以引入一些线上 debug 的工具,arthas 就是很好的一种,除了分析耗时,还可以打印调用栈、方法入参及返回,类加载情况,线程池状态,系统参数等等,其实现原理是解析 JVM 在操作系统中的文件,大部分操作是只读的,对服务进程没有侵入性,因此可以放心使用。

实战

CPU占用高示例

创建一个springboot项目并打包成arthas-demo-1.0.jar,启动arthas-demo-1.0.jar

代码示例如下

package cn.itxs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
​
@SpringBootApplication
public class App 
{
    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
        new Thread( () -> {
            while (true) {
                String str = UUID.randomUUID().toString().replaceAll("-", "");
            }
        },"cpu demo thread").start();
​
        new Thread( () -> {
            while (true) {
                String str = UUID.randomUUID().toString().replaceAll("-", "");
                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"cpu with sleep thread").start();
    }
}

安装与使用

推荐方式

# 下载`arthas-boot.jar`这种也是官方推荐的方式
curl -O https://arthas.aliyun.com/arthas-boot.jar
# 启动arthas-boot.jar,必须启动至少一个 java程序,否则会自动退出。运行此命令会自动发现 java进程,输入需要 attach 进程对应的序列号,例如,输入1按回车则会监听该进程。
java -jar arthas-boot.jar
# 比如输入JVM (jvm实时运行状态,内存使用情况等)

CPU占用高示例

package cn.itxs.controller;
​
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
​
import java.util.concurrent.TimeUnit;
​
@RestController
@RequestMapping("/thread")
public class ThreadController {
    private Object obj1 = new Object();
    private Object obj2 = new Object();
​
    @RequestMapping("/test")
    @ResponseBody
    public String test(){
        new Thread(() -> {
            synchronized (obj1){
                try {
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    synchronized (obj2){
                        System.out.printf("thread 1执行到此");
                    }
                }
            }
        },"thread 1").start();
​
        new Thread(() -> {
            synchronized (obj2) {
                synchronized (obj1){
                    System.out.printf("thread 2执行到此");
                }
            }
        },"thread 2").start();
        return "thread test";
    }
}

SpringBoot启动类

package cn.itxs;
​
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
​
@SpringBootApplication
public class App 
{
    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }
}
# 访问页面http://192.168.50.100:8080/cpu/test
# 仪表盘命令,通过上面我们可以发现线程ID为29也即是线程名称为“cpu demo thread”占用的cpu较高
dashboard

  • 第一部分时显示JVM中运行的所有线程:所在线程组,优先级,线程的状态,CPU的占有率,是否是后台进程等。
  • 第二部分显示的JVM内存的使用情况和GC的信息。
  • 第三部分是操作系统的一些信息和 Java版本号。
# 当前最忙的前N个线程 thread -b, ##找出当前阻塞其他线程的线程 thread -n 5 -i 1000 #间隔一定时间后展示,本例中可以看到最忙CPU线程为id=45,代码行数为19
thread -n 5 
# jad查看反编译的代码
jad cn.itxs.controller.CpuController

线程死锁示例

package cn.itxs.controller;
​
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
​
@RestController
@RequestMapping("/thread")
public class ThreadController {
    private Object obj1 = new Object();
    private Object obj2 = new Object();
​
    @RequestMapping("/test")
    @ResponseBody
    public String test(){
        new Thread(() -> {
            synchronized (obj1){
                try {
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                }
                synchronized (obj2){
                    System.out.println("thread 1执行到此");
                }
            }
        },"thread 1").start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            synchronized (obj2) {
                synchronized (obj1){
                    System.out.println("thread 2执行到此");
                }
            }
        },"thread 2").start();
        return "thread test";
    }
}
# 启动SpringBoot演示程序,访问页面http://192.168.50.100:8080/thread/test
# 运行arthas,查看线程
thread
# 查看阻塞线程
thread -b
# jad反编译查看代码
jad --source-only cn.itxs.controller.ThreadController

线上修复热部署

准备一个有问题的java类

package cn.itxs.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/hot")
public class HotController {

    @RequestMapping("/test")
    @ResponseBody
    public String test(){
        boolean flag = true;
        if (flag) {
            System.out.println("开始处理逻辑");
            throw new RuntimeException("出异常了");
        }
        System.out.println("结束流程");
        return "hot test";
    }
}

启动Spring Boot程序,访问页面http://192.168.50.94:8080/hot/test发现报错,当我们分析到这段程序出异常后,我们分析异常后进行线上代码修改不停机不重新发包的情况下的热更新,操作流程如下:

# 第一步:`jad命令` 将需要更改的文件先进行反编译,保存下来 ,编译器修改,-c 指定这个类的classloader的哈希值,–source-only只显示源码,最后是文件反编译之后的存放路径
jad --source-only cn.itxs.controller.HotController > /home/commons/arthas/data/HotController.java
# 我们将HotController.java中的throw new RuntimeException("出异常了")代码删掉,修改完后需要将类重新加载到JVM
# 第二步:`SC命令` 查找当前类是哪个classLoader加载的,首先,使用sc命令找到要修改的类.sc全称-search class, -d表示detail,主要是为了获取classLoader的hash值
sc -d *HotController | grep classLoader
classLoaderHash   6267c3bb #类加载器  编号  
# 第三步:`MC命令` 用指定的classloader重新将类在内存中编译
mc -c 6267c3bb /home/commons/arthas/data/HotController.java -d /home/commons/arthas/class
# 第四步:`redefine命令` 将编译后的类加载到JVM,参数是编译后的.class文件地址
redefine /home/commons/arthas/class/cn/itxs/controller/HotController.class  

以上操作后再次访问一下页面http://192.168.50.94:8080/hot/test,发现异常没有了程序已经是我们修改正确后的,class文件替换成功,功能确实很强大。

上面我们是手工一步步执行,当然我们可以使用shell脚本串起来简单操作。

此外还可以安装Alibaba Cloud Toolkit热部署组件(一键retransform),热部署组件支持一键将编辑器中修改的 Java 源码快速编译,并更新到远端应用服务中,免去手动 dump、mc 的过程。此外,也可以一键还原 retransform 的类文件。

由于Arthas命令还是较复杂,Arthas-idea插件(部分命令可视化)是一个帮助生成命令的IDEA插件,使用文档:https://www.yuque.com/arthas-idea-plugin

安装基于Arthas实现的简单好用的热部署插件ArthasHotSwap可以一键生成热部署命令,提高我们线上维护的效率。

线上问题常见定位

watch(方法执行数据观测)

package cn.itxs.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@RestController
@RequestMapping("/watch")
public class WatchController {
    private static Random random = new Random();
    private int illegalArgumentCount = 0;

    @RequestMapping("/test")
    @ResponseBody
    public String test(){
        String res = null;
        try {
            int number = random.nextInt() / 10000;
            List<Integer> idStrs = this.getIdStr(number);
            res = printList(number, idStrs);
        }
        catch (Exception e) {
            System.out.println(String.format("illegalArgumentCount:%3d, ", this.illegalArgumentCount) + e.getMessage());
        }
        return res;
    }

    private List<Integer> getIdStr(int number) {
        if (number < 5) {
            ++this.illegalArgumentCount;
            throw new IllegalArgumentException("number is: " + number + ", need >= 5");
        }
        ArrayList<Integer> result = new ArrayList<Integer>();
        int count = 2;
        while (count <= number) {
            if (number % count == 0) {
                result.add(count);
                number /= count;
                count = 2;
                continue;
            }
            ++count;
        }
        return result;
    }

    private String printList(int number, List<Integer> primeFactors) {
        StringBuffer sb = new StringBuffer(number + "=");
        for (int factor : primeFactors) {
            sb.append(factor).append('*');
        }
        if (sb.charAt(sb.length() - 1) == '*') {
            sb.deleteCharAt(sb.length() - 1);
        }
        System.out.println(sb);
        return sb.toString();
    }
}

启动Spring Boot程序,通过Jmeter每秒访问一次http://192.168.50.100:8080/watch/test

# Arthas中的**watch**命令可以让我们能方便的观察到指定方法的调用情况,可以观察到返回值,入参,以及变量等。
# watch 全路径类名 方法名 观察表达式 -x 3  ,观察表达式匹配ognl表达式,观察的维度也比较多。
# 比如:watch cn.itxs.controller.WatchController printList "{params,returnObj}" -x 3
# 查看printList方法的入参和出参,-x表示的是遍历结果深度默认1,只会打印对象的堆地址,看不到具体的属性值,-x 2会打印结果的属性值的信息 -x 3会输出入参属性值和结果属性值
# -n 1只抓紧一次,由于我们这里是模拟一直请求的
watch cn.itxs.controller.WatchController printList '{params}' -n 1
# -x 表示的是遍历结果深度默认3
watch cn.itxs.controller.WatchController printList '{params}' -n 1 -x 3
# params[0]代表第一个参数
watch cn.itxs.controller.WatchController printList '{params[0]}' -n 1 -x 3

# 方法的返回值
watch cn.itxs.controller.WatchController getIdStr '{returnObj}' -n 1 -x 3
# 方法参数和返回值
watch cn.itxs.controller.WatchController getIdStr '{params,returnObj}' -n 1 -x 3

# 观察方法执行前后当前对象属性值
watch cn.itxs.controller.WatchController getIdStr 'target.illegalArgumentCount'

# 观察异常信息,观察表达式里增加throwExp就好了。如果增加-e 参数就能过滤掉非异常的监听了。

# 在观察表达式后面,我们可以增加条件表达式,例如按时间过滤:#cost>0.5,单位是毫秒,那么控制台输出来的都是耗时在0.5毫秒以上的方法调用
watch cn.itxs.controller.WatchController getIdStr '{params}' '#cost>0.5'

# 按条件过滤观察params[1].size>4:这里支持ognl表达式。下面例子的意思是:第二个参数(也就是List primeFactors),的size大于4的时候才观察入参。
watch cn.itxs.controller.WatchController printList '{params}' 'params[1].size>4' -x 3

monitor(方法执行监控)

monitor结果包括如下

  • **timestamp:时间戳 **
  • class:Java类
  • method:方法(构造方法、普通方法)
  • total:调用次数
  • success:成功次数
  • fail:失败次数
  • rt:平均RT
  • fail-rate:失败率
# -c :统计周期,默认值为10秒
monitor -c 10 cn.itxs.controller.WatchController getIdStr
# 在方法调用之前计算condition-express,方法后可带表达式
monitor -b -c 10 cn.itxs.controller.WatchController getIdStr

trace

# trace:方法内部调用路径,并输出方法路径上的每个节点上耗时
trace cn.itxs.controller.WatchController test -n 2
#包含jdk的函数--skipJDKMethod <value>  skip jdk method trace, default value true.默认情况下,trace不会包含jdk里的函数调用,如果希望trace jdk里的函数,需要显式设置--skipJDKMethod false。
trace --skipJDKMethod false cn.itxs.controller.WatchController test -n 2
# 调用耗时过滤,只会展示耗时大于10ms的调用路径,有助于在排查问题的时候,只关注异常情况
trace cn.itxs.controller.WatchController test '#cost > 1'

stack

# 输出当前方法被调用的调用路径,getIdStr是从test方法调用进来的
stack cn.itxs.controller.WatchController getIdStr -n 1
# 输出当前方法被调用的调用路径,条件表达过滤,第0个参数小于0,也可以根据执行时间来过滤,'#cost>1'
stack cn.itxs.controller.WatchController getIdStr 'params[0]<0' -n 1

tt

tt(TimeTunnel):方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测。对于一个最基本的使用来说,就是记录下当前方法的每次调用环境现场。

# 记录指定方法的每次调用环境现场
tt -t cn.itxs.controller.WatchController getIdStr 
# 列出所有调用记录
tt -l cn.itxs.controller.WatchController getIdStr

# 筛选调用记录
tt -s 'method.name=="getIdStr"'
# 查看调用信息
tt -i 1001

# 重新发起一次调用
tt -i 1001 -p

Web Console

# 启动时指定Linux的ip
java -jar arthas-boot.jar --target-ip 192.168.50.94

profiler

profiler** 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。一般分析性能可以先通过Arthas profiler命令生成**jfr文件;在本地通过 jprofiler来分析 jfr文件,定位谁在调用我。

# 启动profiler 默认情况下,生成的是cpu的火焰图,即event为cpu。可以用--event参数来指定
profiler start
# 获取已采集的sample的数量
profiler getSamples
# 查看profiler状态
profiler status
# 停止profiler 生成html格式结果,默认情况下,结果文件是html格式,也可以用--format参数指定;或者在--file参数里用文件名指名格式。比如--file /tmp/result.html
profiler stop --format html

通过浏览器查看arthas-output下面的profiler结果,http://192.168.50.100:3658/arthas-output/

# profiler支持的events
profiler list

# 可以用--event参数指定要采样的事件,比如对alloc事件进入采样:
profiler start --event alloc
# 使用execute来执行复杂的命令
profiler execute 'start,framebuf=5000000'
# 生成 jfr格式结果;注意,jfr只支持在 start时配置。如果是在stop时指定,则不会生效。
profiler start --file /tmp/test.jfr
# 配置 include/exclude 来过滤数据
profiler start --include 'java/*' --include 'demo/*' --exclude '*Unsafe.park*'
# profiler执行 300 秒自动结束,可以用 -d/--duration 参数指定
profiler start --duration 300

其他功能

  • 提供Http API可以提供结构化的数据,支持更复杂的交互功能,比如特定应用场景的一系列诊断操作。Http API接口地址为:http://ip:port/api**,必须使用POST方式提交请求参数。如POST **http://127.0.0.1:8563/api
{
  "action": "exec",
  "requestId": "req112",
  "sessionId": "94766d3c-8b39-42d3-8596-98aee3ccbefb",
  "consumerId": "955dbd1325334a84972b0f3ac19de4f7_2",
  "command": "version",
  "execTimeout": "10000"
}
  • docker使用,很多时候,应用在docker里出现arthas无法工作的问题,是因为应用没有安装 JDK ,而是安装了 JRE 。如果只安装了 JRE,则会缺少很多JAVA的命令行工具和类库,Arthas也没办法正常工作,可以使用公开的JDK镜像和包管理软件来安装这两种方式在Docker里使用JDK。# 选择需要监控应用的进程编号,回车后Arthas会attach到目标进程上,并输出日志: docker exec -it arthas-demo /bin/sh -c "java -jar /opt/arthas/arthas-boot.jar" # 甚至我们可以直接把arthas放到容器镜像文件中:
  • Arthas Spring Boot Starter:应用启动后,spring会启动arthas,并且attach自身进程。 <dependency> <groupId>com.taobao.arthas</groupId> <artifactId>arthas-spring-boot-starter</artifactId> <version>${arthas.version}</version> </dependency>
  • 非spring boot应用使用方式
        <dependency>
            <groupId>com.taobao.arthas</groupId>
            <artifactId>arthas-agent-attach</artifactId>
            <version>${arthas.version}</version>
        </dependency>
        <dependency>
            <groupId>com.taobao.arthas</groupId>
            <artifactId>arthas-packaging</artifactId>
            <version>${arthas.version}</version>
        </dependency>
import com.taobao.arthas.agent.attach.ArthasAgent;
 
public class ArthasAttachExample {
  
    public static void main(String[] args) {
        ArthasAgent.attach();
    }
}

原文来自IT小神博客 http://www.itxiaoshen.cn

rthas对于SpringBoot2的支持和监控体系

在SpringBoot2应用中加入arthas-spring-boot-starter后,Spring会启动arthas服务,并且进行attach自身进程,并配合tunnel server实现远程管理。这样的方案非常适合在微服务容器环境中进行远程诊断,在容器网络环境中仅需要对外暴露tunnel server的端口。

Arthas的监控体系所需要的组件支持

  • Arthas Tunnel Server/Client(Java agent探针的管理和监控,方便我们管理服务和探针)
  • Web Console

什么是Arthas Tunnel

在容器化部署的环境内部,Java进程可以是在不同的机器启动的,想要使用Arthas去诊断会比较麻烦,因为用户通常没有机器的权限,即使登陆机器也分不清是哪个Java进程。在这种情况下,可以使用 Arthas Tunnel Server/Client。

Arthas Tunnel的作用和目的

整个Arthas的功能体系中,可以通过Arthas Tunnel Server/Client来远程管理/连接多个Agent(也就代表着可以监控多个JVM进程)。主要目的用于监控和获取目标的JVM的进程数据信息。

下载部署Arthas tunnel server

Github源码仓库下载

下载地址Arthas tunnel server,目前最新版本为arthas-all-3.6.7版本,如下图所示。

针对于Arthas的安装包进行下载资料进行介绍:

  • arthas-3.6.7.deb:主要用于debian操作系统去运行的安装包
  • arthas-bin.zip:二进制可运行执行包
  • arthas-doc.zip:针对于arthas的文档
  • arthas-tunnel-server-3.6.7-fatjar.jar:Arthas tunnel server服务的Jar可以执行包
  • Source code(zip):源码zip压缩包
  • Source code(tar.gz):源码tar包

Maven仓库下载

阿里云的下载地址:arthas.aliyun.com/download/ar…

直接运行对应的Arthas tunnel server

Arthas tunnel server是一个Spring boot fat jar 应用,直接java -jar启动:

java -jar  arthas-tunnel-server.jar
复制代码

默认情况下,arthas tunnel server的web端口是8080,Arthas agent 连接的端口是7777

打开WebConsole,分别输入Arthas agent的ip(127.0.0.1)和port(7777),和SpringBoot应用里配置的agent-id(URJZ5L48RPBR2ALI5K4V),点Connect即可。

Web Console

如果希望可以通过浏览器连接Arthas服务,此时这里的Arthas服务指的不是Arthas tunnel server,Arthas是总体的服务控制端,发送指令的部分,而Arthas tunnel server属于对接和管理agent的专门服务(依赖于Arthas Spring Boot Starter的服务)。

出了CLI模式之外,Arthas目前支持 Web Console,用户在attach成功之后,可以直接访问:http://127.0.0.1:8563/。 可以填入 IP,远程连接其它机器上的arthas。启动之后,可以访问 http://127.0.0.1:8080/ ,再通过agentId连接到已注册的arthas agent 上,如下图所示。

通过Spring Boot的Endpoint,可以查看到具体的连接信息: http://127.0.0.1:8080/actuator/arthas ,

登陆用户名是arthas,密码在 arthas tunnel server 的日志里可以找到,比如:

注意:默认情况下,arthas 只 listen 127.0.0.1,所以如果想从远程连接,则可以使用 --target-ip参数指定 listen 的 IP,更多参考-h的帮助说明。 注意会有安全风险,考虑下面的 tunnel server 的方案。

如何将服务连接Arthas tunnel server

主要有两种模式连接Arthas tunnel server:

  1. 远程运行的Arthas server连接Arthas tunnel server
  2. 远程运行的Arthas Spring Boot Starter的agent探针服务连接Arthas tunnel server

启动 arthas 时连接到 tunnel server

在启动 arthas,可以传递--tunnel-server参数,比如:

as.sh --tunnel-server 'ws://127.0.0.1:7777/ws'
复制代码

如果有特殊需求,可以通过--agent-id参数里指定 agentId。默认情况下,会生成随机 ID。attach 成功之后,会打印出 agentId。

  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'

wiki      https://arthas.aliyun.com/doc
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html
version   3.1.2
pid       86183
time      2022-11-30 15:40:53
id        URJZ5L48RPBR2ALI5K4V

复制代码

即使是启动时没有连接到 tunnel server,也可以在后续自动重连成功之后,通过 session 命令来获取 agentId:

[arthas@86183]$ session
 Name           Value
-----------------------------------------------------
 JAVA_PID       86183
 SESSION_ID     f7273eb5-e7b0-4a00-bc5b-3fe55d741882
 AGENT_ID       URJZ5L48RPBR2ALI5K4V
 TUNNEL_SERVER  ws://127.0.0.1:7777/ws
复制代码

在浏览器里访问 http://localhost:8080/arthas,输入agentId,就可以连接到本机/其他机器上上的 arthas 了。

tunnel server的注意要点

  • agentId要保持唯一,否则会在 tunnel server 上冲突,不能正常工作。
  • 如果arthas agent配置了appName,则生成的agentId会带上appName的前缀。

添加对应的app-name参数

启动参数

as.sh --tunnel-server 'ws://127.0.0.1:7777/ws' --app-name demoapp ,则生成的 agentId 可能是demoapp_URJZ5L48RPBR2ALI5K4V。
复制代码

Tunnel server 会以_做分隔符,提取出appName,方便按应用进行管理

配置参数

解压的 arthas 目录下的 arthas.properties,或者在 spring boot 应用的application.properties里配置appName。

Arthas Spring Boot Starter的agent服务连接Jar

只支持 springboot2

  • maven的仓库地址:search.maven.org/search?q=a:…

  • 配置 maven 依赖:

arthas.version:3.6.7

<dependency>
     <groupId>com.taobao.arthas</groupId>
    <artifactId>arthas-spring-boot-starter</artifactId>
    <version>${arthas.version}</version>
</dependency>
复制代码

应用启动后,spring 会启动 arthas,并且 attach 自身进程。如果你不知道如何创建或者引入哪些依赖,可以采用一键创建包含 Arthas Spring Boot Starter 的工程:点击跳转到云原生脚手架

可以看到最下面已经自动勾选了arthas的监控机制体系。

application.yml配置

arthas:
  agent-name: nihaotest
  agent-id: URJZ5L48RPBR2ALI5K4V  #需手工指定agent-id
  tunnel-server: ws://127.0.0.1:7777/ws
复制代码

查看 Endpoint 信息

需要配置 spring boot 暴露 endpoint:假定endpoint 端口是 8080,则通过下面 url 可以查看:

http://localhost:8080/actuator/arthas

{
    "arthasConfigMap": {
        "agent-id": "hsehdfsfghhwertyfad",
        "tunnel-server": "ws://47.75.156.201:7777/ws",
    }
}
复制代码

最后,启动SpringBoot服务即可

非 spring boot 应用使用方式

非 Spring Boot 应用,可以通过下面的方式来使用:

 <dependency>
     <groupId>com.taobao.arthas</groupId>
     <artifactId>arthas-agent-attach</artifactId>
     <version>${arthas.version}</version>
 </dependency>
 <dependency>
      <groupId>com.taobao.arthas</groupId>
     <artifactId>arthas-packaging</artifactId>
     <version>${arthas.version}</version>
</dependency>
复制代码

attach本身的服务进行探针探测。

import com.taobao.arthas.agent.attach.ArthasAgent;
public class ArthasAttachExample {
	public static void main(String[] args) {
		ArthasAgent.attach();
	}
}
复制代码

也可以配置属性:

HashMap<String, String> configMap = new HashMap<String, String>();
configMap.put("arthas.appName", "demo");
configMap.put("arthas.tunnelServer", "ws://127.0.0.1:7777/ws");
ArthasAgent.attach(configMap);
复制代码

Tunnel Server 的管理页面

需要在 spring boot 的application.properties里配置 arthas.enable-detail-pages=true

注意,开放管理页面有风险!管理页面没有安全拦截功能,务必自行增加安全措施。

在本地启动 tunnel-server,然后使用as.sh attach,并且指定应用名--app-name test:

$ as.sh --tunnel-server 'ws://127.0.0.1:7777/ws' --app-name test
telnet connecting to arthas server... current timestamp is 1627539688
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'

wiki       https://arthas.aliyun.com/doc
tutorials  https://arthas.aliyun.com/doc/arthas-tutorials.html
version    3.5.3
main_class demo.MathGame
pid        65825
time       2022-07-29 14:21:29
id         test_PE3LZO9NA9ENJYTPGL9L

复制代码

然后访问 tunnel-server,可以看到所有连接的应用列表:

http://localhost:8080/apps.html
复制代码

再打开详情,则可以看到连接的所有 agent 列表:

http://localhost:8080/agents.html?app=test
复制代码


链接:https://juejin.cn/post/7213744681393176633