Apache SkyWalking Agent、OAP 与 APM 工具手册
服务明明在运行,拓扑为什么是一张空图
发布后的 Java 服务持续返回 200,SkyWalking UI 也能打开,但 Services 页面没有业务服务;偶尔出现一个服务名,Topology 仍没有边,Trace 页面也搜不到请求。最容易做错的动作是重启 UI。UI 只是查询客户端,真正的数据链是:
业务线程 -> Java Agent -> OAP 接收与分析 -> storage 持久化
-> UI 通过 OAP 查询Agent 插件拦截框架调用并创建 Span;OAP 接收 Trace,聚合服务指标、实例指标、端点指标和拓扑关系,再把记录与指标写入存储;UI 通过 OAP 的 HTTP/GraphQL 查询,不直接读取数据库。空拓扑可能是 Agent 根本没加载、Agent 连错 OAP、插件没识别框架、采样丢弃、上下文传播断裂、OAP 未落库、查询时间窗错误,或压根没有产生跨服务调用。把这几层拆开,故障才不会都被叫作“SkyWalking 没数据”。
SkyWalking 的三个核心实体也要先分清:
Service 是稳定的逻辑服务,例如 checkout-api,不能包含 Pod UID、端口或机器名。Instance 是 Service 的一个运行副本,可以随 Pod 或进程变化,用来比较 JVM、负载和单实例异常。Endpoint 是服务内可聚合的入口或操作,例如 GET:/slow。把完整订单 URL 当 endpoint 会制造高基数。
Topology 不是 CMDB。只有真实 Trace 或遥测建立了调用关系,OAP 才能画出边;没有流量、传播中断或采样后没有关系数据时,空图并不表示服务之间没有依赖。
第一次动手需要 Docker 24+、Compose v2、至少 6 GiB 可用内存、JDK 17、Maven 3.9+,以及空闲的 8080、11800、12800、17912、17913 端口。Docker daemon 要能访问镜像仓库,Java 进程要能访问 OAP 11800。下面固定使用 SkyWalking APM/OAP/UI 10.3.0 与该版本官方依赖线中的 BanyanDB 0.9.0;不能因为 BanyanDB 有更新镜像就单独跨版本替换。Agent 不要求与 OAP 号码完全相同,但必须通过兼容矩阵核对。若看到 gRPC unimplemented,优先怀疑 Agent 使用了 OAP 尚不支持的协议能力。
先把 BanyanDB、OAP 和 UI 跑成一条链
创建 compose.yaml:
name: skywalking-lab
services:
banyandb:
image: apache/skywalking-banyandb:0.9.0
command: standalone
ports:
- "127.0.0.1:17912:17912"
- "127.0.0.1:17913:17913"
volumes:
- banyandb-data:/var/lib/banyandb
healthcheck:
test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 17912"]
interval: 5s
timeout: 3s
retries: 30
oap:
image: apache/skywalking-oap-server:10.3.0
depends_on:
banyandb:
condition: service_healthy
ports:
- "127.0.0.1:11800:11800"
- "127.0.0.1:12800:12800"
- "127.0.0.1:1234:1234"
environment:
SW_STORAGE: banyandb
SW_STORAGE_BANYANDB_TARGETS: banyandb:17912
SW_HEALTH_CHECKER: default
SW_TELEMETRY: prometheus
SW_STORAGE_BANYANDB_RECORDS_TTL_DAYS: "3"
SW_STORAGE_BANYANDB_TRACE_TTL_DAYS: "3"
SW_STORAGE_BANYANDB_LOG_TTL_DAYS: "3"
SW_STORAGE_BANYANDB_METRICS_MINUTE_TTL_DAYS: "7"
SW_STORAGE_BANYANDB_METRICS_HOUR_TTL_DAYS: "15"
SW_STORAGE_BANYANDB_METRICS_DAY_TTL_DAYS: "15"
SW_STORAGE_BANYANDB_METADATA_TTL_DAYS: "15"
JAVA_OPTS: "-Xms1g -Xmx1g"
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:12800/internal/l7check"]
interval: 10s
timeout: 5s
retries: 30
ui:
image: apache/skywalking-ui:10.3.0
depends_on:
oap:
condition: service_healthy
ports:
- "127.0.0.1:8080:8080"
environment:
SW_OAP_ADDRESS: http://oap:12800
volumes:
banyandb-data:docker compose up -d
docker compose ps
curl -fsS http://localhost:12800/internal/l7check
curl -fsS http://localhost:12800/status/config/ttl
curl -fsS http://localhost:8080/ >/dev/nulll7check 返回成功说明 OAP 进程能服务;TTL API 应返回有效的 records/metrics 保留配置;UI 首页返回 200 只证明浏览器入口可用。三者都不证明 Agent 数据已经入库。若 OAP 反复重启,先看 docker compose logs oap banyandb:connection refused banyandb:17912 是存储未就绪或地址错误,API version incompatible 表示 OAP 与 BanyanDB 版本线不匹配,permission denied 则检查数据卷。
这里的配置分成连接与数据组两层:
SW_STORAGE=banyandb 选择 OAP storage provider。SW_STORAGE_BANYANDB_TARGETS 是容器网络内地址,不能写宿主机的 localhost。SW_STORAGE_BANYANDB_TRACE_TTL_DAYS、...RECORDS_TTL_DAYS 与 ...LOG_TTL_DAYS 分别约束 Trace、通用记录和日志所在数据组,不能用一个通用 record TTL 代替。
SW_STORAGE_BANYANDB_METRICS_MINUTE_TTL_DAYS、...METRICS_HOUR_TTL_DAYS、...METRICS_DAY_TTL_DAYS 与 ...METADATA_TTL_DAYS 分别约束不同降采样粒度和元数据。小时、天级 TTL 不应短于对应 segment interval,元数据也不应比依赖它的查询窗口更早消失。
SkyWalking 10.3.0 已把 BanyanDB provider 配置拆到 bydb.yml,因此这里必须使用 SW_STORAGE_BANYANDB_*_TTL_DAYS 数据组变量。BanyanDB 还可以按组配置 shard、replica、segment interval 与 hot/warm/cold 阶段;启用 warm/cold 后,各阶段有自己的 TTL,不能只看 hot 阶段。启动后用 /status/config/ttl 读取最终生效值,并以 10.3.0 的配置词汇表核对字段。
用一个真实 Java 进程验证 Agent
让测试服务产生快、慢、错三种请求
先创建只属于本次实验的临时目录,再在其中创建一个最小 Spring Boot 项目。依赖只需要 Web:
COMPOSE_FILE="$PWD/compose.yaml"
test -f "$COMPOSE_FILE"
LAB_DIR=$(mktemp -d)
cd "$LAB_DIR"
mkdir -p src/main/java/lab<!-- pom.xml -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.3</version>
<relativePath/>
</parent>
<groupId>lab</groupId>
<artifactId>skywalking-demo</artifactId>
<version>1.0.0</version>
<properties><java.version>17</java.version></properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>// src/main/java/lab/DemoApplication.java
package lab;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping("/fast")
String fast() {
return "ok";
}
@GetMapping("/slow")
String slow() throws InterruptedException {
Thread.sleep(1500);
return "slow";
}
@GetMapping("/fail")
String fail() {
throw new IllegalStateException("trace-lab failure");
}
}mvn -q -DskipTests package从SkyWalking 下载页取得与 OAP 兼容的 Java Agent,校验 SHA-512/PGP 后解压到 ./skywalking-agent。Agent 包与 OAP 是两个制品,不要从不明镜像复制 jar。启动时把服务名、实例名和 OAP 地址显式交给进程:
java -javaagent:./skywalking-agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=checkout-api \
-Dskywalking.agent.instance_name=checkout-api-local-1 \
-Dskywalking.collector.backend_service=127.0.0.1:11800 \
-jar target/skywalking-demo-1.0.0.jar \
--server.address=127.0.0.1 --server.port=8081 \
>"$LAB_DIR/app-8081.log" 2>&1 &
APP_PID=$!
until curl -fsS http://localhost:8081/fast >/dev/null; do sleep 1; done另一个终端执行:
curl -fsS http://localhost:8081/fast
curl -fsS http://localhost:8081/slow
curl -i http://localhost:8081/failSpring Boot 服务使用 8081,避免与 UI 的 8080 冲突。几十秒内,UI 的 General Service 应出现 checkout-api,Instance 应出现 checkout-api-local-1,Endpoint 可看到三个路径,Trace 中有慢请求和错误请求。点击一个 Trace,核对入口 Span 名、持续时间、错误状态与异常事件,而不是只确认服务名出现。
Agent 配置读取有优先级,系统属性、环境变量和 agent.config 可能互相覆盖。排障时查看应用启动日志中 SkyWalking Agent 的实际 backend 与 service name,不要只看部署模板。容器中的 127.0.0.1:11800 指向应用容器自己;Compose 中应改为 oap:11800,Kubernetes 中应使用 OAP 的 Service 或平台提供的接入网关。
故意连错 OAP,观察失败是否可解释
先停止 8081 进程,再用不存在的 OAP 端口启动 8082 反例。进程放到后台并保存 PID,才能在请求和日志证据完成后明确关闭:
kill "$APP_PID"
wait "$APP_PID" 2>/dev/null || true
java -javaagent:./skywalking-agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=checkout-api-broken \
-Dskywalking.collector.backend_service=127.0.0.1:11999 \
-jar target/skywalking-demo-1.0.0.jar \
--server.address=127.0.0.1 --server.port=8082 \
>"$LAB_DIR/app-8082-broken.log" 2>&1 &
BROKEN_PID=$!
until curl -fsS http://localhost:8082/fast >/dev/null; do sleep 1; done
curl -fsS http://localhost:8082/fast
grep -E '11999|connect|Connection refused|UNAVAILABLE' \
"$LAB_DIR/app-8082-broken.log" | tail -n 20
kill "$BROKEN_PID"
wait "$BROKEN_PID" 2>/dev/null || true
java -javaagent:./skywalking-agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=checkout-api \
-Dskywalking.agent.instance_name=checkout-api-local-1 \
-Dskywalking.collector.backend_service=127.0.0.1:11800 \
-jar target/skywalking-demo-1.0.0.jar \
--server.address=127.0.0.1 --server.port=8081 \
>"$LAB_DIR/app-8081-recovered.log" 2>&1 &
APP_PID=$!
until curl -fsS http://localhost:8081/fast >/dev/null; do sleep 1; done
curl -fsS http://localhost:8081/slow8082 的 /fast 仍返回业务结果,而 Agent 日志出现连接失败或重试,UI 不应出现这个反例进程的新 Trace。这证明 Agent 异步上报没有把 OAP 故障传播为业务故障。随后关闭 8082,恢复指向 11800 的 8081 进程并重新发出 /slow;UI 出现新的慢 Trace 才说明恢复后的上报链重新工作。不要期待 Agent 一定补发断连期间的所有历史 Span,内存队列有容量上限。此时只有恢复后的 8081 进程仍在运行,后面的存储失败实验可以继续使用它。
再做一次存储失败实验:
docker compose -f "$COMPOSE_FILE" stop banyandb
curl -fsS http://localhost:8081/fast
docker compose -f "$COMPOSE_FILE" logs --since=2m oap
docker compose -f "$COMPOSE_FILE" start banyandb
curl -fsS http://localhost:12800/internal/l7checkOAP 可能仍能接收连接,但日志会出现持久化错误,UI 的近期指标和记录会不完整。恢复后重新产生请求并查询,不能把“Agent 没报错”当作“数据已落库”。
Service、Instance、Endpoint 和拓扑是怎样形成的
Java Agent 在进程启动时加载插件,匹配 Spring MVC、HTTP client、JDBC、MQ 等框架增强点。入口请求创建 Entry Span,调用外部服务创建 Exit Span,下游 Agent 从传播头恢复上下文并创建新的 Entry Span。OAP 按 service/instance/endpoint 维度聚合指标,并从跨进程关系构建拓扑。
因此四种现象分别指向不同证据:
Service 不出现:Agent 未加载、服务名非法、没有请求、11800 不通或协议不兼容。Service 出现但没有 Endpoint/Trace:注册或指标到了,具体插件未生效、Trace 被采样、时间窗错误或 storage 写记录失败。Endpoint 有数据但 Topology 没边:测试只有单服务内部请求,或下游调用未被插件识别。
拓扑出现两个本应相同的服务:service name 随环境、Pod 或版本漂移,或传播格式不一致导致关系拆分。
要验证一条真实拓扑,给 demo 再增加一个通过 RestClient 调用的下游服务,确保两端都装 Agent,然后用同一个 trace ID 对照上游 Exit Span 和下游 Entry Span。线程池、CompletableFuture、响应式链、消息队列和自定义 RPC 是传播最容易断裂的地方;需要相应插件或 Toolkit API,不能靠 OAP 在事后猜父子关系。
Endpoint 命名也直接影响成本。框架插件通常会把 /orders/123 归一为 /orders/{id},但自定义 Span 若把完整 URL、SQL 或用户 ID 放进名称,会制造无限实体。动态值放进受控 tag,并只把确实需要查询的 key 加入 searchableTracesTags;tag key/value 长度和自动补全数量都有后端限制。
采样要同时保留故障证据和指标可信度
SkyWalking 的 Agent 和 OAP 都可能参与采样。Agent 端过早丢弃能节省网络与 OAP 成本,但慢、错结果尚未知;OAP 的 Trace sampling policy 可以按服务、端点和延迟保留记录,forceSampleErrorSegment 可在策略启用时强制保留错误 segment。采样影响 Trace record,不应简单等同于所有指标都按同一比例消失。
验证策略时发送固定数量的 fast、slow、fail 请求,分别记录:
请求总数
Agent 创建/丢弃的 segment
OAP 接收/丢弃的 segment
最终可查询的 fast/slow/error Trace
服务请求量与响应时间指标如果 100 个请求只看到 10 条 Trace,但服务 RPM 与延迟趋势仍合理,说明记录采样和指标聚合的边界符合预期;若错误 Trace 也消失,检查策略优先级和 forceSampleErrorSegment。采样率不是全局常量:低流量关键服务需要最低样本保障,高流量健康入口要限流,慢和错请求优先保留。任何比例都由容量预算与故障诊断目标决定。
用一条能触发的规则验证告警
OAP 从 config/alarm-settings.yml 读取规则。开发环境可以把 service 平均响应时间阈值临时设低:
rules:
service_resp_time_rule:
expression: avg(service_resp_time) > 100
period: 1
silence-period: 1
message: "服务 {name} 最近一分钟平均响应时间超过 100 ms"把文件以只读卷挂到 OAP 对应配置路径并重启,然后连续请求 /slow。expression 是 10.3 的 MQE 表达式,根操作必须是比较或布尔操作,并返回 SINGLE_VALUE;旧版 metrics-name、op、threshold、count 组合已经不属于 10.3 规则语法。预期 Alarm 页面出现 checkout-api 的告警。
停止慢请求并等待窗口滑过后,表达式会回到 false,OAP 将停止为这条规则产生新的告警;已有 Alarm 记录不会因此变成一条“已恢复”事件,10.3 的核心告警 hook 也没有原生 recovery/resolve 通知语义。需要恢复闭环时,应由告警接收端按 ruleName、实体 ID 和时间维护事件状态,再用持续正常的指标或单独恢复规则关闭外部事件,不能把“静默期内没再通知”当作恢复。period 是参与表达式计算的分钟窗口,silence-period 只控制同一告警再次触发的静默周期。阈值 100 ms 只是实验值,生产值应来自 SLO 和基线。规则动态变更会重建窗口状态,发布时要避开关键事故窗口。Webhook secret 放 Secret,告警正文避免拼入敏感 tag;接收端要用稳定字段做幂等,而不是依赖展示文本。
若慢请求明显却无告警,按顺序查:service_resp_time 在同一时间窗是否有值、MQE 是否返回单值、规则名是否以 _rule 结尾、OAP 是否加载了目标文件、服务时区是否一致、告警模块是否启用。不要先调低到零,因为无指标、表达式类型错误与指标未越线是三种故障。
OAP 集群不等于 Agent 自动获得高可用入口
单 OAP 的 receiver、aggregator、query 混合在一个进程里,适合开发和小规模。生产可运行多个 OAP,通过 Kubernetes、ZooKeeper、etcd、Consul 或 Nacos 等 cluster provider 发现彼此,完成跨节点聚合。OAP 的 internalComHost/internalComPort 必须是其他 OAP 可达地址;把 0.0.0.0 当成通告地址会导致成员看得见却互相连不上。
集群模块解决 OAP 节点协作,不给 Agent 提供服务发现。Agent 仍要通过 Kubernetes Service、四层 LB、网关或 SkyWalking Satellite 获得稳定的 11800 入口。Cluster Management明确区分了这两件事。LB 还要考虑 gRPC 长连接:仅增加 OAP 副本不一定均匀分流,滚动升级时要做连接排空和超时控制。
典型生产链分为:
Agent/Probe
-> 内部 LB 或 Satellite
-> OAP Receiver 副本
-> OAP Aggregator/Query 副本
-> BanyanDB 或 Elasticsearch/OpenSearch 集群
-> 认证代理后的 UI中等规模新部署优先评估 BanyanDB,它按 APM 数据模型提供 records、metrics 和分层 TTL;已有成熟搜索平台且需要相关查询时可评估 Elasticsearch/OpenSearch,但要承担索引、分片、heap、模板和升级成本。MySQL/PostgreSQL 更适合采样率较低、规模较小且数据库团队成熟的场景。Backend storage列出了 10.3.0 仍可配置的 provider,最终选择要同时核对 OAP provider、数据库服务版本和迁移工具,不能沿用旧版本中已经移除的存储选项。
容量从 Span 结构而不是 QPS 开始算
两个同为 1000 QPS 的服务,可能有完全不同成本:一个请求只有 3 个 Span,另一个经过网关、RPC、缓存、数据库和 MQ 产生 40 个 Span;后者还可能携带异常栈、日志和高基数 tag。容量基线至少记录:
每秒 segment/span 数
每 segment 平均与 p95 字节
服务、实例、端点基数
可检索 tag 基数
record 与 metrics 每日增长
OAP heap、GC、队列拒绝和持久化耗时
存储写入、查询延迟、压实与磁盘增长OAP 的聚合、持久化批次、查询窗口和 storage bulk 参数会共同消耗 heap。盲目增大 bulk、队列或 gRPC message size 只会把拒绝变成更晚的 OOM。先看 OAP 自身 1234 Prometheus 指标、JVM GC、receiver refused、storage latency,再决定扩 OAP、扩存储、降采样或缩短 TTL。
TTL 也不能只按“保留 7 天”估算。records 包含 Trace、日志、TopN 和告警,metrics 包含 service/instance/endpoint、拓扑与元数据;BanyanDB 的 hot/warm/cold 阶段会把不同粒度放在不同节点。缩短 record TTL 会直接减少事故回溯窗口,缩短 metrics TTL 还会让服务和端点元数据更早消失。先通过有效 TTL API确认配置,再用测试实体等待跨越 TTL 或在隔离环境缩短周期做清理证据。
权限、凭证和敏感数据
11800 接收面只允许应用网段或 Satellite;12800 查询面只允许 UI、自动化和受控用户;BanyanDB/ES 端口只允许 OAP;1234 自监控端口只允许监控系统。UI 必须位于 SSO/OIDC 代理后,OAP 查询 API 不能因为“UI 已登录”就直接暴露公网。接收身份与查询身份分离,存储初始化账号与运行账号分离。
OAP 支持 gRPC TLS 与受信 CA 路径,Agent 证书轮换要验证长连接重连。存储用户名、密码、TLS truststore、Webhook secret、动态配置 token 通过 Secret 注入,不写进 application.yml 或镜像。配置状态接口应掩码 password、token、accessKey、secretKey 等关键字,新增自定义凭证字段时同步扩充掩码列表。
Trace 的 URL、SQL、HTTP header、MQ key、日志和 profile 可能包含个人信息、令牌或业务数据。治理顺序是:
Agent 插件配置中关闭不需要的采集。对动态值做归一或哈希,禁止 Authorization、Cookie、密码和请求正文进入 tag/log。只把经过评审的 tag key 加入可检索集合。
UI 查询和导出按角色授权并留审计。事故分享用 trace ID 和脱敏截图,不导出整批原始数据。
按层诊断空数据、断拓扑和查询异常
Agent 层
先在应用启动日志找 skywalking-agent.jar 加载、插件目录、实际 service name 和 backend。JDK、Spring Boot 或字节码框架升级后,Agent 可能加载但插件增强失败。用 -javaagent 参数位置、兼容矩阵和插件 debug 日志定位;不要因为 JVM 能启动就判定 Agent 正常。
网络与入口层
从应用运行环境而不是宿主机执行 11800 连通测试。容器/Kubernetes 的 localhost、DNS、NetworkPolicy、mTLS、LB idle timeout 和代理对 HTTP/2 的支持都会影响 gRPC。连接建立但长期无数据时观察 LB 后端连接分布与 OAP receiver 指标。
OAP 层
unimplemented 是协议能力不兼容,resource exhausted 常指消息、并发或队列限制,持续 Full GC 与 receiver refused 表示容量不足。OAP 集群还要检查成员列表、通告地址、跨节点聚合和时间同步;成员数正确不代表内部通信正常。
Storage 层
服务元数据出现但 Trace 查不到时,检查 record 持久化、TTL、BanyanDB group/segment 或 ES 索引模板;查询旧数据失败而近期正常时,检查 warm/cold 节点、索引生命周期和时钟。不要直接删除 schema 或索引重建,先快照并确认 OAP 版本对应的初始化/迁移工具。
UI 与查询层
UI 的 OAP 地址应是 UI 容器可达的 http://oap:12800,不是浏览器看到的 localhost。时间范围、时区和服务层级会过滤结果。直接对 OAP 做健康与 GraphQL 查询可以区分 UI 展示问题和后端无数据;查询复杂度限制、超大窗口和高基数条件也可能被拒绝。
升级、迁移与回滚
SkyWalking 升级是 Agent、OAP、UI、storage 和配置五条兼容线,不是替换一个镜像。升级前固定以下矩阵:
JDK/框架 -> Java Agent 与插件
Agent 协议 -> OAP
OAP -> UI
OAP storage provider -> BanyanDB/ES/OpenSearch 版本
旧 schema/TTL/索引 -> 新版初始化与迁移步骤先在影子环境复制配置和脱敏流量,验证 Service、Instance、Endpoint、Topology、Trace、告警、TTL 和 OAP 自监控。随后升级 OAP/UI,再分批升级 Agent;若新 Agent 使用了旧 OAP 不支持的能力,会直接出现 unimplemented。存储迁移前做快照和恢复演练,禁止只验证“新 OAP 能启动”。
回滚要区分二进制回滚与数据回滚。配置或 Agent 有问题,可以把入口切回旧 OAP;若新版已经写入新 schema,旧 OAP 未必还能读取,不能承诺原地降级。最稳妥的方案是新旧 OAP 使用隔离存储,短期双路接收固定样本,完成查询对照后切流;旧环境进入只读保留窗口。卷、索引、BanyanDB namespace 和凭证在窗口结束前都不能删除。
团队把 SkyWalking 当成长期能力
实验结束时先停止仍在运行的 Java 进程,再关闭 Compose。只有确认当前目录中的 Compose 项目名是 skywalking-lab,并且不再需要 BanyanDB 中的合成数据时,才删除卷和临时项目:
kill "$APP_PID" 2>/dev/null || true
wait "$APP_PID" 2>/dev/null || true
test "$(docker compose -f "$COMPOSE_FILE" config --format json | jq -r .name)" = "skywalking-lab"
docker compose -f "$COMPOSE_FILE" down
# 二次确认后才执行;该命令会删除实验 BanyanDB 数据。
test "${DELETE_SKYWALKING_LAB_VOLUMES:-}" = "yes"
docker compose -f "$COMPOSE_FILE" down --volumes
cd /
test -n "$LAB_DIR" && test -f "$LAB_DIR/pom.xml"
rm -r -- "$LAB_DIR"如果机器没有 jq,可用 docker compose config 人工核对顶层 name,不要跳过项目身份检查直接执行 down --volumes。生产回滚只切换 Agent/OAP 入口或恢复经过验证的旧环境,不能删除正在承载历史 Trace 的存储卷。
应用团队维护 service/instance/endpoint 命名、Agent 注入和插件兼容;平台团队维护 OAP、入口、存储、容量、备份恢复和版本矩阵;安全团队维护接收与查询权限、敏感字段和审计;值班团队维护分层排障手册与告警路由。新增 Agent 插件、可检索 tag、告警规则和 TTL 变更都要经过评审,因为它们分别改变应用风险、存储成本、值班噪声和追溯窗口。
每次发布平台基线都运行快、慢、错三类请求,并保存可比较的证据:
Agent 启动日志显示正确版本、插件、service name 和 OAP 地址。Service、Instance、Endpoint、Trace 和 Topology 都由真实请求产生。错 OAP 地址、停存储和无调用关系三条失败路径可稳定复现。
OAP 有稳定 Agent 入口,cluster provider 与内部通告地址独立验证。storage provider、有效 TTL、分片副本和冷热阶段符合容量预算。慢请求能触发告警,恢复、Webhook、去重和静默周期均有证据。
11800、12800、1234 和存储端口按调用方最小开放。Trace、日志和 profile 的敏感字段在采集前后均有治理。Agent/OAP/UI/storage 兼容矩阵、升级顺序和隔离回滚路径已演练。
