skywalking 原理
好的,我们来深入解析 Apache SkyWalking 的原理。它的设计非常精巧,核心思想是**通过分布式追踪技术,在复杂的分布式系统中清晰地还原一个请求的完整调用链,并在此之上构建强大的监控能力**。
为了让您更容易理解,我将从以下几个核心部分来阐述其原理:
1. **整体架构与工作流程**
2. **核心概念:什么是 Tracing?**
3. **数据采集与自动探针(Agent)原理**
4. **数据流与存储(OAP)原理**
5. **数据分析与聚合原理**
6. **可视化(UI)原理**
---
### 1. 整体架构与工作流程
SkyWalking 采用经典的**客户端-服务端**架构,如下图所示(精简版):
```
[您的应用] -> [SkyWalking Agent] --(gRPC)--> [SkyWalking OAP Server] --(GraphQL)--> [SkyWalking UI]
|
|--(写入)--> [存储集群] (Elasticsearch, TiDB, H2...)
```
**工作流程简述:**
1. **注入探针**:在您的应用(Java, Go, .NET, PHP 等)中通过 `-javaagent` 或相关方式植入 SkyWalking Agent。
2. **收集数据**:Agent 会**无侵入地**收集应用的性能数据(如调用链、指标、日志)。
3. **上报数据**:Agent 将数据通过 **gRPC**(默认)或 HTTP 协议上报给 SkyWalking OAP (Observability Analysis Platform) 服务器。
4. **流式分析**:OAP 服务器接收到数据后,会进行**实时流式分析**(使用 MAL 等脚本),对数据进行聚合、计算、丰富。
5. **持久化存储**:分析后的数据被持久化到后端的存储中,如 Elasticsearch、MySQL (TiDB)、H2 等。
6. **可视化展示**:用户通过 SkyWalking UI 查询数据,UI 会向 OAP 服务器发送 GraphQL 查询请求,并将结果以图表、拓扑图、列表等形式展示出来。
---
### 2. 核心概念:什么是 Tracing?
要理解 SkyWalking,必须先理解 **Tracing**(追踪)。
* **Trace**:代表一个**完整的请求链路**。例如,用户从浏览器点击一个按钮,这个请求从网关 -> 认证服务 -> 订单服务 -> 支付服务 -> 数据库,这一整条路径就是一个 Trace。
* **Span**:代表一个**工作单元**,是 Trace 中的单个节点。例如,订单服务处理这个请求就是一个 Span。每个 Span 包含:
* `Trace ID`:全局唯一,用于串联整个请求的所有 Span。
* `Span ID`:当前工作单元的唯一标识。
* `Parent Span ID`:父工作单元的 ID,用于构建树形结构。
* `Operation Name`:操作名(如 `GET:/order/{id}`)。
* `Start Time` & `End Time`:时间戳,用于计算耗时。
* `Tags`:键值对,记录上下文信息(如 `http.status_code=200`, `db.instance=mysql`)。
* `Logs`:时间戳事件,用于记录特定时刻的信息(如错误堆栈)。
* **Context Propagation**(上下文传播):这是分布式追踪的魔法所在。当一个服务调用另一个服务时,`Trace ID`、`Parent Span ID` 等信息会通过 **HTTP Headers**(如 `sw8`)或 **RPC 上下文**传递给下游服务,从而将整个调用链串起来。
---
### 3. 数据采集与自动探针(Agent)原理
这是 SkyWalking **无侵入性** 的关键。
* **字节码增强(Byte Buddy)**:SkyWalking Agent 主要通过在**运行时**修改应用程序的字节码来收集数据。它不需要你修改任何业务代码。
* **如何工作**:
1. 当 JVM 启动时,`-javaagent` 参数会优先加载 SkyWalking Agent。
2. Agent 会定义一系列**拦截点**(例如,所有 `HttpClient.execute()` 方法、所有 `@RestController` 类的方法、所有 JDBC 的 `executeQuery` 方法等)。
3. 当你的应用代码执行到这些拦截点时,Agent 会在**方法执行前**和**方法执行后**插入自己的监控代码。
4. 这些插入的代码会负责**创建 Span**、**记录开始时间**、**捕获异常**、**添加标签**,并在方法执行结束时**记录结束时间**,最后将 Span 数据放入缓冲区。
* **性能开销极低**:所有操作都是内存操作,且采用**异步上报**模式(Agent 将数据先放入缓冲区,再由单独线程批量发送给 OAP),因此对应用性能的影响非常小(官方宣称资源开销 < 10%)。
---
### 4. 数据流与存储(OAP)原理
OAP 服务器是大脑,负责处理和存储数据。
* **Receiver**:接收器模块,负责从 Agent 接收不同格式的数据(如 SkyWalking 原生格式、Zipkin、Jaeger、OpenTelemetry 格式)。
* **Parser**:解析器,将接收到的数据解析成内部的流数据模型。
* **Streaming Core**(流式核心):这是最核心的部分。它使用 **MAL (Meter Analysis Language)** 等配置对数据流进行**实时分析**。
* **聚合**:例如,将一秒内的所有“订单服务”的指标数据聚合起来,计算该秒的总请求数、平均耗时、错误数等。
* **计算**:根据原始数据计算出衍生指标,如 Apdex、SLA、P99 延迟等。
* **丰富**:将不同数据流关联起来,例如将 JVM 指标关联到对应的服务实例上。
* **Storage**:存储模块。处理后的数据会被分门别类地保存到存储集群中。
* **时序数据**(指标):存储在 ES 等,用于绘制曲线图。
* **明细数据**(追踪链):存储在 ES 等,用于查询具体某次请求的详情。
* **元数据**(服务、实例列表):通常也存储在 ES 或关系型数据库中。
---
### 5. 数据分析与聚合原理
这是产生强大监控能力的关键。
* **Top N 计算**:OAP 不会存储所有原始数据(那样成本太高),而是按时间窗口(如1分钟)进行预聚合。例如,它会计算出一分钟内:
* 哪个端点(Endpoint)最慢?(Slow Endpoint List)
* 哪个服务错误率最高?
* **指标派生**:
* **Apdex**:根据配置的阈值 T,分析延迟数据分布计算得出。
* **百分位数(P99, P95...)**:使用 **TDigest** 或 **AvgHistogram** 等算法对延迟数据进行流式计算,以高效且近似地得到百分位数值,而不需要保存所有原始数据点。
* **拓扑分析**:通过分析 Trace 数据中的服务间调用关系(`Tags` 和 `Logs` 中的网络地址信息),OAP 可以自动绘制出**服务依赖关系拓扑图**。
---
### 6. 可视化(UI)原理
UI 是最终展示层。
* **GraphQL API**:UI 不直接查询数据库,而是向 OAP 服务器发送 **GraphQL** 查询请求。GraphQL 允许 UI 精确地指定它需要哪些数据,避免了 REST API 的“过度获取”或“获取不足”的问题。
* **查询过程**:当你在 UI 上选择“过去1小时”、“服务A”的“平均响应时间”时:
1. UI 会构建一个对应的 GraphQL 查询。
2. OAP 服务器接收到查询,解析后向存储集群(如 ES)发起请求。
3. 从 ES 获取到聚合好的时序数据后,返回给 UI。
4. UI 使用 ECharts 等图形库将数据渲染成曲线图。
### 总结
SkyWalking 的原理可以概括为:
1. **无侵入采集**:通过**字节码增强技术**在运行时自动埋点,收集追踪和指标数据。
2. **上下文传播**:通过 **HTTP Headers** 传递 `Trace ID`,将分散的服务调用串联成完整的调用链。
3. **流式处理**:服务端对海量数据进行**实时聚合和计算**,生成指标、拓扑、告警等高级信息。
4. **集中存储与查询**:将处理后的结果存入高性能存储,并通过 **GraphQL API** 提供给 UI 进行灵活的可视化展示。
这种设计使得 SkyWalking 既能提供强大的分布式追踪和监控能力,又能保持对应用的低侵入性和低性能影响。