一、为什么金融项目首选 SkyWalking 而不是 Zipkin?
我们选型时对比了 SkyWalking 和 Zipkin,最终选 SkyWalking 三个核心原因:
第一,零侵入探针。 金融项目大量老系统,代码改造成本高、风险大。SkyWalking 的 Java Agent 通过字节码插桩自动埋点,我们12个核心服务一周内全部接完,业务代码零改动。Zipkin 需要手动埋点或依赖 OpenTelemetry,接入成本高得多。
第二,多语言统一视图。 我们系统有 Java 主服务、Go 的结算服务、Python 的风控脚本。SkyWalking 一个界面看全链路,Zipkin 各语言各自一套,体验割裂。
第三,内置告警开箱即用。 金融项目对稳定性要求高,SkyWalking 自带告警引擎,配好规则直接对接钉钉/短信。Zipkin 本身没有告警能力,需要自己搭 AlertManager,运维成本翻倍。
| 对比维度 | SkyWalking | Zipkin |
|---|---|---|
| 语言无关性 | 多语言支持(Java/Go/Node/Python),UI 统一 | 主要 Java,其他语言需各语言 SDK |
| 探针方式 | Java Agent 零侵入,字节码插桩自动埋点 | 需手动埋点或 OpenTelemetry 介入 |
| 告警能力 | 内置告警规则引擎,开箱即用 | 依赖 AlertManager 等第三方 |
| UI 功能 | 拓扑图/链路/实例/日志联动,一站式 | 链路为主,其他能力弱 |
二、OAP 和 Java Agent 到底是什么?
OAP 不是消息队列
OAP = Observability Analysis Platform(可观测性分析平台),是 SkyWalking 的核心服务进程,负责:
- 接收 Agent 采集的数据(gRPC/HTTP)
- 聚合计算,生成拓扑图和调用链
- 触发告警规则
- 协调写入存储层(ES/MySQL)
很多人搞混的一个点:OAP 不是 Kafka 或 RabbitMQ。 Kafka/RabbitMQ 是 OAP 集群模式下用于多实例间同步数据的中间件,是可选组件,不是 OAP 本身。
Java Agent 是什么
Java Agent 是 JVM 的外挂插件,通过 -javaagent 参数加载,通过字节码插桩 在业务代码运行过程中动态织入监控逻辑 ,业务代码零改动。
工作原理一句话:用 ByteBuddy 在类加载前/时修改字节码,在方法入口出口自动插入埋点代码。
三个核心职责:
-
字节码插桩 --- 扫描需要监控的类(HTTP、MySQL、Dubbo 等),在方法入口/出口自动插入埋点代码
-
数据采集 --- 采集调用耗时、SQL 内容、异常堆栈、traceId 等
-
数据上报 --- 通过 gRPC 异步推送给 OAP Server
java -javaagent:/opt/skywalking/agent/skywalking-agent.jar
-Dsw.agent.service_name=payment-service
-jar app.jar
一个 -javaagent 参数就搞定了,业务代码一行不用改。
三、SkyWalking 核心架构
┌─────────────────────────────────────────────┐
│ SkyWalking UI │
│ (拓扑图 / 调用链 / 告警 / JVM 监控) │
└──────────────────┬──────────────────────────┘
│ REST / GraphQL
┌──────────────────▼──────────────────────────┐
│ OAP Server │
│ ┌─────────┐ ┌─────────┐ ┌──────────┐ │
│ │ Reciever│ → │Aggregator│ → │ Sender │ │
│ │ (接收) │ │ (聚合) │ │ (存储) │ │
│ └─────────┘ └─────────┘ └──────────┘ │
└──────────────────┬──────────────────────────┘
│ gRPC
┌──────────────────▼──────────────────────────┐
│ Java Agent (Sidecar) │
│ ByteBuddy 字节码插桩 → 自动埋点 │
│ HTTP / Dubbo / MySQL / Redis / MQ │
└─────────────────────────────────────────────┘
│
┌──────────────────▼──────────────────────────┐
│ Storage (Elasticsearch/MySQL) │
└─────────────────────────────────────────────┘
架构分四层:
- Java Agent:字节码插桩,零代码侵入
- OAP Server:数据聚合、拓扑图计算、告警触发
- Storage:链路数据持久化,生产用 ES 支撑日均亿级数据
- UI:调用链详情、拓扑图、告警展示三合一
核心是 Agent 和 OAP 通过 gRPC 异步通信,不阻塞业务线程。
四、Spring Boot 项目接入 SkyWalking 完整步骤
Step 1:下载 Agent
wget https://archive.apache.org/dist/skywalking/9.7.0/apache-skywalking-apm-9.7.0.tar.gz
tar -xzf apache-skywalking-apm-9.7.0.tar.gz -C /opt/skywalking/
Step 2:配置 agent.config(三项关键配置)
# 服务名(显示在 UI 拓扑中)
agent.service_name=${SW_AGENT_NAME:payment-service}
# OAP Server 地址(gRPC 端口)
collector.backend_service=${SW_AGENT_COLLECTOR:192.168.1.100:11800}
# 采样率(高并发控制存储)
agent.sample_n_per_3_secs=10
Step 3:启动时挂载
java -javaagent=/opt/skywalking/agent/skywalking-agent.jar \
-Dsw.agent.service_name=payment-service \
-Dsw.collector.backend_service=192.168.1.100:11800 \
-Dsw.agent.sample_n_per_3_secs=10 \
-jar payment-service.jar
Step 4:Docker 环境接入
ENTRYPOINT ["java","-javaagent","/agent/skywalking-agent.jar",\
"-Dsw.agent.service_name=payment-service",\
"-Dsw.collector.backend_service=oap:11800",\
"-jar","/app/payment-service.jar"]
Step 5:OAP + ES + UI 一键部署
# docker-compose.yml
version: '3.8'
services:
elasticsearch:
image: elasticsearch:7.17.0
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms2g -Xmx2g
ports:
- "9200:9200"
oap:
image: apache/skywalking-oap-server:9.7.0
environment:
SW_STORAGE_ES_CONNECTOR_SERVERADDRESSES: elasticsearch:9200
ports:
- "11800:11800" # gRPC:Agent 数据上传
- "12800:12800" # REST:UI 查询接口
ui:
image: apache/skywalking-ui:9.7.0
environment:
BACKEND_SERVICE: oap:12800
ports:
- "8080:8080"
接入就三步:下载 Agent → 配置服务名和 OAP 地址 → 启动时加 -javaagent 参数。业务代码完全不用改。
五、OAP 高可用:为什么必须做?怎么做?
单实例 OAP 挂了会怎样?
很多人忽视这个,但 OAP 单实例是生产隐患:
| 时间 | 后果 |
|---|---|
| < 30 秒 | Agent 本地缓冲,短暂数据积压 |
| > 30 秒 | 缓冲文件写满,Agent 报 Buffer is full, data will be dropped,链路数据永久丢失 |
| > 5 分钟 | 告警失效,监控盲区 |
OAP 挂了 30 秒就开始丢数据,而链路数据是金融项目排查事故的唯一证据,丢了等于盲测。
为什么用 Nginx 而不是 Spring Cloud Gateway 或 SLB 做负载均衡?
这是被问得最多的追问。
核心原因:SkyWalking Agent 与 OAP 之间走的是 gRPC 协议 。Spring Cloud Gateway 和公有云 SLB 不原生支持 gRPC 原始 TCP 转发,而 Nginx 通过 stream 模块做 TCP 层透明代理,Agent 完全无感知。
| 对比 | Nginx | Spring Cloud Gateway | 公有云 SLB |
|---|---|---|---|
| gRPC 支持 | ngx_stream_proxy 原生支持 |
不支持 | 不支持 |
| Agent 兼容性 | 完全透明 | 需要改造 Agent | 需要改造 Agent |
| 性能 | C 语言,高并发低内存 | JVM 进程,资源占用大 | 云厂商控制 |
完整高可用架构图
Copy
┌──────────────────┐
│ SkyWalking UI │
│ (Port 8080) │
└────────┬─────────┘
│ HTTP/GraphQL
┌─────────────────┴──────────────────┐
│ Nginx (Master + Backup) │
│ upstream oap_http { │
│ server oap-1:12800; │
│ server oap-2:12800; │
│ server oap-3:12800; │
│ } │
│ stream { │
│ upstream oap_grpc { │
│ server oap-1:11800; │
│ server oap-2:11800; │
│ server oap-3:11800; │
│ } │
│ } │
│ keepalived VIP: 11800/12800 │
└─────────────────┬──────────────────┘
│ gRPC / HTTP
┌────────────────────────┼────────────────────────┐
│ │ │
┌───────▼───────┐ ┌───────▼───────┐ ┌───────▼───────┐
│ OAP Server │ │ OAP Server │ │ OAP Server │
│ (Node-1) │ │ (Node-2) │ │ (Node-3) │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
└────────────────────────┼────────────────────────┘
│ Storage Cluster
┌────────▼────────┐
│ Elasticsearch │
│ (3节点集群) │
└─────────────────┘
Agent 端配置:collector.backend_service=VIP:11800(Keepalived 虚拟IP)
Agent 端多地址故障转移:
Copy
# 方式一:Nginx VIP(推荐,透明)
collector.backend_service=192.168.1.200:11800
# 方式二:直连多个 OAP
collector.backend_service=oap-1:11800,oap-2:11800,oap-3:11800
六、真实生产案例
案例 1:MySQL 慢查询定位
场景: 账务服务响应时间从 200ms 飙到 2s,对账延迟告警。
排查过程:
- SkyWalking Trace 列表按耗时排序
- 找到一笔 2100ms 的账务调用,点进详情
- 调用链:
/account/debit→MySQL: UPDATE account ... WHERE user_id = ? [1980ms] - 根因:历史数据迁移后
ANALYZE TABLE统计信息过期,MySQL 选错执行计划,全表扫描 - 解决:
ANALYZE TABLE account;+ 加组合索引(user_id + status)
效果: 没有 SkyWalking 之前要登录多台机器 grep 日志拼 traceId,半天打底。有了 SkyWalking,5分钟定位到是哪台 MySQL、哪条 SQL。分析表后恢复到 50ms。
案例 2:跨服务调用链追踪
场景: 支付成功率骤降,支付→账务→银行网关三方调用定位。
SkyWalking 调用链:
总耗时:1.8s
payment-service: /pay 1.8s
└── account-service: debit 1.5s
└── bank-gateway: POST 1.2s ← 银行接口超时
└── MySQL: INSERT 80ms
结论: 银行网关抖动,账务服务无责,触发熔断降级。
那次支付成功率从 99.5% 掉到 95%,打开 SkyWalking 拓扑图,5 分钟看到是银行网关超时。立刻触发熔断返回"银行维护中",同时告警通知银行接口负责人。如果靠日志排查,估计要查 2 小时。
案例 3:自定义告警 + WebHook 钉钉
alarm-settings.yml:
rules:
- name: endpoint_resp_time
metrics-name: endpoint_resp_time
threshold: 3000
op: ">"
duration: 1
count: 2
message: "服务 {name} 接口 {operation} 响应时间超过 3 秒"
- name: error_rate
metrics-name: service_error_rate
threshold: 0.05
op: ">"
duration: 1
count: 3
message: "服务 {name} 错误率超过 5%"
- name: mysql_slow
metrics-name: database_access_resp_time
data-name: mysql
threshold: 1000
op: ">"
duration: 1
count: 2
message: "MySQL {data-name} 执行超过 1 秒"
webhooks:
- http://alert-gateway:8080/alert/callback
告警回调(Spring Boot):
@RestController
@RequestMapping("/alert")
public class AlertController {
@PostMapping("/callback")
public void onAlert(@RequestBody AlertDTO alert) {
for (Alarm alarm : alert.getAlarmList()) {
if (alarm.getScope() == AlarmLevel.CRITICAL) {
// 严重告警:电话 + 短信双通道(金融合规要求)
phoneService.callOnDuty();
smsService.sendCritical(alarm.getMessage());
} else {
// 普通告警:钉钉机器人
dingTalkClient.send(webHookUrl, buildMsg(alarm));
}
}
}
}
案例 4:OAP 高可用故障切换
背景: 3 个 OAP 实例 + Nginx + Keepalived VIP,19 个微服务接入,日均 1.2 亿链路数据。
故障过程:
00:05 OAP-2 OOM,进程退出
00:05 Nginx 检测到 oap-2:11800 连接失败,自动转发到 oap-1/oap-3
00:05 Agent 侧无感知,数据正常上报
00:30 运维完成 OAP-2 重启,少量数据积压
01:00 全部恢复正常,ES 数据完整
关键指标:
| 指标 | 数据 |
|---|---|
| OAP 故障到恢复 | < 5 分钟 |
| 链路数据丢失 | < 0.01% |
| 业务影响 | 零影响 |
七、性能影响与采样控制
面试时一定要能回答这个问题:Agent 对业务性能影响有多大?怎么控制?
Agent 本身对业务性能损耗 <3%,主要来自字节码插桩和数据发送。生产通过三件事控制开销:
第一,采样控制。 高并发服务设 agent.sample_n_per_3_secs=10,每秒只完整追踪 3-4 个请求,其余只记录基础指标,省 70% 存储。
第二,异步发送。 Agent 数据先放内存缓冲,异步推给 OAP,不阻塞业务线程。
第三,接入前压测验证。 JMeter 对比有无 Agent 的 TP99,差值 <3% 才上生产。