从 0 到 1 精通 SkyWalking:分布式系统的 “透视镜“ 技术全解析

引言:当分布式系统遇见 "盲人摸象" 困境

在单体应用时代,我们排查问题就像在自己家里找东西,虽然偶尔也会找不到,但至少对整个空间了如指掌。而进入分布式系统时代,排查问题更像是在一个陌生的大型商场里找一串丢失的钥匙 ------ 你知道它就在某个地方,但完全不知道从何找起。

想象这样一个场景:用户投诉某个电商平台下单后长时间未收到确认信息。客服反馈给技术团队,前端工程师检查后发现接口调用超时,后端工程师查看服务日志未发现异常,数据库团队确认查询性能正常,运维团队表示服务器资源充足。每个环节看起来都没问题,但整个流程却失败了。这就是分布式系统的 "盲人摸象" 困境 ------ 每个团队只能看到自己负责的部分,无法把握全局。

SkyWalking 正是为解决这一困境而生的分布式追踪系统。它就像给分布式系统装上了 "透视镜" 和 "黑匣子",不仅能看到系统的整体运行状态,还能在出现问题时快速定位根因。本文将从理论到实践,全面解析 SkyWalking 的核心原理、架构设计、实战应用和高级特性,帮助你真正理解并掌握这一强大的分布式追踪工具。

一、SkyWalking 核心概念与价值定位

1.1 什么是 SkyWalking?

SkyWalking 是一个开源的分布式追踪系统,由华为工程师吴晟(现 Apache 基金会董事)发起,目前已成为 Apache 顶级项目。它主要用于微服务、云原生和容器化应用的可观测性分析,提供分布式追踪、服务网格(Service Mesh)遥测分析、度量聚合和可视化一体化解决方案。

简单来说,SkyWalking 能帮助我们回答这些关键问题:

  • 一个请求在分布式系统中经过了哪些服务?
  • 每个服务处理请求花费了多长时间?
  • 哪个服务或组件是系统性能瓶颈?
  • 当请求失败时,具体是在哪个环节出了问题?
  • 系统整体的调用拓扑结构是怎样的?

1.2 SkyWalking 的核心价值

在分布式系统中,SkyWalking 的核心价值体现在三个方面:

  1. 问题定位:快速定位跨服务调用中的异常和性能瓶颈,减少故障排查时间
  2. 性能优化:通过分析调用链和性能指标,发现系统优化点
  3. 系统可视化:将抽象的分布式系统转化为直观的拓扑图和指标图表
  4. 容量规划:基于历史数据和趋势分析,为系统扩容提供决策依据
  5. 服务治理:识别不健康的服务实例,为服务熔断和降级提供数据支持

1.3 可观测性三支柱与 SkyWalking 的定位

现代分布式系统的可观测性(Observability)建立在三个支柱上:

  • 追踪(Tracing):记录请求在分布式系统中的完整路径,关注单个请求的流转
  • 度量(Metrics):对系统状态的数值化描述,关注聚合数据和趋势
  • 日志(Logging):系统产生的离散事件记录,关注具体细节

SkyWalking 以分布式追踪为核心,同时整合了度量和日志功能,形成了一个完整的可观测性平台。与其他工具相比,SkyWalking 的特点是:

  • 探针性能优异,对应用侵入性小
  • 支持多种语言和框架
  • 提供丰富的可视化界面
  • 可扩展性强,支持自定义插件
  • 对 Service Mesh 有良好支持

1.4 SkyWalking 与其他可观测性工具的对比

工具 特点 优势场景 不足
SkyWalking 全栈可观测性,性能优秀,国产开源 微服务、云原生应用 生态相对 Prometheus+Grafana 较小
Zipkin 简单轻量,易于部署 中小规模分布式系统 功能相对简单,可视化较弱
Jaeger CNCF 毕业项目,与 K8s 生态融合好 Kubernetes 环境 对部分旧框架支持不够完善
Pinpoint 字节码增强,无需代码侵入 无法修改代码的场景 插件开发相对复杂
Prometheus+Grafana 度量监控强大,生态丰富 指标监控和告警 追踪功能需要额外集成

二、SkyWalking 核心原理深度解析

2.1 分布式追踪的基础:追踪上下文传播

分布式追踪的核心是如何将跨服务的请求关联起来,形成完整的调用链。SkyWalking 采用了与 OpenTelemetry 兼容的上下文传播机制,主要通过以下几个标识符实现:

  • Trace ID:整个分布式调用链的唯一标识,一个 Trace ID 代表一个完整的请求链路
  • Segment ID:每个服务处理请求时生成的片段 ID,一个 Trace 由多个 Segment 组成
  • Span ID:每个 Segment 中具体操作的标识,代表一个具体的处理单元

当请求从一个服务传递到另一个服务时,这些标识符通过网络协议(如 HTTP 头、RPC 元数据)进行传递,从而将分散在不同服务的处理过程关联起来。

2.2 SkyWalking 的核心工作流程

SkyWalking 的工作流程可以分为四个主要阶段:

  1. 数据采集:通过 Agent 探针对应用进行字节码增强,自动生成追踪数据;同时支持手动埋点补充关键业务信息
  2. 数据传输:Agent 采集的数据通过 gRPC 或 HTTP 协议发送到 SkyWalking 后端(OAP Server)
  3. 数据存储:OAP Server 对数据进行分析和聚合后,存储到指定的存储介质(如 Elasticsearch)
  4. 数据展示:通过 SkyWalking UI 展示系统拓扑、调用链、性能指标等,并提供告警功能

2.3 字节码增强技术:SkyWalking 的 "无侵入" 秘诀

SkyWalking Agent 之所以能实现对应用的无侵入式监控,核心在于其采用了字节码增强技术。简单来说,就是在应用程序的类加载过程中,动态修改字节码,插入监控逻辑,而无需修改应用源代码。

字节码增强的工作流程:

SkyWalking 内置了对主流框架的增强器,如 Spring Boot、Dubbo、MyBatis、HttpClient 等,覆盖了大多数常见的调用场景。对于自定义框架或特殊场景,也可以开发自定义增强器。

2.4 SkyWalking 的数据模型

SkyWalking 定义了一套完整的数据模型来描述分布式系统的运行状态,核心模型包括:

  1. 服务(Service):具有相同功能的一组实例的集合,如订单服务、用户服务
  2. 服务实例(Service Instance):服务的具体运行实例,通常对应一个进程
  3. 端点(Endpoint):服务中可以被调用的具体接口或方法,如 HTTP 接口、RPC 方法
  4. 进程(Process):操作系统层面的进程,一个服务实例对应一个进程
  5. 追踪(Trace):一个请求在分布式系统中的完整调用路径
  6. 片段(Segment):追踪在单个服务实例中的部分
  7. 跨度(Span):片段中的一个具体操作,如一次数据库查询、一次 HTTP 调用

这些模型之间的关系如下:

2.5 OAP Server 的核心功能

SkyWalking OAP(Observability Analysis Platform)服务器是整个系统的核心,负责数据处理、分析和存储,主要功能包括:

  1. 数据接收:接收来自 Agent 和其他数据源的数据
  2. 数据解析:解析不同格式的输入数据
  3. 拓扑分析:根据调用关系自动构建服务拓扑图
  4. 指标计算:聚合计算各种性能指标(响应时间、吞吐量、错误率等)
  5. 数据存储:将处理后的数据存储到指定的存储介质
  6. 查询服务:提供查询接口供 UI 和其他系统使用
  7. 告警管理:根据预设规则判断是否触发告警

OAP Server 采用了模块化设计,不同功能通过插件实现,便于扩展和定制。

三、SkyWalking 环境搭建与基础配置

3.1 环境准备

在开始搭建 SkyWalking 之前,需要准备以下环境:

  • JDK 17+(SkyWalking 9.x 及以上版本推荐)
  • 操作系统:Linux、Windows 或 MacOS
  • 存储介质:推荐使用 Elasticsearch 7.x 或 8.x
  • 网络:确保 Agent、OAP Server 和 UI 之间的网络连通

3.2 搭建 Elasticsearch 存储

SkyWalking 支持多种存储介质,其中 Elasticsearch 是最常用的选择,因为它在处理时序数据和支持复杂查询方面表现优异。

使用 Docker 快速启动 Elasticsearch 8.11.3(最新稳定版):

bash

复制代码
# 拉取镜像
docker pull elasticsearch:8.11.3

# 启动容器
docker run -d \
  --name elasticsearch \
  -p 9200:9200 \
  -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
  elasticsearch:8.11.3

验证 Elasticsearch 是否启动成功:

bash

复制代码
curl http://localhost:9200

成功启动会返回类似以下的响应:

json

复制代码
{
  "name" : "3f1a91f8b6a",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "3zH7x1a5Qv-5L7Z9y8YJ-Q",
  "version" : {
    "number" : "8.11.3",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "64cf052f3b56b10c041973289942cb37b108e6",
    "build_date" : "2023-12-08T11:33:53.634979450Z",
    "build_snapshot" : false,
    "lucene_version" : "9.8.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

3.3 安装 SkyWalking OAP Server

下载并解压 SkyWalking 9.7.0(最新稳定版):

bash

复制代码
# 下载
wget https://archive.apache.org/dist/skywalking/9.7.0/apache-skywalking-apm-9.7.0.tar.gz

# 解压
tar -zxvf apache-skywalking-apm-9.7.0.tar.gz
cd apache-skywalking-apm-bin

配置 OAP Server 使用 Elasticsearch 存储:

编辑config/application.yml文件,修改存储配置:

yaml

复制代码
storage:
  selector: ${SW_STORAGE:elasticsearch}
  elasticsearch:
    namespace: ${SW_NAMESPACE:""}
    clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
    protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:http}
    connectTimeout: ${SW_STORAGE_ES_CONNECT_TIMEOUT:3000}
    socketTimeout: ${SW_STORAGE_ES_SOCKET_TIMEOUT:30000}
    responseTimeout: ${SW_STORAGE_ES_RESPONSE_TIMEOUT:15000}
    numHttpClientThread: ${SW_STORAGE_ES_NUM_HTTP_CLIENT_THREAD:0}
    user: ${SW_ES_USER:""}
    password: ${SW_ES_PASSWORD:""}
    # 其他配置保持默认

启动 OAP Server:

bash

复制代码
# Linux/Mac
bin/oapService.sh

# Windows
bin/oapService.bat

OAP Server 启动成功后,会监听 11800 端口(gRPC)和 12800 端口(HTTP)。

3.4 启动 SkyWalking UI

SkyWalking UI 是一个基于 React 的前端应用,用于可视化展示监控数据。

启动 UI 服务:

bash

复制代码
# Linux/Mac
bin/webappService.sh

# Windows
bin/webappService.bat

默认情况下,UI 会监听 8080 端口,并连接本地的 OAP Server(127.0.0.1:12800)。如果 OAP Server 部署在其他地址,需要修改webapp/application.yml文件:

yaml

复制代码
server:
  port: 8080

spring:
  cloud:
    gateway:
      routes:
        - id: oap-route
          uri: http://localhost:12800  # 修改为实际的OAP Server地址
          predicates:
            - Path=/graphql/**,/ui/**,/api/**,/analysis/**,/logs/**

启动成功后,访问http://localhost:8080即可打开 SkyWalking UI 界面。

3.5 配置 SkyWalking Agent

SkyWalking Agent 是嵌入到应用中的探针,负责收集监控数据。

下载 Agent:

SkyWalking Agent 已经包含在之前下载的安装包中,位于agent目录下。也可以单独下载:

bash

复制代码
wget https://archive.apache.org/dist/skywalking/java-agent/8.16.0/apache-skywalking-java-agent-8.16.0.tgz
tar -zxvf apache-skywalking-java-agent-8.16.0.tgz

Agent 核心配置:

Agent 的主要配置文件是agent/config/agent.config,关键配置项包括:

properties

复制代码
# 应用名称(服务名称)
agent.service_name=${SW_AGENT_NAME:YourApplicationName}

# OAP Server地址
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}

# 采样率,1表示100%采样
agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:-1}

# 日志级别
logging.level=${SW_LOGGING_LEVEL:INFO}

# 插件配置,默认启用所有插件
plugin.mount=${SW_MOUNT_PLUGINS:}

3.6 在 Spring Boot 应用中集成 Agent

创建一个简单的 Spring Boot 应用:

首先,创建一个 Maven 项目,pom.xml配置如下:

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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 http://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.2.0</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>skywalking-demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>17</java.version>
        <lombok.version>1.18.30</lombok.version>
        <springdoc.version>2.1.0</springdoc.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>${springdoc.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

创建一个简单的控制器:

java

复制代码
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Random;

/**
 * 演示控制器
 *
 * @author ken
 */
@Slf4j
@RestController
@RequestMapping("/demo")
@Tag(name = "演示接口", description = "用于SkyWalking演示的接口")
public class DemoController {

    private final RestTemplate restTemplate = new RestTemplate();
    private final Random random = new Random();

    /**
     * 简单的Hello接口
     *
     * @param name 名称
     * @return 问候语
     */
    @GetMapping("/hello/{name}")
    @Operation(summary = "Hello接口", description = "返回简单的问候语")
    public String hello(@PathVariable String name) {
        log.info("收到hello请求,名称:{}", name);
        
        // 模拟处理时间
        try {
            Thread.sleep(random.nextInt(200));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("处理hello请求时发生中断", e);
        }
        
        return "Hello, " + name + "!";
    }

    /**
     * 调用另一个接口的示例
     *
     * @param id ID参数
     * @return 处理结果
     */
    @GetMapping("/call/{id}")
    @Operation(summary = "调用示例", description = "调用另一个接口的示例")
    public String callAnother(@PathVariable Long id) {
        log.info("收到call请求,ID:{}", id);
        
        // 模拟调用另一个服务
        String result = restTemplate.getForObject("http://localhost:8081/demo/process/" + id, String.class);
        
        return "处理结果:" + result;
    }
}

创建应用启动类:

java

复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 应用启动类
 *
 * @author ken
 */
@SpringBootApplication
public class SkywalkingDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SkywalkingDemoApplication.class, args);
    }
}

使用 Agent 启动应用:

bash

复制代码
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \
     -Dskywalking.agent.service_name=demo-service \
     -Dskywalking.collector.backend_service=localhost:11800 \
     -jar target/skywalking-demo-1.0.0.jar

其中:

  • -javaagent:指定 Agent 的路径
  • -Dskywalking.agent.service_name:设置服务名称
  • -Dskywalking.collector.backend_service:设置 OAP Server 地址

启动成功后,访问几次http://localhost:8080/demo/hello/world接口,然后打开 SkyWalking UI(http://localhost:8080),就可以看到服务的监控数据了。

四、SkyWalking 核心功能实战

4.1 服务拓扑图分析

服务拓扑图是 SkyWalking 最直观的功能之一,它能自动根据服务间的调用关系生成可视化的系统架构图。

查看服务拓扑图的步骤:

  1. 登录 SkyWalking UI
  2. 在左侧菜单中选择 "拓扑图"
  3. 选择时间范围(如最近 10 分钟)
  4. 点击 "刷新" 按钮

拓扑图会展示:

  • 所有被监控的服务节点
  • 服务之间的调用关系
  • 调用的吞吐量(每秒请求数)
  • 调用的响应时间
  • 调用的错误率

通过拓扑图,我们可以快速了解:

  • 系统由哪些服务组成
  • 服务之间的依赖关系
  • 哪些服务之间的交互频繁
  • 哪些调用路径存在性能问题(红色表示响应时间长或错误率高)

4.2 分布式调用链追踪

当系统出现问题时,调用链追踪是定位问题的关键工具。SkyWalking 可以展示一个请求从开始到结束的完整路径,包括每个环节的处理时间。

查询调用链的步骤:

  1. 在 SkyWalking UI 左侧菜单中选择 "追踪"
  2. 设置查询条件(如服务名称、时间范围、是否包含错误等)
  3. 点击 "查询" 按钮
  4. 在结果列表中选择一个追踪记录查看详情

调用链详情展示:

  • 每个服务的处理时间
  • 每个 Span 的具体信息(如 HTTP 方法、URL、参数摘要)
  • 异常信息(如果有)
  • 标签信息(如数据库语句、缓存键等)

示例:分析一个慢查询

假设我们发现/demo/call/{id}接口响应缓慢,通过调用链追踪发现:

  1. demo-service调用process-service/demo/process/{id}接口耗时 2.3 秒
  2. process-service中,ProcessService.process()方法耗时 2.2 秒
  3. 进一步查看发现,ProcessService中的数据库查询耗时 2.1 秒

通过这个调用链,我们可以快速定位到性能瓶颈在process-service的数据库查询上,而不是网络传输或其他环节。

4.3 性能指标监控

SkyWalking 提供了丰富的性能指标监控,帮助我们了解系统的运行状态。主要指标包括:

  • 响应时间(Response Time):服务处理请求的时间,包括 P50、P90、P99 等百分位值
  • 吞吐量(Throughput):单位时间内处理的请求数
  • 错误率(Error Rate):错误请求占总请求的比例
  • SLA(Service Level Agreement):服务可用性指标

查看性能指标的步骤:

  1. 在 SkyWalking UI 左侧菜单中选择 "仪表盘"
  2. 选择要查看的服务
  3. 选择时间范围
  4. 查看各项指标图表

通过性能指标,我们可以:

  • 发现服务的性能趋势
  • 比较不同服务的性能表现
  • 识别性能异常(如响应时间突增、错误率上升)
  • 评估系统的整体健康状况

4.4 日志集成与分析

SkyWalking 可以与应用日志集成,将日志与调用链关联起来,方便问题排查。

集成 Logback 日志框架:

  1. 添加 Logback 依赖:

xml

复制代码
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.4.8</version>
</dependency>
  1. 创建src/main/resources/logback-spring.xml配置文件:

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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>
    
    <!-- 输出到SkyWalking OAP的日志追加器 -->
    <appender name="SKYWALKING_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <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" />
        <appender-ref ref="SKYWALKING_LOG" />
    </root>
</configuration>
  1. 添加 SkyWalking 日志工具包依赖:

xml

复制代码
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-logback-1.x</artifactId>
    <version>8.16.0</version>
</dependency>

配置完成后,应用日志中会自动包含TraceID,并且日志会被发送到 SkyWalking OAP Server。在 SkyWalking UI 的 "日志" 菜单中,可以根据TraceID查询与特定调用链相关的所有日志,实现日志与调用链的联动分析。

4.5 告警配置与使用

SkyWalking 支持基于各种指标设置告警规则,当指标超过阈值时会触发告警通知。

配置告警规则:

编辑 OAP Server 的config/alarm-settings.yml文件,添加或修改告警规则:

yaml

复制代码
rules:
  # 服务响应时间告警
  service_resp_time_rule:
    metrics-name: service_resp_time
    op: ">"
    threshold: 1000
    period: 10
    count: 3
    silence-period: 5
    message: "服务 {name} 的响应时间超过1000ms,持续3个周期"
  
  # 服务错误率告警
  service_error_rate_rule:
    metrics-name: service_error_rate
    op: ">"
    threshold: 0.05
    period: 10
    count: 2
    silence-period: 5
    message: "服务 {name} 的错误率超过5%,持续2个周期"
  
  # 端点响应时间告警
  endpoint_resp_time_rule:
    metrics-name: endpoint_resp_time
    op: ">"
    threshold: 500
    period: 10
    count: 3
    silence-period: 5
    message: "端点 {name} 的响应时间超过500ms,持续3个周期"

# 告警通知器配置
notification-settings:
  default:
    # 钉钉通知器
    dingtalk:
      enabled: true
      webhook: https://oapi.dingtalk.com/robot/send?access_token=your_token
      secret: your_secret
      message-type: TEXT
    # 邮件通知器
    email:
      enabled: false
      host: smtp.example.com
      port: 587
      username: alert@example.com
      password: password
      from: alert@example.com
      to: admin@example.com
      subject: "SkyWalking 告警通知"

配置说明:

  • metrics-name:要监控的指标名称
  • op:比较运算符(>、<、>=、<=、==)
  • threshold:阈值
  • period:检查周期(分钟)
  • count:连续多少次超过阈值后触发告警
  • silence-period:告警沉默期,避免重复告警(分钟)
  • message:告警消息内容

修改配置后需要重启 OAP Server 生效。在 SkyWalking UI 的 "告警" 菜单中,可以查看所有触发的告警记录。

五、SkyWalking 高级特性与定制化

5.1 自定义埋点与增强

虽然 SkyWalking 的自动埋点已经覆盖了大部分场景,但在某些情况下,我们需要添加自定义埋点来跟踪特定的业务逻辑。

使用 SkyWalking 工具包进行自定义埋点:

  1. 添加工具包依赖:

xml

复制代码
<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
    <version>8.16.0</version>
</dependency>
  1. 在代码中添加自定义埋点:

java

复制代码
import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.springframework.stereotype.Service;

/**
 * 自定义埋点示例服务
 *
 * @author ken
 */
@Service
public class CustomTraceService {

    /**
     * 使用@Trace注解标记需要追踪的方法
     *
     * @param orderId 订单ID
     * @return 处理结果
     */
    @Trace
    public String processOrder(Long orderId) {
        // 添加自定义标签
        ActiveSpan.tag("orderId", orderId.toString());
        
        try {
            // 模拟业务处理
            validateOrder(orderId);
            calculatePrice(orderId);
            saveOrder(orderId);
            
            // 记录日志,包含TraceID
            log.info("订单处理完成,订单ID:{},TraceID:{}", 
                    orderId, TraceContext.traceId());
            
            return "SUCCESS";
        } catch (Exception e) {
            // 标记Span为错误状态
            ActiveSpan.error(e);
            log.error("订单处理失败,订单ID:{}", orderId, e);
            return "FAIL";
        }
    }
    
    /**
     * 子方法也会被追踪
     */
    @Trace
    private void validateOrder(Long orderId) {
        // 模拟验证逻辑
        ActiveSpan.tag("step", "validate");
    }
    
    /**
     * 子方法也会被追踪
     */
    @Trace
    private void calculatePrice(Long orderId) {
        // 模拟计算价格
        ActiveSpan.tag("step", "calculate");
    }
    
    /**
     * 子方法也会被追踪
     */
    @Trace
    private void saveOrder(Long orderId) {
        // 模拟保存订单
        ActiveSpan.tag("step", "save");
    }
}

@Trace注解会让 SkyWalking 对方法进行追踪,创建相应的 Span。ActiveSpan类可以用来添加标签、记录错误等。通过自定义埋点,我们可以更细致地追踪业务流程,特别是核心业务逻辑的执行情况。

5.2 自定义指标与仪表盘

SkyWalking 允许我们定义自定义指标,并在 UI 中创建自定义仪表盘来展示这些指标。

创建自定义指标:

  1. 首先,在代码中使用 SkyWalking API 记录自定义指标:

java

复制代码
import org.apache.skywalking.apm.toolkit.meter.MeterFactory;
import org.apache.skywalking.apm.toolkit.meter.api.Counter;
import org.apache.skywalking.apm.toolkit.meter.api.Gauge;
import org.apache.skywalking.apm.toolkit.meter.api.Histogram;
import org.springframework.stereotype.Service;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义指标服务
 *
 * @author ken
 */
@Service
public class CustomMetricService {

    // 订单创建计数器
    private final Counter orderCreateCounter = MeterFactory.counter("order.create.count")
            .tag("status", "success")
            .build();
            
    // 订单支付计数器
    private final Counter orderPayCounter = MeterFactory.counter("order.pay.count")
            .tag("status", "success")
            .build();
            
    // 库存 gauge 指标
    private final AtomicInteger inventory = new AtomicInteger(1000);
    private final Gauge inventoryGauge = MeterFactory.gauge("product.inventory", inventory::get)
            .tag("product", "phone")
            .build();
            
    // 订单金额直方图
    private final Histogram orderAmountHistogram = MeterFactory.histogram("order.amount")
            .tag("type", "normal")
            .build();

    /**
     * 记录订单创建
     */
    public void recordOrderCreate() {
        orderCreateCounter.increment();
    }
    
    /**
     * 记录订单支付
     */
    public void recordOrderPay() {
        orderPayCounter.increment();
    }
    
    /**
     * 更新库存
     */
    public void updateInventory(int amount) {
        inventory.addAndGet(amount);
    }
    
    /**
     * 记录订单金额
     */
    public void recordOrderAmount(double amount) {
        orderAmountHistogram.observe(amount);
    }
}
  1. 在业务代码中使用这些指标:

    @Service
    public class OrderService {

    复制代码
     @Autowired
     private CustomMetricService metricService;
     
     public void createOrder(Order order) {
         // 业务逻辑...
         
         // 记录指标
         metricService.recordOrderCreate();
         metricService.recordOrderAmount(order.getAmount());
         metricService.updateInventory(-order.getQuantity());
     }
     
     public void payOrder(Long orderId) {
         // 业务逻辑...
         
         // 记录指标
         metricService.recordOrderPay();
     }

    }

  2. 在 SkyWalking UI 中创建自定义仪表盘:

  • 登录 SkyWalking UI
  • 点击右上角的 "+" 号,选择 "创建仪表盘"
  • 输入仪表盘名称和描述
  • 点击 "添加图表",选择自定义指标
  • 配置图表类型、时间范围等
  • 保存仪表盘

通过自定义指标和仪表盘,我们可以监控业务层面的关键指标,如订单量、支付转化率、库存水平等,实现技术指标与业务指标的统一监控。

5.3 SkyWalking 插件开发

SkyWalking 的插件机制允许我们扩展其功能,支持更多的框架和组件。下面以开发一个简单的插件为例,介绍插件开发的基本流程。

插件开发步骤:

  1. 创建插件项目,pom.xml配置:

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>skywalking-custom-plugin</artifactId>
    <version>1.0.0</version>

    <properties>
        <skywalking.version>8.16.0</skywalking.version>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-agent-core</artifactId>
            <version>${skywalking.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-util</artifactId>
            <version>${skywalking.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- 被增强的目标框架依赖 -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>custom-framework</artifactId>
            <version>1.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  1. 创建增强类:

    import net.bytebuddy.description.method.MethodDescription;
    import net.bytebuddy.matcher.ElementMatcher;
    import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
    import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
    import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
    import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
    import static net.bytebuddy.matcher.ElementMatchers.named;
    import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;

    /**

    • 自定义框架插件定义

    • @author ken
      */
      public class CustomFrameworkPlugin extends ClassInstanceMethodsEnhancePluginDefine {

      /**

      • 定义需要增强的类
        */
        @Override
        protected ClassMatch enhanceClass() {
        // 匹配com.example.framework.CustomService类
        return byName("com.example.framework.CustomService");
        }

      /**

      • 定义构造方法拦截点
        */
        @Override
        public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
        }

      /**

      • 定义实例方法拦截点
        */
        @Override
        public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
        new InstanceMethodsInterceptPoint() {
        @Override
        public ElementMatcher<MethodDescription> getMethodsMatcher() {
        // 匹配execute方法
        return named("execute");
        }

        复制代码
             @Override
             public String getMethodsInterceptor() {
                 // 拦截器类
                 return "com.example.plugin.CustomServiceInterceptor";
             }
        
             @Override
             public boolean isOverrideArgs() {
                 return false;
             }
         }

        };
        }
        }

  2. 创建拦截器类:

    import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
    import org.apache.skywalking.apm.agent.core.context.ContextManager;
    import org.apache.skywalking.apm.agent.core.context.tag.Tags;
    import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
    import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
    import org.apache.skywalking.apm.agent.core.interceptor.enhance.EnhancedInstance;
    import org.apache.skywalking.apm.agent.core.interceptor.enhance.InstanceMethodsAroundInterceptor;
    import org.apache.skywalking.apm.agent.core.interceptor.enhance.MethodInterceptResult;
    import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;

    import java.lang.reflect.Method;

    /**

    • 自定义服务拦截器

    • @author ken
      */
      public class CustomServiceInterceptor implements InstanceMethodsAroundInterceptor {

      @Override
      public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
      Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
      // 创建一个新的Span
      AbstractSpan span = ContextManager.createLocalSpan("CustomService.execute()");

      复制代码
       // 设置组件类型
       span.setComponent(ComponentsDefine.CUSTOM);
       
       // 设置层级为中间件
       SpanLayer.asMiddleware(span);
       
       // 添加标签
       if (allArguments != null && allArguments.length > 0) {
           Tags.ARGS.set(span, String.valueOf(allArguments[0]));
       }

      }

      @Override
      public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
      Class<?>[] argumentsTypes, Object ret) throws Throwable {
      // 结束Span
      ContextManager.stopSpan();
      return ret;
      }

      @Override
      public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
      Class<?>[] argumentsTypes, Throwable t) {
      // 记录异常
      ContextManager.activeSpan().log(t);
      }
      }

  3. 创建插件描述文件:

src/main/resources目录下创建skywalking-plugin.def文件:

复制代码
custom-framework-plugin=com.example.plugin.CustomFrameworkPlugin
  1. 打包插件:

    mvn clean package

  2. 安装插件:

将生成的 jar 包复制到 SkyWalking Agent 的plugins目录下,重启应用即可生效。

通过开发自定义插件,我们可以扩展 SkyWalking 的监控能力,使其支持特定的框架、组件或业务逻辑,满足个性化的监控需求。

5.4 SkyWalking 与 Kubernetes 集成

在云原生环境中,SkyWalking 可以与 Kubernetes 无缝集成,实现对容器化应用的全面监控。

在 Kubernetes 中部署 SkyWalking:

  1. 创建命名空间:

yaml

复制代码
apiVersion: v1
kind: Namespace
metadata:
  name: skywalking
  1. 部署 Elasticsearch:

yaml

复制代码
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: elasticsearch
  namespace: skywalking
spec:
  serviceName: elasticsearch
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: elasticsearch:8.11.3
        ports:
        - containerPort: 9200
          name: rest
          protocol: TCP
        - containerPort: 9300
          name: inter-node
          protocol: TCP
        env:
        - name: discovery.type
          value: single-node
        - name: xpack.security.enabled
          value: "false"
        - name: ES_JAVA_OPTS
          value: -Xms512m -Xmx512m
        resources:
          limits:
            cpu: 1
            memory: 1Gi
          requests:
            cpu: 500m
            memory: 512Mi
        volumeMounts:
        - name: data
          mountPath: /usr/share/elasticsearch/data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
  namespace: skywalking
spec:
  selector:
    app: elasticsearch
  ports:
  - port: 9200
    targetPort: 9200
  clusterIP: None
  1. 部署 SkyWalking OAP Server:

yaml

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: skywalking-oap
  namespace: skywalking
spec:
  replicas: 1
  selector:
    matchLabels:
      app: skywalking-oap
  template:
    metadata:
      labels:
        app: skywalking-oap
    spec:
      containers:
      - name: skywalking-oap
        image: apache/skywalking-oap-server:9.7.0
        ports:
        - containerPort: 11800
          name: grpc
        - containerPort: 12800
          name: rest
        env:
        - name: SW_STORAGE
          value: elasticsearch
        - name: SW_STORAGE_ES_CLUSTER_NODES
          value: elasticsearch:9200
        - name: JAVA_OPTS
          value: -Xms512m -Xmx512m
---
apiVersion: v1
kind: Service
metadata:
  name: skywalking-oap
  namespace: skywalking
spec:
  selector:
    app: skywalking-oap
  ports:
  - port: 11800
    targetPort: 11800
    name: grpc
  - port: 12800
    targetPort: 12800
    name: rest
  1. 部署 SkyWalking UI:

yaml

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: skywalking-ui
  namespace: skywalking
spec:
  replicas: 1
  selector:
    matchLabels:
      app: skywalking-ui
  template:
    metadata:
      labels:
        app: skywalking-ui
    spec:
      containers:
      - name: skywalking-ui
        image: apache/skywalking-ui:9.7.0
        ports:
        - containerPort: 8080
        env:
        - name: SW_OAP_ADDRESS
          value: http://skywalking-oap:12800
---
apiVersion: v1
kind: Service
metadata:
  name: skywalking-ui
  namespace: skywalking
spec:
  selector:
    app: skywalking-ui
  ports:
  - port: 80
    targetPort: 8080
  type: NodePort
  1. 在 Kubernetes 中部署应用时集成 SkyWalking Agent:

yaml

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-service
  template:
    metadata:
      labels:
        app: demo-service
    spec:
      initContainers:
      - name: init-agent
        image: busybox:1.35
        command:
        - sh
        - -c
        - wget -q -O /skywalking/agent.tar.gz https://archive.apache.org/dist/skywalking/java-agent/8.16.0/apache-skywalking-java-agent-8.16.0.tgz && tar -zxf /skywalking/agent.tar.gz -C /skywalking
        volumeMounts:
        - name: skywalking-agent
          mountPath: /skywalking
      containers:
      - name: demo-service
        image: demo-service:1.0.0
        ports:
        - containerPort: 8080
        env:
        - name: JAVA_OPTS
          value: >-
            -javaagent:/skywalking/agent/skywalking-agent.jar
            -Dskywalking.agent.service_name=demo-service
            -Dskywalking.collector.backend_service=skywalking-oap.skywalking:11800
        volumeMounts:
        - name: skywalking-agent
          mountPath: /skywalking
      volumes:
      - name: skywalking-agent
        emptyDir: {}

通过这种方式,我们可以在 Kubernetes 环境中实现 SkyWalking 的完整部署,并对容器化应用进行全面监控。SkyWalking 能够自动识别 Kubernetes 中的服务和实例,提供与容器平台深度集成的监控能力。

六、SkyWalking 性能优化与最佳实践

6.1 Agent 性能优化

SkyWalking Agent 作为嵌入在应用中的组件,其性能对整个系统有直接影响。以下是一些优化 Agent 性能的建议:

  1. 合理设置采样率

    • 高流量系统可以降低采样率(如 1%),减少数据量
    • 关键业务或调试期间可以提高采样率(如 100%)
    • 配置方式:agent.sample_n_per_3_secs=1(每 3 秒采样 1 个请求)
  2. 禁用不必要的插件

    • SkyWalking 默认启用所有插件,对于不需要的插件可以禁用
    • 配置方式:plugin.mount=!mysql,!redis(禁用 mysql 和 redis 插件)
  3. 调整缓存大小

    • 对于高并发系统,可以适当增大 Agent 的缓存
    • 配置方式:agent.buffer_size=30000(设置缓存大小为 30000)
  4. 异步报告数据

    • 确保 Agent 使用异步方式向 OAP Server 报告数据
    • 配置方式:agent.force_tls=false(禁用 TLS,提高传输效率)
  5. 合理设置批量发送参数

    • 调整批量发送的大小和间隔,平衡实时性和性能

    • 配置方式: plaintext

      复制代码
      agent.batch_size=1000
      agent.batch_interval=3000

6.2 OAP Server 性能优化

OAP Server 作为数据处理和分析的核心,其性能优化同样重要:

  1. 集群部署

    • 对于大规模系统,OAP Server 应采用集群部署,分担负载
    • 配置方式:通过cluster配置项设置集群模式(如 zookeeper、kubernetes)
  2. 调整 JVM 参数

    • 根据服务器配置合理分配内存,避免 OOM 或 GC 问题
    • 推荐配置:-Xms4g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
  3. 优化存储配置

    • 使用性能更好的存储介质(如 Elasticsearch 集群)
    • 调整索引生命周期管理,自动清理过期数据
    • 配置方式:在application.yml中设置storage.elasticsearch.indexTTL
  4. 水平扩展

    • 根据数据量和查询压力,增加 OAP Server 实例数量
    • 确保存储层也能相应扩展
  5. 优化线程池配置

    • 根据 CPU 核心数调整处理线程池大小
    • 配置方式:在application.yml中调整core.default.workers

6.3 存储优化

存储是 SkyWalking 性能的关键瓶颈之一,合理的存储优化可以显著提升系统性能:

  1. 选择合适的存储介质

    • 中小规模系统:可以使用 MySQL 或 TiDB
    • 大规模系统:推荐使用 Elasticsearch 集群
    • 超大规模系统:考虑使用专门的时序数据库(如 InfluxDB、TimescaleDB)
  2. Elasticsearch 优化

    • 增加数据节点数量,提高存储和查询性能
    • 合理设置分片和副本数量(推荐分片数 = 数据节点数)
    • 配置索引生命周期管理(ILM),自动删除过期数据
    • 调整刷新间隔(index.refresh_interval),平衡实时性和性能
  3. 数据保留策略

    • 根据业务需求设置不同数据的保留时间

    • 配置方式: yaml

      复制代码
      storage:
        elasticsearch:
          traceDataTTL: 7 # 追踪数据保留7天
          metricsDataTTL: 30 # 指标数据保留30天
          logDataTTL: 15 # 日志数据保留15天
  4. 定期优化

    • 定期执行存储优化操作(如 ES 的 force merge)
    • 监控存储性能指标,及时扩容

6.4 生产环境最佳实践

在生产环境中使用 SkyWalking,建议遵循以下最佳实践:

  1. 分环境部署

    • 开发、测试、生产环境使用独立的 SkyWalking 部署
    • 生产环境配置应更注重性能和稳定性
  2. 渐进式接入

    • 初次接入时,可以先选择非核心服务进行试点
    • 逐步扩大监控范围,观察系统性能影响
  3. 完善的监控告警

    • 不仅监控业务系统,也要监控 SkyWalking 自身
    • 设置关键指标的告警阈值,及时发现问题
  4. 安全配置

    • 生产环境应启用 TLS 加密传输
    • 限制 UI 和 API 的访问权限
    • 敏感数据脱敏处理
  5. 定期备份

    • 定期备份 SkyWalking 的配置和数据
    • 制定灾难恢复计划
  6. 持续优化

    • 定期 review 监控数据,优化系统性能
    • 关注 SkyWalking 新版本,及时升级获取新功能和性能优化
  7. 文档和培训

    • 建立 SkyWalking 使用文档
    • 对开发和运维人员进行培训,提高问题排查效率

七、总结与展望

SkyWalking 作为一款优秀的开源分布式追踪系统,为我们解决分布式系统的可观测性问题提供了全面的解决方案。从核心原理来看,它通过字节码增强技术实现了对应用的无侵入式监控,通过分布式追踪上下文传播将分散的服务调用关联起来,形成完整的调用链。

在功能上,SkyWalking 不仅提供了基础的服务拓扑图和调用链追踪,还整合了性能指标监控、日志分析和告警功能,形成了一个完整的可观测性平台。通过本文的介绍,我们了解了 SkyWalking 的核心概念、工作原理、环境搭建、功能使用以及高级特性。

从实践角度来看,SkyWalking 的优势在于:

  • 对应用的侵入性小,部署和使用简单
  • 性能优秀,对系统的影响小
  • 支持多种语言和框架,兼容性好
  • 提供丰富的可视化界面,易于理解和使用
  • 可扩展性强,支持自定义埋点、指标和插件

掌握 SkyWalking 不仅能帮助我们快速定位分布式系统中的问题,还能让我们更深入地理解系统的运行状态,为系统优化和架构演进提供数据支持。希望本文能成为你学习和使用 SkyWalking 的有益指南,让你在分布式系统的复杂世界中,拥有一双 "透视" 的眼睛。

相关推荐
七夜zippoe3 小时前
Java 生态监控体系实战:Prometheus+Grafana+SkyWalking 整合全指南(三)
java·grafana·prometheus
陈遇巧4 小时前
Spring Framework
java·笔记·spring
我是华为OD~HR~栗栗呀4 小时前
20届-高级开发(华为oD)-Java面经
java·c++·后端·python·华为od·华为
摇滚侠5 小时前
java.lang.RuntimeException: java.lang.OutOfMemoryError
java·开发语言·intellij-idea
sibylyue5 小时前
IDEA cannot resolve method
java·ide·intellij-idea
翻斗花园刘大胆6 小时前
JavaWeb之快递管理系统(完结)
java·开发语言·前端·jvm·spring·servlet·java-ee
熙客7 小时前
SpringCloudStream:消息驱动组件
java·分布式·spring cloud·rabbitmq
西门吹雪@1327 小时前
springboot项目添加请求链路追踪日志traceId
java·spring boot·后端
新知图书8 小时前
JMeter的定时器
java·jvm·jmeter