字节码的终极应用-GitHub高星开源APM项目之Pinpoint

发布时间 2023-08-14 22:47:20作者: yue_stack

大家好, 我们前面的章节javaagent以及一些字节码修改框架ASM和Javassist, 以及他们的一些简单的应用场景. 今天重点给大家介绍一款github上开源的APM分布式链路监控产品 -- Pinpoint.

Pinpoint是什么?

Pinpoint 是一个开源的APM (Application Performance Management/应用性能管理) 工具,用于基于java的大规模分布式系统。在使用上力图简单高效,通过在启动时安装 agent,不需要修改哪怕一行代码,最小化性能损失 (3%)。

中文参考文档:http://skyao.github.io/leaning-pinpoint/index.html
开源源码地址:https://github.com/naver/pinpoint

Pinpoint的特点

  • 分布式事务跟踪,跟踪跨分布式应用的消息;
  • 自动检测应用拓扑,帮助你搞清楚应用的架构;
  • 水平扩展以便支持大规模服务器集群;
  • 提供代码级别的可见性以便轻松定位失败点和瓶颈;
  • 使用字节码增强技术,添加新功能而无需修改代码。
  • pinpoint有非常直观的UI,符合项目的当前需求
  • pinpoint是基于java开发的,利于项目后期对源代码的修改
  • pinpoint的社区还是挺活跃,一般提问题第二天就有项目的 committer回复。

Pinpoint架构图

架构图对应说明:

  • Pinpoint-Collector:收集各种性能数据
  • Pinpoint-Agent:探针与应用服务器(例如tomcat)关联,部署到同一台服务器上
  • Pinpoint-Web:将收集到的数据层现在web展示
  • HBase Storage:收集到数据存到HBase中

演示Demo

准备工作

为了模拟分布式架构系统, 我们这里准备了三个springboot构建的项目, demoX, demoY, demoZ. 他们之间不仅会相会调用, 每个项目本身还会调用Kafka, Mysql, Redis等中间件. 我们假设他们之家的调用关系是这样的:

  1. demoX程序通过http协议调用demoY程序, 并访问Redis
private final String URL_Y = "http://localhost:18002/demoY/testY";

public String callY() {
    return restTemplate.getForObject(URL_Y, String.class);
}

public void callRedis() {
    redisTemplate.opsForValue().set("APM", "pinpoint");
}
  1. demoY通过http协议调用demoZ程序
public void callZ() {
    restTemplate.getForObject(URL_Z, String.class);
}

public void sendMessage() {
    kafkaTemplate.send("topic_z", "test message");
}
  1. demoZ程序查询Mysql数据库, 并通过json反序列化结果输出
@GetMapping("testZ")
public String testZ() {
    SysLog sysLog = demoZService.callMysql();
    return JSONObject.toJSONString(sysLog);
}

接入pinpoint

接入pinpoint无需修改任何源码, 只需在demoX, demoY, demoZ三个java进程启动的时候, 配置一个--javaagent的参数即可.

java -javaagent:D:/project/2.3.0-all/Assets/pinpoint-agent-2.3.0/pinpoint-bootstrap.jar -Dpinpoint.agentId=app_x_0810 -Dpinpoint.applicationName=app_x -Dpinpoint.profiler.profiles.active=local  -jar demoX.jar

其中

  • -javaagent用于指定pinpoint启动类包的位置
  • -Dpinpoint.applicationName用户指定接入pinpoint的应用名, 一会儿我们会在pinpoint的页面上看到.
  • -Dpinpoint.agentId 用户指定pinpoint的进程名, 用户区分一个应用下的不同实例

启动成功, 会在日志中输出:

08-11 00:46:43.428 INFO  PinpointStarter                     : pinpoint agent started normally.

监控数据查看

指标类数据

接入pinpoint之后,我们可以在页面上直观的看到jvm的各种指标数据, 比如CPU使用率, 堆内存大小, 堆内存使用量, GC次数, GC后的堆回收率等指标. 通过这些图表可以直观的反应当前应用的健康情况.

  • 堆内存与GC图表
    当前堆最大值125M, 已经使用50.7M, Major GC耗时128ms

  • 非堆区域

  • CPU使用率

宿主机使用率9.8%, java进程使用率2.1%

Trace请求数据

Trace请求数据为当前java应用程序实时收到的外界的访问情况.从Trace数据中我们可以直观的看到当前系统的哪些接口被调用, 调用的次数, 接口的调用耗时, 是否存在异常等关键信息, 可以帮助运维和开发人员快速的定位和分析问题.

  • 调用拓扑

如上面准备工作中的调用逻辑, 在pinpoint中可以直观的反应在调用拓扑中.

  • 方法燃尽图
    方法燃尽图是从方法的维度看某一次请求的耗时情况, 从该图中我们可以清洗的看到调用了哪些方法, 他们的耗时是多少. 对于业务开发人员来说, 通常可以一眼就看出哪些方法的耗时偏高.

  • 堆栈明细

堆栈明细是从代码维度来看一次请求经过的所有应用和方法, 以及他们是如何调用了. 我们以请求经过的第一个应用demoX的堆栈明细为例, 请求首先进入Tocmat容器专门处理http请求的方法StandardHostValve.invoke(), 随后经过spring的框架方法FrameworkServlet.doGet(), 然后接下来是用户的业务Controller方法, Service方法, 在业务方法内部, 分别使用redis的set方法往redis中写入了数据, 随后又通过HTTP_Client_4工具发起了http调用, 请求的目的地是localhost:18002/demoY/testY, 也就是我们的demoY应用.如果你是一个有经验的开发人员, 你会一眼就发现调用redis的set方法居然花费了863ms, 这个显然是不符合预期的.

同理, demnY的堆栈:

demoZ的堆栈:

小结

本文我们介绍了一个开源的APM分布式链路监控工具Pinpoint.主要介绍了Pinpoint的架构和特点, 随后我们使用几个简单的demo模拟分布式调用的场景, 和大家一起分析了java应用采集到的各种监控指标, 主要分为Metric(指标数据)和Trace(请求数据). 希望对大家排查问题有一定的帮助.

本文由mdnice多平台发布