Spring Cloud(十):Spring Cloud Skywalking 以及 JavaAgent

news2025/7/11 18:27:57

链路追踪组件选型

  • Zipkin是Twitter开源的调用链分析工具,目前基于springcloud sleuth得到了广泛的使用,特点是轻量,使用部署简单。
  • Pinpoint是韩国人开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,UI功能强大,接入端无代码侵入。
  • SkyWalking是本土开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,UI功能较强,接入端无代码侵入。目前已加入Apache孵化器。
  • CAT是大众点评开源的基于编码和配置的调用链分析,应用监控分析,日志采集,监控报警等一系列的监控平台工具。

在这里插入图片描述
在这里插入图片描述

探针性能对比:

在三种链路监控组件中,skywalking的探针对吞吐量的影响最小,zipkin的吞吐量居中。pinpoint的探针对吞吐量的影响较为明显

skywalking是什么

skywalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。skywalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。SkyWalking 是观察性分析平台和应用性能管理系统,提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。

  • 官网:http://skywalking.apache.org/

  • 下载:http://skywalking.apache.org/downloads/

  • Github:https://github.com/apache/skywalking

  • 文档:https://skywalking.apache.org/docs/main/v9.1.0/readme/

  • 中文文档: https://skyapm.github.io/document-cn-translation-of-skywalking/

  • 版本: v9.2.0

  • 采集数据——》传输数据——》存储数据——》分析数据——》监控报警

Skywalking主要功能特性

  1. 多种监控手段,可以通过语言探针和service mesh获得监控的数据;
  2. 支持多种语言自动探针,包括 Java,.NET Core 和 Node.JS;
  3. 轻量高效,无需大数据平台和大量的服务器资源;
  4. 模块化,UI、存储、集群管理都有多种机制可选;
  5. 支持告警;
  6. 优秀的可视化解决方案;

Skywalking整体架构

在这里插入图片描述

整个架构分成四部分:

  • 上部分Agent :负责从应用中,收集链路信息,发送给 SkyWalking OAP 服务器;
  • 下部分 SkyWalking OAP :负责接收Agent发送的Tracing数据信息,然后进行分析(Analysis Core),存储到外部存储器(Storage),最终提供查询(Query)功能;
  • 右部分Storage:Tracing数据存储,目前支持ES、MySQL、Sharding Sphere、TiDB、H2多种存储器,目前采用较多的是ES,主要考虑是SkyWalking开发团队自己的生产环境采用ES为主;
  • 左部分SkyWalking UI:负责提供控制台,查看链路等等;

SkyWalking支持三种探针:

  • Agent – 基于ByteBuddy字节码增强技术实现,通过jvm的agent参数加载,并在程序启动时拦截指定的方法来收集数据。
  • SDK – 程序中显式调用SkyWalking提供的SDK来收集数据,对应用有侵入。
  • Service Mesh – 通过Service mesh的网络代理来收集数据。

后端(Backend)

接受探针发送过来的数据,进行度量分析,调用链分析和存储。后端主要分为两部分:

  • OAP(Observability Analysis Platform)- 进行度量分析和调用链分析的后端平台,并支持将数据存储到各种数据库中,如:ElasticSearch,MySQL,InfluxDB等。
  • OAL(Observability Analysis Language)- 用来进行度量分析的DSL,类似于SQL,用于查询度量分析结果和警报。

界面(UI)

  • RocketBot UI – SkyWalking 7.0.0 的默认web UI
  • CLI – 命令行界面

在这里插入图片描述

SkyWalking 环境搭建部署

在这里插入图片描述

  • skywalking agent和业务系统绑定在一起,负责收集各种监控数据
  • Skywalking oapservice是负责处理监控数据的,比如接受skywalking agent的监控数据,并存储在数据库中;接受skywalking webapp的前端请求,从数据库查询数据,并返回数据给前端。- Skywalking oapservice通常以集群的形式存在。
  • skywalking webapp,前端界面,用于展示数据。
  • 用于存储监控数据的数据库,比如mysql、elasticsearch等。

在这里插入图片描述
SkyWalking APM
Java Agent

搭建SkyWalking OAP 服务

1)先使用默认的H2数据库存储,不用修改配置
config/application.yml

2)启动脚本bin/startup.sh

➜  apache-skywalking-apm-bin ./bin/startup.sh
SkyWalking OAP started successfully!
SkyWalking Web Application started successfully!

日志信息存储在logs目录

启动成功后会启动 skywalking-oap-server 和 skywalking-web-ui

skywalking-oap-server服务启动后会暴露端口,修改端口可以修改config/applicaiton.yml

  • 11800 收集监控数据端口
  • 12800 接受前端请求端口

skywalking-web-ui服务会占用 8080 端口, 修改端口可以修改webapp/webapp.yml

  • server.port:SkyWalking UI服务端口,默认是8080;
  • spring.cloud.discovery.client.simple.instances.oap-service:SkyWalking OAP服务地址数组,SkyWalking UI界面的数据是通过请求SkyWalking OAP服务来获得;

SkyWalking中三个概念

  • 服务(Service) :表示对请求提供相同行为的一系列或一组工作负载,在使用Agent时,可以定义服务的名字;
  • 服务实例(Service Instance) :上述的一组工作负载中的每一个工作负载称为一个实例, 一个服务实例实际就是操作系统上的一个真实进程;
  • 端点(Endpoint) :对于特定服务所接收的请求路径, 如HTTP的URI路径和gRPC服务的类名 + 方法签名;
    在这里插入图片描述

SkyWalking快速开始

  1. 通过jar包方式接入
    startup.sh
#!/bin/sh
# SkyWalking Agent配置
export SW_AGENT_NAME=springboot-skywalking-demo #Agent名字,一般使用`spring.application.name`
export SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 #配置 Collector 地址。
export SW_AGENT_SPAN_LIMIT=2000 #配置链路的最大Span数量,默认为 300。
export JAVA_AGENT=-javaagent:/root/skywalking-agent/skywalking-agent.jar
java $JAVA_AGENT -jar springboot-skywalking-demo-0.0.1-SNAPSHOT.jar #jar启动
java -javaagent:/root/skywalking-agent/skywalking-agent.jar 
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 
-DSW_AGENT_NAME=springboot-skywalking-demo -jar springboot-skywalking-demo-0.0.1-SNAPSHOT.jar
-javaagent:/root/skywalking-agent/skywalking-agent.jar
-Dskywalking.agent.service_name=springboot-skywalking-demo
-Dskywalking.collector.backend_service=127.0.0.1:11800

使用skywalking.+配置文件中的配置名作为系统配置项来进行覆盖。 javaagent参数配置方式优先级更高

  1. IDEA中使用Skywalking
    在运行的程序配置jvm参数
-javaagent:/root/skywalking-agent/skywalking-agent.jar
-DSW_AGENT_NAME=springboot-skywalking-demo
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800

Skywalking跨多个微服务追踪 gateway(bug)

解决方案:拷贝agent/optional-plugins目录下的gateway插件和webflux插件到agent/plugins目录

在这里插入图片描述

Skywalking集成日志框架

https://skywalking.apache.org/docs/skywalking-java/latest/en/setup/service-agent/java-agent/application-toolkit-logback-1.x/

在这里插入图片描述

引入依赖

<!-- apm-toolkit-logback-1.x -->
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-logback-1.x</artifactId>
    <version>8.11.0</version>
</dependency>

微服务添加logback-spring.xml文件,并配置 %tid 占位符

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 日志的格式化 -->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
        </encoder>
    </appender>

    <!-- https://skywalking.apache.org/docs/skywalking-java/latest/en/setup/service-agent/java-agent/application-toolkit-logback-1.x/  -->
    <!-- 通过grpc上报日志到skywalking oap-->
    <appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
        </encoder>
    </appender>

    <!-- 设置 Appender -->
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="grpc-log"/>
    </root>

</configuration>

Skywalking通过grpc上报日志 (需要v8.4.0以上)
gRPC报告程序可以将收集到的日志转发到SkyWalking OAP服务器上

在这里插入图片描述
兼容ELK 配置 Logstash
在这里插入图片描述

Skywalking告警通知

skywalking告警的核心由一组规则驱动,这些规则定义在config/alarm-settings.yml文件中,告警规则的定义分为三部分:

  • 告警规则:它们定义了应该如何触发度量警报,应该考虑什么条件;
  • 网络钩子(Webhook}:当警告触发时,哪些服务终端需要被通知;
  • gRPC钩子:远程gRPC方法的主机和端口,告警触发后调用;

为了方便,skywalking发行版中提供了默认的alarm-setting.yml文件,包括一些规则,每个规则有英文注释,可以根据注释得知每个规则的作用:

  • 在最近10分钟的3分钟内服务平均响应时间超过1000ms
  • 最近10分钟内,服务成功率在2分钟内低于80%
  • 服务实例的响应时间在过去10分钟的2分钟内超过1000ms
  • 数据库访问{name}的响应时间在过去10分钟的2分钟内超过1000ms

只要我们的服务请求符合alarm-setting.yml文件中的某一条规则就会触发告警。

比如service_resp_time_rule规则:

该规则表示服务{name}的响应时间在最近10分钟的3分钟内超过1000ms
在这里插入图片描述

  • metrics-name:度量名称,也是OAL脚本中的度量名。默认配置中可以用于告警的度量有:服务,实例,端点,服务关系,实例关系,端点关系。它只支持long,double和int类型。
  • op:操作符。
  • threshold:阈值。
  • period:多久告警规则需要被检查一下。这是一个时间窗口,与后端部署环境时间相匹配。
  • count:在一个周期窗口中,如果按op计算超过阈值的次数达到count,则发送告警
  • silence-period:在时间N中触发报警后,在N -> N + silence-period这段时间内不告警。
  • message:该规则触发时,发送的通知消息。

demo

  1. config/alarm-settings.yml
    在这里插入图片描述
  2. notify
 @RequestMapping("/notify")
 public String notify(@RequestBody Object obj) {
     //TODO 告警信息,给技术负责人发短信,钉钉消息,邮件,微信通知等
     System.err.println(obj.toString());
     return "notify successfully";
 }
  1. log
    在这里插入图片描述
  2. 控制台
    在这里插入图片描述
    参考:https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/backend-alarm.md

在这里插入图片描述

Skywalking持久化追踪数据

基于mysql持久化

  1. 修改config目录下的application.yml,使用mysql作为持久化存储的仓库
  2. 修改mysql连接配置
storage:
  #选择使用mysql   默认使用h2,不会持久化,重启skyWalking之前的数据会丢失
  selector: ${SW_STORAGE:mysql}
  #使用mysql作为持久化存储的仓库
  mysql:
    properties:
      #数据库连接地址  创建swtest数据库
      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://1ocalhost:3306/swtest"}
      #用户名
      dataSource.user: ${SW_DATA_SOURCE_USER:root}
      #密码
      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root}
  1. 添加mysql驱动包
➜  apache-skywalking-apm-bin ls oap-libs/mysql-connector-java-8.0.19.jar
oap-libs/mysql-connector-java-8.0.19.jar

注意:需要添加mysql数据驱动包,因为在lib目录下是没有mysql数据驱动包的,所以修改完配置启动是会报错,启动失败的。
4. 启动Skywalking 查看swtest库生成的表
在这里插入图片描述

同样 Elasticsearch (注意添加索引前缀 namespace)

在这里插入图片描述

自定义SkyWalking链路追踪

<!-- SkyWalking 工具类 -->
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
    <version>8.11.0</version>
</dependency>
  1. 在业务方法中可以TraceContext获取到traceId
@RequestMapping("/list")
public List<User> list(){

    //TraceContext可以绑定key-value
    TraceContext.putCorrelation("name", "fox");
    Optional<String> op = TraceContext.getCorrelation("name");
    log.info("name = {} ", op.get());
    //获取追踪的traceId
    String traceId = TraceContext.traceId();
    log.info("traceId = {} ", traceId);

    return userService.list();
}
  1. @Trace将方法加入追踪链路

如果一个业务方法想在ui界面的追踪链路上显示出来,只需要在业务方法上加上@Trace注解即可

加入@Tags或@Tag为追踪链路增加其他额外的信息,比如记录参数和返回信息

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Trace
    @Tag(key = "list", value = "returnedObj")
    @Override
    public List<User> list() {
        return userMapper.list();
    }

    @Trace
    @Tags({@Tag(key = "param", value = "arg[0]"),
            @Tag(key = "user", value = "returnedObj")})
    @Override
    public User getById(Integer id) {
        return userMapper.getById(id);
    }
}

在这里插入图片描述

Skywalking集群部署(oap服务高可用)

Skywalking集群是将skywalking oap作为一个服务注册到nacos上,只要skywalking oap服务没有全部宕机,保证有一个skywalking oap在运行,就能进行追踪。
搭建一个skywalking oap集群需要:
(1)至少一个Nacos(也可以是nacos集群)
(2)至少一个ElasticSearch(也可以是es集群)
(3)至少2个skywalking oap服务;
(4)至少1个UI(UI也可以集群多个,用Nginx代理统一入口)

  1. 修改config/application.yml文件
    • 使用nacos作为注册中心
    • 修改nacos配置
    • 可以选择性修改监听端口
cluster:
	selector: ${SW_CLUSTER:nacos}
  nacos:
    serviceName: ${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"}
    hostPort: ${SW_CLUSTER_NACOS_HOST_PORT:localhost:8848}
    # Nacos Configuration namespace
    namespace: ${SW_CLUSTER_NACOS_NAMESPACE:"public"}
    # Nacos auth username
    username: ${SW_CLUSTER_NACOS_USERNAME:""}
    password: ${SW_CLUSTER_NACOS_PASSWORD:""}
    # Nacos auth accessKey
    accessKey: ${SW_CLUSTER_NACOS_ACCESSKEY:""}
    secretKey: ${SW_CLUSTER_NACOS_SECRETKEY:""}
    internalComHost: ${SW_CLUSTER_INTERNAL_COM_HOST:""}
    internalComPort: ${SW_CLUSTER_INTERNAL_COM_PORT:-1}
  1. 配置ui服务webapp.yml文件的oap-service,写多个oap服务地址
  2. 指定微服务的jvm参数 -Dskywalking.collector.backend_service=ip1:11800,ip2:11800
  3. 启动微服务测试

JavaAgent

引用

-javaagent:instrument-demo/target/instrument-demo-1.0-SNAPSHOT.jar

javassist

  1. pom
<dependencies>
   <dependency>
       <groupId>javassist</groupId>
       <artifactId>javassist</artifactId>
       <version>3.12.1.GA</version>
       <type>jar</type>
   </dependency>
</dependencies>


<build>
   <plugins>
       <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
           <version>2.2</version>
           <configuration>
               <archive>
                   <manifestEntries>
                       <Project-name>${project.name}</Project-name>
                       <Project-version>${project.version}</Project-version>
                       <Premain-Class>com.demo.TestAgent</Premain-Class>
                   </manifestEntries>
               </archive>
               <skip>true</skip>
           </configuration>
       </plugin>
       <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-shade-plugin</artifactId>
           <executions>
               <execution>
                   <phase>package</phase>
                   <goals>
                       <goal>shade</goal>
                   </goals>
               </execution>
           </executions>
           <configuration>
               <artifactSet>
                   <includes>
                       <include>javassist:javassist:jar:</include>
                   </includes>
               </artifactSet>
           </configuration>
       </plugin>
       <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <configuration>
               <source>6</source>
               <target>6</target>
           </configuration>
       </plugin>
   </plugins>
</build>
  1. java

FoxAgent.java

public class TestAgent {
    
    public static void premain(String args, Instrumentation instrumentation){
        System.out.println("premain:获取方法调用时间");
    
        // 添加 Transformer
        ClassFileTransformer transformer = new PerformMonitorTransformer();
        instrumentation.addTransformer(transformer);
    }
}

PerformMonitorTransformer.java

public class PerformMonitorTransformer implements ClassFileTransformer {

    private static final Set<String> classNameSet = new HashSet<String>();
    static {
        // 直接定位
        classNameSet.add("com.demo.HelloService");
        // 间接定位   注解  继承关系
    }

    @Override
    public byte[] transform(ClassLoader loader,
                            String className,
                            Class<?> classBeingRedefined,
                            ProtectionDomain protectionDomain,
                            byte[] classfileBuffer) throws IllegalClassFormatException {
        try {
            String currentClassName = className.replaceAll("/", ".");
            // 只增强Set中含有的类   过滤
            if (!classNameSet.contains(currentClassName)) {
                return null;
            }
            System.out.println("transform: [" + currentClassName + "]");

            CtClass ctClass = ClassPool.getDefault().get(currentClassName);
            CtBehavior[] methods = ctClass.getDeclaredBehaviors();
            for (CtBehavior method : methods) {
                //增强方法
                enhanceMethod(method);
            }
            return ctClass.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private void enhanceMethod(CtBehavior method) throws Exception {
        if (method.isEmpty()) {
            return;
        }
        String methodName = method.getName();
        // 不增强main方法
        if (methodName.equalsIgnoreCase("main")) {
            return;
        }
        // 增强@Test修饰的方法
        if(null == method.getAnnotation(Test.class)){
            return;
        }
     
        final StringBuilder source = new StringBuilder();
        source.append("{")
                    // 前置增强: 加入时间戳
                    .append("long start = System.currentTimeMillis();\n")
                    // 保留原有的代码处理逻辑
                    .append("$_ = $proceed($$);\n")
                    .append("System.out.print(\"method:[" + methodName + "]\");")
                    .append("\n")
                    // 后置增强
                    .append("System.out.println(\" cost:[\" +(System.currentTimeMillis() -start)+ \"ms]\");")
                .append("}");

        ExprEditor editor = new ExprEditor() {
          @Override
          public void edit(MethodCall methodCall) throws CannotCompileException {
              methodCall.replace(source.toString());
          }
        };
        method.instrument(editor);
    }
}

bytebuddy

  1. pom
<dependencies>
    <dependency>
        <groupId>javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.12.1.GA</version>
        <type>jar</type>
    </dependency>

    <dependency>
        <groupId>net.bytebuddy</groupId>
        <artifactId>byte-buddy</artifactId>
        <version>1.5.13</version>
    </dependency>

    <dependency>
        <groupId>net.bytebuddy</groupId>
        <artifactId>byte-buddy-agent</artifactId>
        <version>1.5.13</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Project-name>${project.name}</Project-name>
                        <Project-version>${project.version}</Project-version>
                        <Premain-Class>com.demo.TestAgent</Premain-Class>
                    </manifestEntries>
                </archive>
                <skip>true</skip>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <artifactSet>
                    <includes>
                        <include>javassist:javassist:jar:</include>
                        <include>net.bytebuddy:byte-buddy:jar:</include>
                        <include>net.bytebuddy:byte-buddy-agent:jar:</include>
                    </includes>
                </artifactSet>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>6</source>
                <target>6</target>
            </configuration>
        </plugin>
    </plugins>
</build>
  1. java
    TestAgent
public class TestAgent {
    
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("premain:获取方法调用时间");
        
        AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
            @Override
            public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                    TypeDescription typeDescription,
                    ClassLoader classLoader) {
                return builder
                        // 拦截任意方法
                        .method(ElementMatchers.<MethodDescription>any())
                        // 指定方法拦截器,此拦截器中做具体的操作
                        .intercept(MethodDelegation.to(TimeInterceptor.class));
            }
        };
        
        AgentBuilder.Listener listener = new AgentBuilder.Listener() {
            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, DynamicType dynamicType) {}
            
            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) { }
            
            @Override
            public void onError(String typeName, ClassLoader classLoader, JavaModule module, Throwable throwable) { }
            
            @Override
            public void onComplete(String typeName, ClassLoader classLoader, JavaModule module) { }
        };
        
        new AgentBuilder
                .Default()
                // 指定需要拦截的类
                .type(ElementMatchers.nameStartsWith("com.demo"))
                .transform(transformer)
                .with(listener)
                .installOn(inst);
    }
    
}

TimeInterceptor

public class TimeInterceptor {
    
    @RuntimeType
    public static Object intercept(@Origin Method method,
            @SuperCall Callable<?> callable) throws Exception {
        long start = System.currentTimeMillis();
        try {
            // 原方法执行
            return callable.call();
        } finally {
            System.out.println(method + ": cost " + (System.currentTimeMillis() - start) + "ms");
        }
    }
    
}

Metric Demo

  1. pom
<dependencies>
    <dependency>
        <groupId>javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.12.1.GA</version>
        <type>jar</type>
    </dependency>
</dependencies>


<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Project-name>${project.name}</Project-name>
                        <Project-version>${project.version}</Project-version>
                        <Premain-Class>com.demo.TestAgent</Premain-Class>
                    </manifestEntries>
                </archive>
                <skip>true</skip>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <artifactSet>
                    <includes>
                        <include>javassist:javassist:jar:</include>
                    </includes>
                </artifactSet>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>6</source>
                <target>6</target>
            </configuration>
        </plugin>
    </plugins>
</build>
  1. java
    TestAgent
public class TestAgent {
    
    public static void premain(String agentArgs, Instrumentation inst) {
        
        //每隔5秒打印JVM内存和GC信息
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                Metric.printMemoryInfo();
                Metric.printGCInfo();
            }
        }, 0, 5000, TimeUnit.MILLISECONDS);
    }
}

Metric

public class Metric {
    private static final long MB = 1048576L;

    public static void printMemoryInfo() {
        MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
        MemoryUsage headMemory = memory.getHeapMemoryUsage();

        String info = String.format("\nHeapMemory init: %s\t max: %s\t used: %s\t committed: %s\t use rate: %s\n",
                headMemory.getInit() / MB + "MB",
                headMemory.getMax() / MB + "MB", headMemory.getUsed() / MB + "MB",
                headMemory.getCommitted() / MB + "MB",
                headMemory.getUsed() * 100 / headMemory.getCommitted() + "%"

        );

        System.out.print(info);

        MemoryUsage nonheadMemory = memory.getNonHeapMemoryUsage();

        info = String.format("NonHeapMemory init: %s\t max: %s\t used: %s\t committed: %s\t use rate: %s\n",
                nonheadMemory.getInit() / MB + "MB",
                nonheadMemory.getMax() / MB + "MB", nonheadMemory.getUsed() / MB + "MB",
                nonheadMemory.getCommitted() / MB + "MB",
                nonheadMemory.getUsed() * 100 / nonheadMemory.getCommitted() + "%"

        );
        System.out.println(info);
    }

    public static void printGCInfo() {
        List<GarbageCollectorMXBean> garbages = ManagementFactory.getGarbageCollectorMXBeans();
        for (GarbageCollectorMXBean garbage : garbages) {
            String info = String.format("name: %s\t count:%s\t took:%s\t pool name:%s",
                    garbage.getName(),
                    garbage.getCollectionCount(),
                    garbage.getCollectionTime(),
                    Arrays.deepToString(garbage.getMemoryPoolNames()));
            System.out.println(info);
        }
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/8833.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CASIO程序(线路计算6.0版)

一、扩展变量设置说明 统计各种要素点的数目 各要素点数目表 名 称 平曲线交点 竖曲线变坡点 超高起始点 最多台阶数 线路导线点 数目&#xff08;个&#xff09; a b c d e 要素点数目为0时取值 -1 -5/3 0 0 0 备 注 不含起终点 不含起终点 含起…

【LeetCode 力扣】1.两数之和 Java实现 哈希表

题目链接&#xff1a;1.两数之和 1 原题描述&#xff1a; 2 解题思路 初看题目相信大家都能想到枚举的做法&#xff0c;简单来说把数组里面的所有值&#xff0c;均两两组合相加。若结果与target相等&#xff0c;则将两个数字的下标返回即可。 代码实现1&#xff1a; class …

C++入门学习5-共用体,枚举类型,宏定义

入门学习五共用体枚举类型宏定义共用体 共用体也称为联合体&#xff0c;其特点就是用一段连续的内存存储多个不同数据类型的数据&#xff0c;在写法上与结构体相似&#xff0c;但是在同一时刻&#xff0c;共用体中只有一个值是有效的&#xff0c;其大小由共用体中最大的数据类…

做PPT绝对不能错过这5个网站

免费高质量PPT模板网站&#xff0c;建议收藏&#xff01;1、菜鸟图库 https://www.sucai999.com/pptx.html?vNTYxMjky菜鸟图库里面有各种类型的PPT模板和素材。下载后模板可以直接套用&#xff0c;也可以自己添加素材进行修改。所有素材都一一进行了详细的分类&#xff0c;而且…

【前端】Flet:一款支持python及多语言开发的UI库

文章目录介绍开发生态支持语言运行体验组件API热更新开发计划 Roadmap2022 7月-8月安全手机端桌面端Controls(控件)核心功能用户指引&#xff08;User education&#xff09;2022 9月到12月手机端控件&#xff08;Controls&#xff09;编程语言支持核心功能介绍 Flet enables …

【设计模式-2】策略模式 - 避免冗余的if-else判断。数据库迁移框架、flink 类型转换框架例子对策略模式的使用

文章目录1. 介绍2. 策略模式结构3. 策略模式使用3.1. 场景一: 表迁移3.2. flink connector类型转换1. 介绍 当if else过多时&#xff0c;可以通过策略模式来进行重构。先定义一个接口&#xff0c;各else处理分支实现这个接口&#xff0c;并定义 < 条件 , 处理类 > 的映射…

NNG 通信模式

NNG 是 nanomsg 的继任版本,纯c语言开发&#xff0c;工作模式分为几种&#xff1a; 1&#xff0c;Pipeline (A One-Way Pipe) 单向通信&#xff0c;类似与生产者消费者模型的消息队列&#xff0c;消息从推方流向拉方。 #include <stdlib.h> #include <stdio.h> #…

[附源码]java毕业设计基于的图书馆管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

RabbitMQ(四):RabbitMQ高级特性

消息队列在使用过程中&#xff0c;面临着很多实际问题需要思考&#xff1a; 消息可靠性问题&#xff1a;如何确保发送的消息至少被消费—次延迟消息问题&#xff1a;如何实现消息的延迟投递消息堆积问题&#xff1a;如何解决数百万消息堆积&#xff0c;无法及时消费的问题高可用…

面试官:MySQL 上亿大表如何优化?

背景 XX 实例&#xff08;一主一从&#xff09;xxx 告警中每天凌晨在报 SLA 报警&#xff0c;该报警的意思是存在一定的主从延迟。&#xff08;若在此时发生主从切换&#xff0c;需要长时间才可以完成切换&#xff0c;要追延迟来保证主从数据的一致性&#xff09; XX 实例的慢…

Oracle LiveLabs实验:Manage Database Instance and Memory for Oracle Database 21c

概述 此实验申请地址在这里。 实验帮助在这里。 此实验预估完成时间100分钟。 该研讨会介绍了 Oracle 数据库实例的基本知识&#xff0c;并指导您管理 Oracle 数据库的初始化参数和内存结构。 管理初始化参数以在 Oracle 数据库上执行关键任务&#xff0c;例如管理数据库实…

【教学类-08-01】20221010《门牌号(6层*3间 黑色版)》(大班主题《我们的城市》)

效果展示 背景需求&#xff1a; 我的小课题《运用Python设计大班层次性纸类学具的案例研究》获得2022年MHQ小课题立项&#xff0c;在前期的《学号名字描字帖》《身份证》《数字分合》《破译电话号码》的基础上&#xff0c;需要设计更多与大班主题活动书上的主题相关的学习材料。…

利用css 动画实现节流

节流指的避免过于频繁的执行一个函数&#xff0c;例如&#xff1a;一个保存按钮&#xff0c;为了避免重复提交或者服务器考虑&#xff0c;往往需要对点击行为做一定的限制&#xff0c;不然会频繁的请求接口&#xff0c;之前基本上是通过js去控制节流问题&#xff0c;其实css也能…

k-form-design 改成自己组件步骤

1&#xff09;修改package.json {"name": "kk-form-design","version": "1.0.2","private": false,"description": "基于vue、ant-design-vue的表单设计器,可视化开发表单","license": &quo…

Linux下的截图工具 —— Flameshot

一、简介 Flameshot是一款功能强大但易于使用的屏幕截图软件&#xff0c;中文名称火焰截图。Flameshot 简单易用并有一个CLI版本&#xff0c;所以你也可以从命令行来进行截图。Flameshot 是一个Linux发行版中完全免费且开源的截图工具。 特性&#xff1a; 外观可定制化。易于…

数据结构-红黑树

红黑树 二分查找 二叉树 二叉平衡树 平衡因子不超1 查找和二叉查找一样的 删除和插入比较复杂 四种失去平衡的方法 LR 两步 RL 两步 不断旋转比较耗时 进一步改进&#xff1a; 红黑树RBT 调整的次数少 平衡性不如二叉平衡树 &#xff0c; 插入删除频繁的使用红黑树&…

redis的主从复制,哨兵和cluster集群

一、redis性能管理 &#xff08;1&#xff09; redis-cli 127.0.0.1:6379> info memory ​ &#xff08;2&#xff09; redis-cli info memory used_memory_rss&#xff1a;是Redis向操作系统申请的内存。used_memory&#xff1a;是Redis中的数据占用的内存。used_memo…

新手零基础自学Python,安装并配置环境+教程

第一步&#xff1a;搭建python运行环境 在 Windows 上安装 Python 和安装普通软件一样简单&#xff0c;下载安装包以后猛击“下一步”即可。 Python 安装包下载地址&#xff1a;https://www.python.org/downloads/ 打开该链接&#xff0c;可以看到有两个版本的 Python&#…

java框架 —— Spring

Spring[TOC](Spring)1、概述1.1、优点1.2、组成2. IOC概述2.1 什么是IOC2.1.1 推导过程2.1.2 IOC本质2.2 HelloSpring2.2.1 导入Jar包2.2.2 编写代码2.2.2 思考2.3 IOC过程2.4 IOC 接口3. Bean 管理3.1 基于xml方式——set方法注入3.2 FactoryBean3.3 bean 作用域3.4 bean 生命…

Java——面向对象进阶(封装、继承、多态)

Java面向对象三大特性——封装、继承、多态一、封装1.封装基本概念2.访问修饰符3.Java中封装的理解4.封装的优点二、继承1.为什么需要继承2.继承层次结构3.super和this关键字4.继承语法与设计一个继承体系三、多态1.多态的概念2.多态的实现条件3.多态的优缺点一、封装 1.封装基…