SkyWalking
概述
Apache SkyWalking 是应用性能监控(APM)系统,通过 无侵入式字节码增强 实现分布式追踪、服务拓扑分析和告警。与 Micrometer Tracing(侵入式 SDK)不同,SkyWalking 无需修改代码。
核心架构
Agent(Java 应用侧)
├── 通过 javaagent 方式挂载
├── 字节码增强:拦截 HTTP/gRPC/JDBC/Redis 等调用
└── 生成 Span 并上报
↓ gRPC
OAP Server(分析端)
├── 接收 Agent 上报的 Trace 数据
├── 聚合分析(指标、拓扑、告警)
└── 存储到 ES / MySQL / TiDB
↓
UI(Web 控制台)
├── 服务拓扑图
├── 调用链查询
├── 慢 SQL / 慢 Trace
└── 告警管理一、无侵入 Agent 接入
1.1 下载 Agent
bash
# 下载 SkyWalking Agent
wget https://dlcdn.apache.org/skywalking/java-agent/9.1.0/apache-skywalking-java-agent-9.1.0.tgz
tar -xzf apache-skywalking-java-agent-9.1.0.tgz1.2 JVM 参数挂载
bash
# IDEA / 命令行启动
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=order-service \
-Dskywalking.collector.backend_service=oap-server:11800 \
-jar order-service.jar
# Docker 启动
docker run -d \
-e SW_AGENT_NAME=order-service \
-e SW_AGENT_COLLECTOR_BACKEND_SERVICES=oap-server:11800 \
-v /path/to/skywalking-agent:/skywalking-agent \
openjdk:17 \
java -javaagent:/skywalking-agent/skywalking-agent.jar -jar app.jar1.3 Spring Boot 自动配置
yaml
# application.yml(仅需配置 agent 参数,无需添加依赖)
# 所有追踪自动生效:
# - HTTP 请求(Tomcat/Netty)
# - JDBC 查询(含 SQL 参数)
# - Redis 操作
# - RabbitMQ / Kafka 消息
# - gRPC 调用
# - Spring @Async 异步
# - RestTemplate / WebClient1.4 Agent 配置文件
properties
# agent/config/agent.config
# 服务名称
agent.service_name=${SW_AGENT_NAME:my-service}
# 采样率(0-1, 1=全采样)
agent.sample_n_per_3_secs=${SW_SAMPLE_N_PER_3_SECS:-1}
# 忽略特定请求路径
agent.ignore_suffix=.jpg,.jpeg,.js,.css,.png,.bmp,.ico
# OAP 地址
collector.backend_service=${SW_COLLECTOR_BACKEND_SERVICE:127.0.0.1:11800}
# 日志级别
logging.level=${SW_LOGGING_LEVEL:DEBUG}二、OAP Server 部署
2.1 Docker Compose
yaml
version: '3.8'
services:
oap-server:
image: apache/skywalking-oap-server:9.7.0
ports:
- "11800:11800" # gRPC(Agent 上报)
- "12800:12800" # HTTP(UI 查询)
environment:
SW_STORAGE: elasticsearch
SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
SW_STORAGE_ES_INDEX_SHARDS_NUMBER: 2
SW_STORAGE_ES_INDEX_REPLICAS_NUMBER: 0
SW_HEALTH_CHECKER: default
SW_TELEMETRY: prometheus
depends_on:
- elasticsearch
skywalking-ui:
image: apache/skywalking-ui:9.7.0
ports:
- "8080:8080" # Web 控制台
environment:
SW_OAP_ADDRESS: oap-server:12800
depends_on:
- oap-server
elasticsearch:
image: elasticsearch:7.17.21
environment:
discovery.type: single-node
ES_JAVA_OPTS: -Xms1g -Xmx1g
ports:
- "9200:9200"2.2 存储配置
yaml
# OAP Server application.yml
storage:
selector: ${SW_STORAGE:elasticsearch}
elasticsearch:
namespace: ${SW_NAMESPACE:skywalking}
clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:2}
indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0}
# 索引生命周期管理(ILM)
enableILM: ${SW_STORAGE_ES_ENABLE_ILM:true}
dayStep: ${SW_STORAGE_ES_DAY_STEP:1} # 按天创建索引三、Trace 数据模型
3.1 Span 结构
Trace(一次完整的请求链路)
└── Span(一个操作单元)
├── EntrySpan → 服务入口(HTTP 请求)
├── LocalSpan → 本地方法调用
└── ExitSpan → 外部调用(DB/Redis/RPC)3.2 手动创建 Span
java
// 在需要手动埋点的方法中创建 Span
@RestController
public class OrderController {
@Autowired
private Tracer tracer;
@GetMapping("/api/orders/{id}")
public Order getOrder(@PathVariable Long id) {
// 创建自定义 Span
AbstractSpan span = tracer.createSpan("validate_order");
try {
span.tag("order_id", String.valueOf(id));
span.log(Instant.now(), "Start processing order");
// 业务逻辑
Order order = orderService.findById(id);
span.log(Instant.now(), "Order found: " + order.getId());
return order;
} catch (Exception e) {
span.log(Instant.now(), "Error: " + e.getMessage());
span.errorOccurred();
throw e;
} finally {
tracer.stopSpan(span);
}
}
}3.3 跨服务 TraceId 串联
java
// SkyWalking Agent 自动注入 TraceId 到 HTTP Header
// 不需要手动配置拦截器
// Agent 会自动处理以下 Header 的传播:
// - sw8 (SkyWalking 8.x 协议)
// 格式: 1-TRACE_ID-SEGMENT_ID-SPAN_ID-PARENT_SERVICE-PARENT_INSTANCE-PARTER_ENDPOINT-ADDRESS
// 如果需要手动获取 TraceId:
@Component
public class TraceIdHelper {
public String getTraceId() {
return TracingContext.manager()
.currentSpan()
.getSpanId();
}
}四、Spring Cloud 整合
4.1 日志关联 TraceId
xml
<!-- logback-spring.xml -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- %tid 是 SkyWalking 提供的 TraceId 占位符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 需要引入 SkyWalking 日志工具包 -->
<!-- <dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>9.1.0</version>
</dependency> -->4.2 自定义插件开发
java
// 当 Agent 内置插件不满足需求时,可以编写自定义插件
// 示例:拦截自定义 HttpClient 调用
public class CustomHttpClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@Override
public ClassMatch enhanceClass() {
// 匹配目标类
return byName("com.example.CustomHttpClient");
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
// 匹配目标方法
return named("execute");
}
@Override
public String getMethodsInterceptor() {
// 拦截器类
return "com.example.CustomHttpClientInterceptor";
}
}
};
}
}4.3 高级配置
yaml
# agent 插件配置(config/agent.config)
# 开启所有插件
plugin.mount=${SW_PLUGIN_MOUNT:}
# 关闭不需要的插件(提升性能)
plugin.exclude_plugins=websocket,activemq
# 数据库参数采集
plugin.mysql.trace_sql_parameters=${SW_MYSQL_TRACE_SQL_PARAMETERS:true}
plugin.mysql.sql_parameters_max_length=${SW_MYSQL_SQL_PARAMETERS_MAX_LENGTH:512}五、服务拓扑与慢 Trace
5.1 服务拓扑图
SkyWalking UI 自动生成服务拓扑图,展示:
网关 (gateway)
├── 用户服务 (user-service)
│ ├── MySQL (user-db)
│ └── Redis (user-cache)
├── 订单服务 (order-service)
│ ├── MySQL (order-db)
│ └── RabbitMQ (order-queue)
└── 支付服务 (payment-service)
├── MySQL (payment-db)
└── 三方 API (wechat-pay)拓扑图每条连线包含:
- 吞吐量(QPS)
- 平均响应时间(RT)
- 错误率
- 服务依赖深度
5.2 慢 Trace 定位
text
问题:下单接口 P99 响应时间 > 3s
Slow Trace 分析:
1. 入口:POST /api/orders (200ms)
2. 校验库存 → user-service GET /api/users/1 (50ms)
3. 锁定库存 → product-service POST /api/stock/lock (1500ms) ← 慢!
4. 创建订单 → MySQL INSERT (300ms)
5. 调用支付 → payment-service POST /api/payments (1800ms) ← 慢!
结论:库存服务和支付服务是瓶颈
优化方案:
- 库存锁定改为 Redis 预扣(200ms → 10ms)
- 支付调用改为异步(从同步改为 MQ 异步通知)5.3 慢 SQL 分析
sql
-- SkyWalking 捕获的慢 SQL(超过 200ms 的查询)
-- 慢 SQL 1:订单列表查询(耗时 850ms)
SELECT * FROM orders
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT 10
-- 优化建议:添加复合索引 (user_id, created_at)
-- 慢 SQL 2:库存查询(耗时 1200ms)
SELECT p.*, s.quantity FROM products p
LEFT JOIN stock s ON p.id = s.product_id
WHERE p.category_id = ?
ORDER BY p.sales DESC
LIMIT 50
-- 优化建议:添加 category_id + sales 覆盖索引,引入缓存六、告警规则配置
yaml
# config/alarm-settings.yml
rules:
# 规则 1:服务响应时间 > 3s
service_resp_time_rule:
metrics-name: service_resp_time
threshold: 3000
period: 10
count: 3
silence-period: 5
message: 服务 {name} 响应时间在 3 分钟内持续超过 3000ms
# 规则 2:服务成功率 < 99%
service_sla_rule:
metrics-name: service_sla
threshold: 99
op: "<"
period: 10
count: 2
silence-period: 5
message: 服务 {name} 成功率在 2 分钟内低于 99%
# 规则 3:慢 SQL(数据库响应时间 > 500ms)
database_resp_time_rule:
metrics-name: database_access_resp_time
threshold: 500
period: 10
count: 3
message: 数据库访问 {name} 在 3 分钟内持续超过 500ms
# 规则 4:端点错误率 > 10%
endpoint_error_rate_rule:
metrics-name: endpoint_error_rate
threshold: 10
op: ">"
period: 10
count: 3
message: 端点 {name} 错误率在 3 分钟内超过 10%
# Webhook 通知
webhooks:
- http://alert-webhook/notify # 企业微信 / 钉钉机器人七、总结
| 知识点 | 说明 |
|---|---|
| 无侵入 | Java Agent 字节码增强,零代码修改 |
| Trace | 跨服务链路追踪,自动串联 |
| 拓扑 | 服务依赖自动发现 |
| 慢 SQL | 自动捕获慢查询及 SQL 参数 |
| 告警 | 基于指标的告警规则 + Webhook 通知 |
| 存储 | ES / MySQL / TiDB 多种支持 |
| 扩展 | 自定义插件 + 手动 Span 埋点 |
参考链接: