SkyWalking 链路追踪实战
链路追踪原理
核心概念
Trace(追踪):
- 请求在分布式系统中的完整调用链路
- 由多个 Span 组成
- 有唯一的 Trace ID 标识
Span(跨度):
- 追踪中的基本单元
- 代表一次 RPC 调用或本地方法调用
- 包含操作名称、开始时间、结束时间等信息
Segment(段):
- 一次服务调用产生的追踪片段
- 包含该服务内部的所有 Span
- 通过 Ref 关联其他 Segment
Log(日志):
- Span 执行过程中的日志信息
- 可以附加到 Span 上
- 帮助排查问题
追踪流程
客户端请求
│
▼
┌─────────────────┐
│ Gateway │ ← 创建 Entry Span
│ Segment 1 │
└───────┬─────────┘
│
▼
┌─────────────────┐
│ User Service │ ← 创建 Entry Span + Exit Span
│ Segment 2 │
└───────┬─────────┘
│
▼
┌─────────────────┐
│ Database │ ← 创建 Entry Span
│ Segment 3 │
└─────────────────┘
数据模型
{
"traceId": "TID-123456789",
"segments": [
{
"segmentId": "SID-1",
"spans": [
{
"operationName": "/api/users/1",
"startTime": 1680000000000,
"endTime": 1680000000100,
"spanType": "Entry",
"tags": [
{"key": "http.method", "value": "GET"},
{"key": "http.url", "value": "/api/users/1"}
],
"logs": [
{
"time": 1680000000050,
"data": [
{"key": "event", "value": "processing"}
]
}
]
}
]
}
]
}
Agent 配置
1. 基础配置
# agent.config
# 服务名
agent.service_name=user-service
# 命名空间(环境隔离)
agent.namespace=prod
# 实例名
agent.instance_name=instance-1
# OAP 服务器地址
collector.backend_service=127.0.0.1:11800
# 采样率(每秒采样数)
sample_n_per_3_secs=100
# 忽略的后缀
agent.ignore_suffix=.css,.js,.html,.png,.jpg,.jpeg,.gif,.ico,.svg
# 日志配置
logging.dir=logs
logging.level=DEBUG
2. JVM 启动参数
java -javaagent:/path/to/skywalking-agent.jar \
-Dskywalking.agent.service_name=user-service \
-Dskywalking.agent.namespace=prod \
-Dskywalking.collector.backend_service=oap:11800 \
-Dskywalking.logging.level=INFO \
-jar app.jar
3. Docker 部署
FROM openjdk:17-jdk-slim
# 复制 Agent
COPY skywalking-agent /opt/skywalking-agent
# 设置环境变量
ENV SW_AGENT_NAME=user-service
ENV SW_AGENT_NAMESPACE=prod
ENV SW_AGENT_COLLECTOR_BACKEND=oap:11800
# 启动应用
ENTRYPOINT ["java", \
"-javaagent:/opt/skywalking-agent/skywalking-agent.jar", \
"-jar", "/app.jar"]
4. K8s 部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
template:
spec:
containers:
- name: user-service
image: user-service:latest
env:
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/opt/skywalking-agent/skywalking-agent.jar"
- name: SW_AGENT_NAME
value: "user-service"
- name: SW_AGENT_NAMESPACE
value: "prod"
- name: SW_AGENT_COLLECTOR_BACKEND
value: "skywalking-oap:11800"
volumeMounts:
- name: skywalking-agent
mountPath: /opt/skywalking-agent
volumes:
- name: skywalking-agent
configMap:
name: skywalking-agent
自动追踪
1. Web 框架
SkyWalking 自动支持以下 Web 框架:
- Spring MVC
- Spring WebFlux
- JAX-RS
- Struts2
- Play Framework
示例:
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
// 自动追踪
return userService.findById(id);
}
}
2. RPC 框架
支持的 RPC 框架:
- Dubbo
- gRPC
- Thrift
- Motan
- Elastic-Job
示例:
@Service
public class UserServiceImpl implements UserService {
@Override
public User findById(Long id) {
// 自动追踪
return userRepository.findById(id);
}
}
3. 数据库
支持的数据库:
- MySQL
- PostgreSQL
- Oracle
- SQL Server
- H2
- MariaDB
示例:
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public User findById(Long id) {
// 自动追踪 SQL 执行
return jdbcTemplate.queryForObject(
"SELECT * FROM user WHERE id = ?",
new Object[]{id},
new UserMapper()
);
}
}
4. 消息队列
支持的消息队列:
- Kafka
- RabbitMQ
- RocketMQ
- ActiveMQ
- Pulsar
示例:
@Service
public class MessageService {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(String topic, String message) {
// 自动追踪消息发送
kafkaTemplate.send(topic, message);
}
@KafkaListener(topics = "user-topic")
public void listen(String message) {
// 自动追踪消息消费
processMessage(message);
}
}
5. HTTP 客户端
支持的 HTTP 客户端:
- OkHttp
- Apache HttpClient
- Jetty Client
- RestTemplate
- WebClient
示例:
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
public Order createOrder(Order order) {
// 自动追踪 HTTP 调用
String url = "http://order-service/orders";
return restTemplate.postForObject(url, order, Order.class);
}
}
手动埋点
1. 使用注解
@Trace 注解:
@Service
public class UserService {
@Trace
public User findById(Long id) {
return userRepository.findById(id);
}
@Trace(operationName = "customOperation")
public User create(User user) {
return userRepository.save(user);
}
}
@Tag 注解(添加标签):
@Service
public class UserService {
@Trace
@Tag(key = "userId", value = "arg[0]")
@Tag(key = "result", value = "returnedObj")
public User findById(Long id) {
return userRepository.findById(id);
}
@Trace
@Tag(key = "user", value = "arg[0]")
@Tag(key = "id", value = "returnedObj.id")
public Long create(User user) {
return userRepository.save(user).getId();
}
}
@NewSpan 注解(创建新 Span):
@Service
public class OrderService {
@Trace
public Order createOrder(Order order) {
// 主流程
validateOrder(order);
// 创建新 Span
saveOrder(order);
return order;
}
@NewSpan("validateOrder")
private void validateOrder(Order order) {
// 验证逻辑
}
@NewSpan("saveOrder")
private void saveOrder(Order order) {
// 保存逻辑
}
}
2. 使用 API
基础 API:
@Service
public class UserService {
@Autowired
private Tracer tracer;
public User findById(Long id) {
Span span = Tracer.createSpan("findById");
try {
span.tag("userId", id.toString());
span.log("开始查询用户");
User user = userRepository.findById(id);
span.log("查询完成");
return user;
} catch (Exception e) {
span.errorOccurred();
span.log("查询失败:" + e.getMessage());
throw e;
} finally {
Tracer.stopSpan(span);
}
}
}
异步追踪:
@Service
public class AsyncService {
public CompletableFuture<String> asyncTask() {
Span span = Tracer.createSpan("asyncTask");
try {
return CompletableFuture.supplyAsync(() -> {
try (Scope ignored = Tracer.activateSpan(span)) {
span.log("执行异步任务");
return doWork();
}
});
} finally {
Tracer.stopSpan(span);
}
}
private String doWork() {
// 异步任务逻辑
return "result";
}
}
跨线程追踪:
@Service
public class ThreadService {
public void processInNewThread(Runnable task) {
Span span = Tracer.createSpan("parentTask");
try {
// 捕获当前 Span
Runnable wrappedTask = RunnableManager.wrap(task);
new Thread(wrappedTask).start();
} finally {
Tracer.stopSpan(span);
}
}
}
3. 自定义标签
@Service
public class CustomTagService {
@Trace
@Tags({
@Tag(key = "http.method", value = "arg[1].method"),
@Tag(key = "http.url", value = "arg[1].url"),
@Tag(key = "db.statement", value = "arg[0]"),
@Tag(key = "user.id", value = "returnedObj.id")
})
public Result execute(String sql, Request request) {
// 业务逻辑
return result;
}
}
链路分析
1. 查看追踪详情
在 SkyWalking UI 的”追踪”页面:
- Trace ID:点击 Trace ID 查看详情
- 耗时:查看每个 Span 的耗时
- 拓扑图:查看服务调用拓扑
- 日志:查看 Span 关联的日志
2. 性能分析
慢调用分析:
- 按响应时间排序
- 查看慢调用的详细链路
- 分析瓶颈所在
错误分析:
- 查看错误链路
- 分析错误原因
- 查看错误堆栈
3. 拓扑分析
服务拓扑图:
- 查看服务间调用关系
- 分析依赖是否合理
- 发现循环依赖
实例拓扑图:
- 查看实例间调用关系
- 分析负载均衡情况
- 发现热点实例
性能优化
1. 采样率配置
# 每秒采样数
sample_n_per_3_secs=100
# 或按比例采样
sample_rate=0.1 # 10% 采样率
2. 插件优化
禁用不需要的插件:
# 禁用的插件
agent.exclude_plugins=skywalking-dubbo-plugin,skywalking-grpc-plugin
只启用需要的插件:
# 启用的插件
agent.include_plugins=skywalking-springmvc-plugin,skywalking-mysql-plugin
3. 异步日志
# 异步日志
logging.async=true
logging.queue_size=10000
4. 批量上报
# 批量上报
buffer.buffer_size=30000
buffer.channel_size=5
日志关联
1. 配置 Logback
<!-- logback.xml -->
<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>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
2. 日志输出
2026-04-10 10:00:00.000 [TID: N/A] [main] INFO c.e.controller.UserController - 收到请求
2026-04-10 10:00:00.100 [TID: 123456.0.1] [main] INFO c.e.service.UserService - 查询用户
2026-04-10 10:00:00.200 [TID: 123456.0.1] [main] INFO c.e.repository.UserRepository - 执行 SQL
3. 日志查询
在 SkyWalking UI 的”日志”页面:
- 按 Trace ID 查询:查看链路相关的所有日志
- 按服务查询:查看服务的日志
- 按关键字查询:搜索日志内容
告警配置
1. 告警规则
# alarm-settings.yml
rules:
# 服务响应时间告警
service_resp_time_rule:
metrics-name: service_resp_time
op: ">"
threshold: 1000
period: 10
count: 3
silence-period: 5
message: 服务 {name} 响应时间超过 1000ms
# 服务成功率告警
service_sla_rule:
metrics-name: service_sla
op: "<"
threshold: 80
period: 10
count: 2
silence-period: 5
message: 服务 {name} 成功率低于 80%
# 链路追踪告警
trace_duration_rule:
metrics-name: trace_duration
op: ">"
threshold: 5000
period: 10
count: 5
silence-period: 5
message: 链路 {name} 耗时超过 5000ms
2. 告警通知
# webhook 通知
webhooks:
- http://alert-manager:9093/alert
# 钉钉通知
dingtalk:
webhooks:
- url: https://oapi.dingtalk.com/robot/send?access_token=xxx
secret: xxx
# 企业微信通知
wechat:
webhooks:
- url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx
最佳实践
1. 追踪规范
- 统一命名:Span 名称统一规范
- 关键埋点:关键业务逻辑埋点
- 标签规范:标签 Key 统一规范
- 日志关联:日志与追踪关联
2. 性能优化
- 合理采样:根据流量调整采样率
- 异步处理:减少同步阻塞
- 批量上报:减少网络开销
- 插件优化:禁用不需要的插件
3. 故障排查
- 慢调用分析:优先分析慢调用
- 错误链路:查看错误堆栈
- 关联日志:结合日志分析
- 拓扑分析:分析服务依赖
4. 监控告警
- 关键指标:RT、QPS、成功率
- 告警分级:warning/critical
- 告警降噪:避免告警风暴
- 告警闭环:及时处理告警
常见问题
1. 链路不完整
问题:链路追踪数据不完整
解决方案:
- 检查采样率配置
- 检查异步调用是否正确传递 Span
- 检查插件是否启用
2. 性能影响
问题:接入 Agent 后性能下降
解决方案:
- 降低采样率
- 禁用不需要的插件
- 优化 Agent 配置
3. 日志不关联
问题:日志没有 Trace ID
解决方案:
- 检查 Logback 配置
- 检查是否正确引入 toolkit
- 检查日志输出格式
总结
SkyWalking 链路追踪功能可以追踪请求在分布式系统中的完整调用链路,帮助快速定位性能瓶颈和故障根源。
通过合理的配置和优化,可以在不影响性能的前提下,实现全面的链路追踪和监控。
在生产环境中,建议建立完善的告警机制,并结合日志分析,提高故障排查效率。