
目录一、SkyWalking 到底解决什么问题二、SkyWalking 的整体架构四个核心角色三、Agent 为什么不用改业务代码也能监控四、Trace、Segment、Span1. Trace2. Segment3. Span五、你实际完成的功能复盘1. 服务监控2. 拓扑图3. Trace 链路追踪六、你遇到的两个“慢”必须分清情况一获取连接慢情况二SQL 执行慢七、自定义 Trace 和 Tags这里要注意八、性能剖析 Trace Profiling三个重要指标九、日志上传与 Trace ID 关联十、日志上传涉及的两个功能1. 日志中显示 Trace ID2. 把日志上传到 OAP十一、告警机制十二、你的自动告警完整链路1. 端点告警2. 数据库告警3. 服务实例告警十三、这次踩过的坑1. OAP、UI、Agent 是三回事2. 服务必须带 Agent 启动3. 自定义仪表板重启后消失4. Profiling 端点下拉框不是直接展示所有端点5. WebHook 接收的是 JSON 数组6. Spring ${} 是环境变量占位符7. QQ 邮箱密码必须是授权码8. 收件人地址写错十四、电脑重启后的启动顺序十五、源码暂时没看应该看哪几条主线主线一Java Agent 如何启动主线二一个 Span 如何创建主线三跨服务 Trace 如何串起来十六、面试必须能回答的问题基础链路追踪故障分析日志与告警十七、你目前对 SkyWalking 的真实掌握程度明白这次只复盘SkyWalking。你这一部分其实做得比较完整已经从“接入 Agent”一路做到“邮件告警闭环”只是源码层面还没系统看。一、SkyWalking 到底解决什么问题微服务出现问题时传统日志往往只能看到某一个服务order-service 报错了但实际问题可能发生在用户请求 → order-service → account-service → storage-service → MySQLSkyWalking解决的是一次请求经过了哪些服务、每一步耗时多少、哪里报错、哪条 SQL 慢、对应日志是什么以及是否需要告警。核心能力可以概括为服务监控 链路追踪 性能分析 日志关联 自动告警二、SkyWalking 的整体架构你当前使用的主要组件有四个。Java 应用 │ │ -javaagent ▼ SkyWalking Java Agent │ │ Trace / Metrics / Log ▼ SkyWalking OAP │ ├─ 存储数据 ├─ 聚合指标 ├─ 执行告警规则 └─ 提供查询接口 │ ▼ SkyWalking UI另外还有OAP │ │ WebHook ▼ alarm-service:8084 │ ▼ QQ 邮箱四个核心角色组件作用Agent插入业务 JVM采集链路和指标OAP接收、计算、存储、查询、告警UI展示服务、拓扑、Trace、日志等Storage保存观测数据和部分 UI 配置你当前端口端口作用11800Agent 向 OAP 上报数据12800UI 查询 OAP8080SkyWalking UI8084自己编写的告警接收服务三、Agent 为什么不用改业务代码也能监控你在三个服务的 VM options 中配置了-javaagent:...\skywalking-agent.jar -Dskywalking.agent.service_nameorder-service -Dskywalking.collector.backend_service127.0.0.1:11800JVM 启动时会先调用 Agent 的premain(...)然后 Agent 使用 Java Instrumentation 和字节码增强对常见框架进行拦截例如Tomcat Spring MVC OpenFeign HikariCP JDBC MySQL Driver所以你的业务代码虽然只写了orderMapper.selectById(orderId);SkyWalking 却可以自动生成GET:/order/query/1 └─ queryOrder ├─ HikariCP/Connection/getConnection ├─ Mysql/JDBC/PreparedStatement/execute └─ HikariCP/Connection/close这叫做无侵入式自动埋点。严格来说不是完全零侵入因为 JVM 启动参数中增加了 Agent但业务代码基本不需要改。四、Trace、Segment、Span这是 SkyWalking 最重要的三个概念。1. Trace一次完整的分布式请求。例如POST /order/create从进入订单服务到调用账户服务、库存服务再访问数据库整体属于同一个 Trace。2. Segment一次 Trace 在某个 JVM 服务内部的部分。例如Trace ├─ order-service Segment ├─ account-service Segment └─ storage-service Segment跨服务调用时每个服务会产生自己的 Segment最后通过上下文传播连接起来。3. SpanSegment 中的一次具体操作。例如Tomcat 接收请求 调用 queryOrder 获取数据库连接 执行 SQL 关闭数据库连接每一项都可能是一个 Span。所以结构是Trace └─ Segment └─ Span五、你实际完成的功能复盘1. 服务监控三个服务启动并挂载 Agent 后UI 中出现order-service account-service storage-serviceSkyWalking 可以看到请求量 成功率 响应时间 Apdex 服务实例 端点这里说明 Agent 已经成功注册并上报指标。2. 拓扑图你调用下单接口后看到了类似User ↓ order-service ├─ account-service ├─ storage-service └─ MySQL拓扑图不是手工配置的而是 OAP 根据 Trace 数据推导出来的。也就是说Agent 采集调用关系 → OAP 聚合调用关系 → UI 生成拓扑3. Trace 链路追踪你查看了/order/create和/order/query/1的调用链。其中可以看到Tomcat Spring MVC 业务方法 Feign HikariCP JDBC MySQLTrace 主要回答三个问题请求去了哪里 每一步耗时多少 哪一步出错六、你遇到的两个“慢”必须分清这是这次实验中最有价值的排障点。情况一获取连接慢你曾经看到HikariCP/Connection/getConnection 耗时约 30 秒当时根因不是 SQL而是Xshell SSH 隧道断开 → 127.0.0.1:13306 无法连接远程 MySQL → HikariCP 不断等待连接 → 最后超时因此getConnection 慢代表应用在等数据库连接不一定是 SQL 本身慢。可能原因包括数据库不可达 连接池耗尽 网络异常 数据库连接建立缓慢情况二SQL 执行慢后来调用GET /order/slowSql?time2Trace 显示Mysql/JDBC/PreparedStatement/execute 约 2 秒这才表示数据库已经拿到连接但 SQL 执行本身耗时较长。因此面试中要明确回答HikariCP/getConnection 慢 ≠ PreparedStatement/execute 慢一个是连接阶段一个是执行阶段。七、自定义Trace和Tags自动插件可以追踪 Tomcat、JDBC、Feign 等标准组件但普通业务方法不一定会自动成为独立 Span。因此你给业务方法添加了Trace(operationName queryOrder) public OrderInfo queryOrder(Integer orderId) { return orderMapper.selectById(orderId); }作用是把 queryOrder 方法创建为一个 Local Span又使用Tags({ Tag(key orderId, value arg[0]), Tag(key orderInfo, value returnedObj) })最终 UI 中显示orderId 1 orderInfo OrderInfo(...)这里要注意生产环境不能无脑记录所有参数和返回值。不适合记录密码 Token 手机号 身份证 银行卡 超大 JSON 完整用户隐私否则会造成信息泄露 网络上报量增大 OAP 存储压力增大 Trace 页面过度膨胀八、性能剖析 Trace Profiling普通 Trace 已经能显示某个 Span 耗时 2 秒但它不一定告诉你这个 Span 内部到底卡在哪个 Java 方法性能剖析会在指定端点执行期间周期性采样业务线程调用栈。你创建了Trace-Profiling并对GET:/order/query/1创建性能剖析任务。主要参数包括参数含义监控时长任务运行多久最小耗时阈值请求超过多少才采样Dump 周期多久采样一次线程栈最大采样数最多分析多少条请求三个重要指标指标含义Duration方法及子调用的累计耗时Self Duration当前方法自身耗时Dump Count采样时命中该方法的次数判断热点时重点看Self Duration 高 Dump Count 高性能剖析和普通 Trace 的区别普通 Trace性能剖析看组件和 Span看 Java 方法调用栈定位到 JDBC、Feign 等定位到具体方法持续自动采集针对指定端点临时开启成本较低采样期间有额外开销因此性能剖析不应该长期、全量开启。九、日志上传与 Trace ID 关联你配置了 SkyWalking Logback Toolkit使日志中出现[TID:26345355054a4443...]例如同一次请求[TID:xxx] 查询订单, orderId:1 [TID:xxx] queryOrder, orderId: 1相同的TID说明它们属于同一条 Trace。日志链路是业务线程存在 Trace 上下文 → SkyWalking Toolkit 获取 Trace ID → Logback Pattern 输出 TID → GRPCLogClientAppender 上传日志 → OAP 保存 → UI Log 页面查询这解决了一个重要问题Trace 发现请求慢或报错 → 点击或复制 Trace ID → 定位同一请求的业务日志相比只看本地控制台日志效率高很多。十、日志上传涉及的两个功能这里要区分1. 日志中显示 Trace ID依靠类似%tid或者 SkyWalking 提供的 Logback Layout。作用只是在日志文本中加入 TID2. 把日志上传到 OAP依靠GRPCLogClientAppender作用是通过 gRPC 把日志传到 SkyWalking所以控制台出现 TID不等于SkyWalking UI 一定能查到日志你最后两部分都验证成功了。十一、告警机制SkyWalking 告警并不是某一次请求超过 1 秒 → 立刻报警而是Agent 持续上报指标 → OAP 按分钟聚合 → 告警规则计算时间窗口 → 满足条件 → 生成 AlarmMessage例如你收到的告警大意是最近 10 分钟中有 2 分钟响应时间超过 1000 ms这是一种时间窗口规则。告警规则位于config/alarm-settings.yml十二、你的自动告警完整链路你最终跑通的是PowerShell 持续请求 /order/slowSql ↓ order-service 每次耗时约 2 秒 ↓ Agent 上报 Trace 和响应时间指标 ↓ OAP 聚合端点、服务实例、数据库指标 ↓ alarm-settings.yml 规则命中 ↓ OAP 发送 HTTP WebHook ↓ POST 127.0.0.1:8084/alarm/handler ↓ AlarmController 接收 AlarmMessage 数组 ↓ JavaMailSender 连接 smtp.qq.com ↓ QQ 邮箱收到告警邮件你收到的邮件中包含了三类告警。1. 端点告警GET:/order/slowSql表示具体接口慢。2. 数据库告警127.0.0.1:13306表示访问数据库的响应时间过长。这里的13306是本机 SSH 隧道入口。3. 服务实例告警SERVICE_INSTANCE表示某个具体order-serviceJVM 实例响应过慢。所以 SkyWalking 可以从多个层次报警服务 服务实例 端点 数据库十三、这次踩过的坑1. OAP、UI、Agent 是三回事UI 能打开只说明 8080 正常。不代表Agent 能上报到 11800 OAP 查询接口 12800 正常所以你最后用端口检查11800 12800 8080这是正确的。2. 服务必须带 Agent 启动普通启动java -jar order-service.jar不会自动进入 SkyWalking。必须带-javaagent:skywalking-agent.jar同时设置服务名和 OAP 地址。3. 自定义仪表板重启后消失在你当前默认 H2 配置下重启后自定义Trace-Profiling仪表板没有保留。这说明当前实验环境不适合长期保存数据。生产环境一般会使用Elasticsearch BanyanDB 其他持久化存储而不是依赖本地实验型存储。4. Profiling 端点下拉框不是直接展示所有端点你当时看到只有All需要在输入框中输入query然后远程搜索GET:/order/query/1这是 UI 的远程筛选机制不是端点没采集到。5. WebHook 接收的是 JSON 数组Java Controller 参数是ListAlarmMessage所以请求体必须是[ { name: manual-test } ]而不能是{ name: manual-test }PowerShell 中需要ConvertTo-Json -AsArray6. Spring${}是环境变量占位符你之前写了username: ${具体邮箱} password: ${具体授权码}这是错误的。Spring 会把括号里面的内容当成环境变量名。正确写法是username: ${MAIL_USERNAME} password: ${MAIL_AUTH_CODE}然后在 IDEA 环境变量中设置真实值。或者临时写死username: 具体邮箱 password: 具体授权码但不安全。7. QQ 邮箱密码必须是授权码不能使用QQ 登录密码必须使用QQ 邮箱 SMTP 授权码并配置host: smtp.qq.com port: 465 ssl.enable: true8. 收件人地址写错代码曾写成mail.sendMail(2195188215.com, ...)缺少qq正确是mail.sendMail(2195188215qq.com, ...)这也是为什么 SMTP 认证修好后仍然收不到邮件。十四、电脑重启后的启动顺序你这套实验环境的正确启动顺序是1. Xshell SSH 隧道 2. Nacos 3. Seata 4. SkyWalking OAP UI 5. storage-service 6. account-service 7. order-service 8. alarm-service随后检查$ports 13306, 8848, 9848, 7091, 8091, 11800, 12800, 8080, 8081, 8082, 8083, 8084其中 SkyWalking 关键端口11800 Agent 上报 12800 OAP 查询 8080 UI十五、源码暂时没看应该看哪几条主线你不需要从 SkyWalking 仓库第一行开始看。先看三条核心链路。主线一Java Agent 如何启动-javaagent → premain() → Agent 配置加载 → 插件加载 → 字节码增强重点理解Java Instrumentation ClassFileTransformer ByteBuddy 插件定义 方法拦截器主线二一个 Span 如何创建Tomcat 请求进入 → 插件拦截 → 创建 EntrySpan → 设置操作名和 Tag → 下游调用创建 ExitSpan → Trace 上下文跨服务传播 → Span 上报 OAP重点概念EntrySpan LocalSpan ExitSpan ContextManager TraceSegment主线三跨服务 Trace 如何串起来order-service 发起 Feign → Agent 把 Trace 上下文放入请求头 → account-service 接收请求 → Agent 读取请求头 → 创建新的 Segment → OAP 根据上下文关联两个 Segment这条主线理解后你才算真正掌握 SkyWalking 链路追踪原理。十六、面试必须能回答的问题基础SkyWalking 的 Agent、OAP、UI 分别做什么为什么不改业务代码也能采集 TraceTrace、Segment、Span 有什么区别11800、12800、8080分别做什么SkyWalking 和普通日志系统有什么区别链路追踪跨服务调用时 Trace ID 如何传播EntrySpan、LocalSpan、ExitSpan 有什么区别Feign 调用为什么能显示成独立 Span数据库 SQL 为什么能自动采集Agent 对业务性能有没有影响故障分析如何区分数据库连接慢和 SQL 执行慢Trace 中显示一个接口慢下一步如何定位Trace Profiling 与普通 Trace 有什么区别为什么性能剖析不建议长期全量开启某个服务没有出现在拓扑中如何排查日志与告警Trace ID 如何注入日志控制台有 TID为什么 UI 可能没有日志SkyWalking 告警为什么不是一次慢请求就触发告警规则在哪里配置WebHook 失败是否会影响业务请求十七、你目前对 SkyWalking 的真实掌握程度你现在已经会安装和启动 OAP、UI、Agent 给多个微服务挂载 Agent 检查端口和上报状态 查看服务、端点和拓扑 分析 Trace 区分连接池慢和 SQL 慢 添加 Trace 和 Tags 创建性能剖析任务 查看线程调用栈 上传日志并关联 TID 配置告警规则 配置 WebHook 发送 QQ 邮件告警还没完全掌握的是Agent premain 启动流程 插件加载机制 字节码增强过程 Span 创建过程 Trace 上下文跨服务传播 OAP 内部数据聚合 告警规则执行源码所以你现在属于能够部署、使用和排障 SkyWalking但源码原理还处于待补阶段。下一步最合理的复盘顺序是-javaagent → premain → 插件增强 Tomcat → 创建 EntrySpan → Feign 创建 ExitSpan → 下游恢复上下文 → OAP 拼接完整 Trace这条链看懂以后SkyWalking 的核心原理就基本打通了。