前言:为什么需要全链路监控?
在分布式系统中,一个用户请求可能穿越 Struts2 控制器、Spring 服务、Hibernate 数据访问等多个层级,传统日志排查方式面临三大痛点:
- 故障定位难:无法快速追踪请求流经路径,问题排查耗时久(某银行案例显示,未接入 APM 时异常定位需 45 分钟);
- 性能瓶颈隐蔽:缺乏各组件耗时统计,难以识别慢 SQL、低效方法等瓶颈;
- 系统行为不透明:微服务调用链路复杂,无法直观掌握系统运行状态。
而 Webfunny APM 结合 OpenTelemetry 可完美解决这些问题 —— 无需大规模改造 SSH 老项目,即可实现零侵入 / 低侵入的全链路追踪。本文将详细拆解对接过程,从环境配置到验证落地,带你快速上手。
一、项目技术栈与对接核心方案
1. 基础技术栈(SSH 框架适配版)
2. 核心集成架构
采用「Agent 自动注入 + OTLP 协议上报」方案,整体链路如下:
用户请求 → OpenTelemetry Java Agent(自动采集)→ SSH 各层级(Struts2→Spring→Hibernate)→
OTLP Exporter → OpenTelemetry Collector → Webfunny APM 平台
关键优势:
- 零侵入:Agent 方式无需修改 SSH 业务代码,老项目快速适配;
- 全覆盖:自动采集 HTTP 请求、SQL 执行、方法调用等核心数据;
- 标准化:基于 OpenTelemetry 协议,支持后续对接其他 APM 平台(如 Elastic、Datadog)。
二、详细对接步骤(直接抄作业)
1. 第一步:添加 Maven 依赖
在 pom.xml 中引入 OpenTelemetry 核心依赖(用于注解增强和 API 调用):
<dependencies>
<!-- OpenTelemetry API -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.24.0</version>
</dependency>
<!-- OpenTelemetry 注解支持 -->
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-annotations</artifactId>
<version>1.24.0</version>
</dependency>
</dependencies>
2. 第二步:配置 OpenTelemetry Java Agent
2.1 下载 Agent 包
2.2 编写启动脚本(关键配置)
#!/bin/bash
# ====================== OpenTelemetry 核心配置 ======================
# 服务名称(Webfunny 平台显示用)
OTEL_SERVICE_NAME="Pro-sshDemo"
# 资源属性(环境标识、实例ID,便于多环境区分)
OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production,service.instance.id=ssh-app-01,service.version=2.0"
# Webfunny OTLP 上报端点(注意:原文档中 http://staging.webfunny.cn:9013 若解析失败,需检查网络连通性)
OTEL_EXPORTER_OTLP_ENDPOINT="http://staging.webfunny.cn:9013"
# 传输协议(GRPC 性能更优,若报错可改为 http/protobuf)
OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
# 超时时间
OTEL_EXPORTER_OTLP_TIMEOUT="10s"
# 仅开启 Trace 采集(Metrics/Logs 按需启用)
OTEL_TRACES_EXPORTER="otlp"
OTEL_METRICS_EXPORTER="none"
OTEL_LOGS_EXPORTER="none"
# 全局方法扫描(无需注解,自动采集指定包下所有方法)
OTEL_INSTRUMENTATION_METHODS_INCLUDE="com.yourapp.service.*,com.yourapp.action.*,com.yourapp.dao.*"
# 排除工具类/配置类(减少冗余 Span)
OTEL_INSTRUMENTATION_METHODS_EXCLUDE="com.yourapp.util.*,com.yourapp.config.*"
# ====================== 应用启动配置 ======================
# Agent 路径(替换为你的实际路径)
OTEL_AGENT_JAR="/opt/otel/opentelemetry-javaagent.jar"
# 端口配置(避免冲突)
JETTY_PORT=8080
# 整合启动参数
export MAVEN_OPTS="\
-javaagent:$OTEL_AGENT_JAR \
-Dotel.service.name=$OTEL_SERVICE_NAME \
-Dotel.resource.attributes=$OTEL_RESOURCE_ATTRIBUTES \
-Dotel.exporter.otlp.endpoint=$OTEL_EXPORTER_OTLP_ENDPOINT \
-Dotel.exporter.otlp.protocol=$OTEL_EXPORTER_OTLP_PROTOCOL \
-Dotel.exporter.otlp.timeout=$OTEL_EXPORTER_OTLP_TIMEOUT \
-Dotel.traces.exporter=$OTEL_TRACES_EXPORTER \
-Dotel.metrics.exporter=$OTEL_METRICS_EXPORTER \
-Dotel.logs.exporter=$OTEL_LOGS_EXPORTER \
-Dotel.instrumentation.methods.include=$OTEL_INSTRUMENTATION_METHODS_INCLUDE \
-Dotel.instrumentation.methods.exclude=$OTEL_INSTRUMENTATION_METHODS_EXCLUDE"
# 启动 Jetty 容器(若用 Tomcat,替换为 catalina.sh start)
mvn jetty:run -Djetty.http.port=$JETTY_PORT
3. 第三步:链路增强(注解 / 全局扫描二选一)
方案 A:@WithSpan 注解(精准控制,生产推荐)
在关键业务方法上添加注解,自定义 Span 名称和类型,适用于核心链路监控:
// Struts2 Action 层(Controller)
@Action("/userList")
public class UserAction {
@WithSpan(value = "UserAction.listUsers", kind = SpanKind.SERVER)
public String list() {
// 业务逻辑...
userService.getAllUsers();
return SUCCESS;
}
}
// Spring Service 层
@Service
public class UserServiceImpl implements UserService {
@WithSpan(value = "UserService.queryAllUsers", kind = SpanKind.INTERNAL)
@Override
public List() {
return userDao.findAll();
}
}
// Hibernate DAO 层
@Repository
public class UserDaoImpl implements UserDao {
@WithSpan(value = "UserDao.findUserList", kind = SpanKind.INTERNAL)
@Override
public List findAll() {
return sessionFactory.getCurrentSession().createQuery("from User").list();
}
}
方案 B:全局方法扫描(零代码,测试 / 快速验证)
通过启动脚本中的 OTEL_INSTRUMENTATION_METHODS_INCLUDE 配置,自动采集指定包下所有方法,无需添加注解,适合快速验证全链路。
两种方案对比:
三、验证与问题排查
1. 本地验证三步法
① 启动应用
# 赋予脚本执行权限
chmod +x start-with-otel.sh
# 启动应用
./start-with-otel.sh
② 发送测试请求
curl http://localhost:8080/userList
③ 验证结果
- 查看应用日志,若输出以下内容说明采集成功:
[otel.javaagent] LoggingSpanExporter - 'GET /userList' : traceId=xxx spanId=xxx SERVER
[otel.javaagent] LoggingSpanExporter - 'UserAction.listUsers' : traceId=xxx spanId=xxx INTERNAL
[otel.javaagent] LoggingSpanExporter - 'UserService.queryAllUsers' : traceId=xxx spanId=xxx INTERNAL
[otel.javaagent] LoggingSpanExporter - 'SELECT * FROM user' : traceId=xxx spanId=xxx CLIENT
- 登录 Webfunny APM 平台,在「链路追踪」模块查看完整调用链。
2. 常见问题排查(避坑指南)
|
问题现象
|
高频原因
|
解决方案
|
|
无 Trace 日志输出
|
Agent 未加载成功
|
1. 检查 -javaagent 路径是否正确;2. 确保 JDK 版本 ≥ 8;3. 避免多个 Agent 冲突(如 SkyWalking、Arthas)
|
|
有日志但 Webfunny 无数据
|
OTLP 端点不通
|
1. 用 nc -zv staging.webfunny.cn 9013 测试网络连通性;2. 若 GRPC 协议报错,改为 OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
|
|
方法扫描未生效
|
包名配置错误
|
1. 包名不要加 java. 前缀;2. 多包用逗号分隔,如 com.yourapp.service.*,com.yourapp.action.*
|
|
SQL 语句未采集
|
Hibernate 版本不兼容
|
确保 Hibernate 版本 ≥ 3.3,Agent 2.22.0 原生支持 3.3+ 版本
|
|
性能下降明显
|
采样率过高
|
添加采样率配置:-Dotel.traces.sampler=parentbased_traceidratio -Dotel.traces.sampler.arg=0.3(30% 采样率)
|
四、最佳实践与性能优化
1. 采样策略优化
链路追踪会产生一定数据量,合理配置采样率平衡监控效果与性能:
- 开发 / 测试环境:全采样(-Dotel.traces.sampler=always_on);
- 生产环境:概率采样(如 30% 采样率)或自适应采样,避免高并发场景下的性能开销。
2. 链路粒度控制
- 核心链路(支付、下单):用 @WithSpan 注解精准采集,保留完整细节;
- 非核心链路(查询、统计):通过全局扫描排除,或降低采样率;
- 排除工具类、循环调用方法,减少冗余 Span。
3. 资源属性规范
务必配置 deployment.environment(环境)和 service.instance.id(实例 ID),便于在 Webfunny 中区分生产 / 测试环境、不同服务器实例,快速定位问题节点。
4. 冷数据处理
Webfunny 支持链路数据归档,可在平台配置 TTL 策略(如 30 天),避免存储资源浪费,降低运维成本。
五、总结
SSH 框架集成 Webfunny APM 的核心优势在于「低侵入、高覆盖」—— 通过 OpenTelemetry Java Agent 实现零代码全链路采集,配合 @WithSpan 注解精准控制粒度,完美适配老项目改造需求。对接后可实现:
- 故障定位效率提升 80%:从 45 分钟缩短至分钟级;
- 全链路可视化:直观查看 HTTP→Action→Service→DAO→DB 的完整调用链;
- 性能瓶颈量化:精准识别慢 SQL、低效方法,为优化提供数据支撑。
如果你的项目是 SSH 架构,且面临故障排查难、性能优化无方向的问题,不妨按照本文步骤对接 Webfunny APM,让分布式系统的运行状态一目了然。