上一篇【第16篇】SkyWalking UI使用手册:学会阅读指挥中心的作战地图
下一篇【第18篇】用SkyWalking观察微服务的各个维度:从宏观到微观的侦察术
前16篇我们学会了SkyWalking的所有理论——基因改造针、指挥中心、档案馆、作战地图。但理论再好,不上战场都是纸上谈兵。
今天我们要打造一个真实的微服务沙场——用Spring Cloud搭建5个微服务,配上SkyWalking的完整监控链路,让所有理论在实践中运转起来。
1. 实战集群架构设计
1.1 微服务架构
我们模拟一个电商系统,包含5个核心服务:
┌──────────────────────────────────────────────────────────────────┐ │ 实战环境 - 电商微服务架构 │ │ │ │ ┌─────── User ────────┐ │ │ │ user-gateway │ ← Spring Cloud Gateway (网关) │ │ │ 端口: 8080 │ │ │ └─────────────────────┘ │ │ │ │ │ │ 路由分发 │ │ ▼ │ │ ┌──── user-service ────┐ ← 用户服务 │ │ │ 端口: 8081 │ │ │ │ 功能: 注册/登录/查询 │ │ │ └──────────────────────┘ │ │ │ │ │ ├──→ ┌─── order-service ──┐ ← 订单服务 │ │ │ │ 端口: 8082 │ │ │ │ │ 功能: 下单/查询 │ │ │ │ └────────────────────┘ │ │ │ │ │ │ │ ├──→ ┌── payment-service ──┐ ← 支付服务 │ │ │ │ │ 端口: 8083 │ │ │ │ │ │ 功能: 支付/退款 │ │ │ │ │ └─────────────────────┘ │ │ │ │ │ │ │ └──→ ┌── inventory-service ──┐ ← 库存服务 │ │ │ │ 端口: 8084 │ │ │ │ │ 功能: 库存查询/扣减 │ │ │ │ └────────────────────────┘ │ │ │ │ ┌─── 基础设施 ────────────────────────────────────────┐ │ │ │ Nacos: 服务注册与发现 (8848) │ │ │ │ MySQL: 业务数据库 (3306) │ │ │ │ Redis: 缓存 (6379) │ │ │ │ RocketMQ: 消息队列 (9876) │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ ┌─── SkyWalking ──────────────────────────────────────┐ │ │ │ OAP Server: 数据分析 (11800/12800) │ │ │ │ ES: 数据存储 (9200) │ │ │ │ UI: 可视化 (8080-sw) │ │ │ └──────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────┘1.2 调用链路设计
一个下单请求的典型链路:
用户下单请求的完整链路: user-gateway (路由) → user-service (验证用户身份) → order-service (创建订单) → inventory-service (扣减库存) → payment-service (发起支付) → MySQL (写入支付记录) → RocketMQ (发送订单通知)1.3 技术选型
| 组件 | 技术 | 版本 |
|---|---|---|
| 网关 | Spring Cloud Gateway | 3.1.x |
| 服务框架 | Spring Boot | 2.7.x |
| 注册中心 | Nacos | 2.2.x |
| 数据库 | MySQL | 8.0 |
| 缓存 | Redis | 7.x |
| 消息队列 | RocketMQ | 5.x |
| 监控 | SkyWalking | 9.3.0 |
| 存储 | Elasticsearch | 8.12 |
2. 各服务的Agent配置
2.1 服务名规划
服务名是Agent最重要的配置——它决定了应用在SkyWalking中的身份标识。规划原则:
┌──────────────────────────────────────────────────────────────────┐ │ 服务名规划原则 │ │ │ │ 1. 使用业务语义名,不使用技术名 │ │ 好的: user-service, order-center │ │ 差的: springboot-app1, svc-8082 │ │ │ │ 2. 同一服务的多个实例用相同名字 │ │ 实例1: user-service │ │ 实例2: user-service (相同名字,SkyWalking自动区分实例) │ │ │ │ 3. 不同层次用不同命名风格 │ │ 网关层: xxx-gateway │ │ 业务层: xxx-service │ │ 基础层: xxx-center │ │ │ │ 4. 避免特殊字符和空格 │ │ user-service ✓ │ │ User Service × │ │ user.service × │ └──────────────────────────────────────────────────────────────────┘我们的服务名规划:
| 服务 | Agent服务名 | 端口 |
|---|---|---|
| user-gateway | ecommerce-gateway | 8080 |
| user-service | user-service | 8081 |
| order-service | order-service | 8082 |
| payment-service | payment-service | 8083 |
| inventory-service | inventory-service | 8084 |
2.2 各服务Agent配置
每个服务的Agent配置核心参数:
# ==================== user-gateway ==================== agent.service_name=ecommerce-gateway collector.backend_service=skywalking-oap:11800 agent.sample_n_per_3_secs=-1 logging.level=WARN # ==================== user-service ==================== agent.service_name=user-service collector.backend_service=skywalking-oap:11800 agent.sample_n_per_3_secs=-1 logging.level=WARN # ==================== order-service ==================== agent.service_name=order-service collector.backend_service=skywalking-oap:11800 agent.sample_n_per_3_secs=-1 logging.level=WARN # ==================== payment-service ==================== agent.service_name=payment-service collector.backend_service=skywalking-oap:11800 agent.sample_n_per_3_secs=-1 logging.level=WARN # ==================== inventory-service ==================== agent.service_name=inventory-service collector.backend_service=skywalking-oap:11800 agent.sample_n_per_3_secs=-1 logging.level=WARN2.3 网关服务的特殊处理
Spring Cloud Gateway是基于WebFlux的响应式框架,需要额外激活Gateway插件:
# 激活Gateway插件mvoptional-plugins/apm-spring-cloud-gateway-2.x-plugin.jar plugins/# 同时需要激活WebFlux插件(如果Gateway使用WebFlux)mvoptional-plugins/apm-spring-webflux-5.x-plugin.jar plugins/2.4 Agent配置的统一管理
在Docker Compose环境中,使用共享Agent卷 + 环境变量覆盖:
# docker-compose.yml - Agent配置services:user-service:image:ecommerce/user-service:latestenvironment:-SW_AGENT_NAME=user-service-SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800-SW_LOGGING_LEVEL=WARNvolumes:-skywalking-agent:/skywalking-agent:rocommand:>java -javaagent:/skywalking-agent/skywalking-agent.jar -jar /app/user-service.jar3. Kubernetes部署时Agent挂载方式
3.1 为什么K8s需要特殊处理
在Docker Compose中,我们可以直接把Agent目录挂载进去。但在K8s中,应用镜像通常不包含Agent——需要一种优雅的方式把Agent注入容器。
3.2 initContainer方式(推荐)
initContainer是K8s的标准机制——在主容器启动前,先运行一个初始化容器,把Agent文件复制到共享卷中:
┌──────────────────────────────────────────────────────────────────┐ │ K8s initContainer Agent挂载流程 │ │ │ │ Pod启动顺序: │ │ │ │ 1. initContainer运行 │ │ ┌───────────────────────────────────────────┐ │ │ │ skywalking-agent-init │ │ │ │ - 从Agent镜像复制文件到共享卷 │ │ │ │ - cp -r /skywalking-agent /agent-volume │ │ │ │ - 容器退出 │ │ │ └───────────────────────────────────────────┘ │ │ │ │ │ │ 文件已复制到共享卷 │ │ ▼ │ │ 2. 主容器运行 │ │ ┌───────────────────────────────────────────┐ │ │ │ user-service │ │ │ │ - 挂载共享卷到/skywalking-agent │ │ │ │ - -javaagent:/skywalking-agent/agent.jar │ │ │ │ - 应用启动 │ │ │ └───────────────────────────────────────────┘ │ │ │ │ 共享卷 (emptyDir): │ │ initContainer写入 → 主容器读取 → Agent文件在两个容器间共享 │ └──────────────────────────────────────────────────────────────────┘3.3 完整K8s Deployment示例
# Kubernetes Deployment - user-service with SkyWalking AgentapiVersion:apps/v1kind:Deploymentmetadata:name:user-servicelabels:app:user-servicespec:replicas:2selector:matchLabels:app:user-servicetemplate:metadata:labels:app:user-servicespec:# initContainer: 复制Agent文件initContainers:-name:skywalking-agent-initimage:apache/skywalking-java-agent:9.3.0-jdk11command:["sh","-c","cp -r /skywalking-agent /agent"]volumeMounts:-name:agent-volumemountPath:/agent# 主容器: 运行应用containers:-name:user-serviceimage:ecommerce/user-service:latestenv:-name:SW_AGENT_NAMEvalue:"user-service"-name:SW_AGENT_COLLECTOR_BACKEND_SERVICESvalue:"skywalking-oap:11800"-name:SW_LOGGING_LEVELvalue:"WARN"volumeMounts:-name:agent-volumemountPath:/skywalking-agentcommand:-java--javaagent:/skywalking-agent/skywalking-agent.jar--jar-/app/user-service.jarports:-containerPort:8081# 共享卷volumes:-name:agent-volumeemptyDir:{}3.4 ConfigMap管理公共配置
# SkyWalking公共配置 ConfigMapapiVersion:v1kind:ConfigMapmetadata:name:skywalking-agent-configdata:SW_AGENT_COLLECTOR_BACKEND_SERVICES:"skywalking-oap:11800"SW_LOGGING_LEVEL:"WARN"SW_AGENT_SAMPLE_N_PER_3_SECS:"-1"所有服务都可以引用这个ConfigMap:
# Deployment中引用ConfigMapenvFrom:-configMapRef:name:skywalking-agent-configenv:-name:SW_AGENT_NAMEvalue:"user-service"# 每个服务单独设置3.5 Sidecar方式(备选)
除了initContainer,还可以用Sidecar方式挂载Agent——一个Pod中运行两个容器:
# Sidecar方式(不推荐,资源浪费)spec:containers:-name:user-serviceimage:ecommerce/user-service:latestcommand:["java","-javaagent:/shared/skywalking-agent.jar","-jar","app.jar"]volumeMounts:-name:sharedmountPath:/shared-name:skywalking-agent-sidecarimage:apache/skywalking-java-agent:9.3.0-jdk11# Sidecar容器只提供Agent文件volumeMounts:-name:sharedmountPath:/sharedvolumes:-name:sharedemptyDir:{}Sidecar方式的问题是——Sidecar容器会一直运行,浪费资源。initContainer方式只在启动时运行一次,更高效。
4. Docker Compose完整实战环境
4.1 完整docker-compose.yml
# docker-compose.yml - 完整实战环境version:'3.8'services:# ==================== 基础设施 ====================# Nacos注册中心nacos:image:nacos/nacos-server:v2.2.3environment:MODE:standaloneports:-"8848:8848"# MySQL数据库mysql:image:mysql:8.0environment:MYSQL_ROOT_PASSWORD:root123MYSQL_DATABASE:ecommerceports:-"3306:3306"volumes:-mysql-data:/var/lib/mysql# Redis缓存redis:image:redis:7-alpineports:-"6379:6379"# Elasticsearchelasticsearch:image:elasticsearch:8.12.0environment:-discovery.type=single-node-"ES_JAVA_OPTS=-Xms1g -Xmx1g"-xpack.security.enabled=falseports:-"9200:9200"volumes:-es-data:/usr/share/elasticsearch/data# ==================== SkyWalking ====================# OAP Serverskywalking-oap:image:apache/skywalking-oap-server:9.3.0environment:-SW_STORAGE=elasticsearch-SW_CLUSTER_NODES=elasticsearch:9200-SW_CORE_RECORD_DATA_TTL=3-SW_CORE_OTHER_METRICS_DATA_TTL=7depends_on:-elasticsearchports:-"11800:11800"-"12800:12800"# SkyWalking UIskywalking-ui:image:apache/skywalking-ui:9.3.0environment:-SW_OAP_ADDRESS=skywalking-oap:12800depends_on:-skywalking-oapports:-"9090:8080"# ==================== 业务服务 ====================# 用户网关user-gateway:build:context:./user-gatewaydockerfile:Dockerfileenvironment:-SW_AGENT_NAME=ecommerce-gateway-SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800-SW_LOGGING_LEVEL=WARN-NACOS_ADDR=nacos:8848depends_on:-nacos-skywalking-oapports:-"8080:8080"# 用户服务user-service:build:context:./user-servicedockerfile:Dockerfileenvironment:-SW_AGENT_NAME=user-service-SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800-SW_LOGGING_LEVEL=WARN-NACOS_ADDR=nacos:8848-MYSQL_HOST=mysql-REDIS_HOST=redisdepends_on:-nacos-mysql-redis-skywalking-oapports:-"8081:8081"# 订单服务order-service:build:context:./order-servicedockerfile:Dockerfileenvironment:-SW_AGENT_NAME=order-service-SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800-SW_LOGGING_LEVEL=WARN-NACOS_ADDR=nacos:8848-MYSQL_HOST=mysqldepends_on:-nacos-mysql-skywalking-oapports:-"8082:8082"# 支付服务payment-service:build:context:./payment-servicedockerfile:Dockerfileenvironment:-SW_AGENT_NAME=payment-service-SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800-SW_LOGGING_LEVEL=WARN-NACOS_ADDR=nacos:8848-MYSQL_HOST=mysqldepends_on:-nacos-mysql-skywalking-oapports:-"8083:8083"# 库存服务inventory-service:build:context:./inventory-servicedockerfile:Dockerfileenvironment:-SW_AGENT_NAME=inventory-service-SW_AGENT_COLLECTOR_BACKEND_SERVICES=skywalking-oap:11800-SW_LOGGING_LEVEL=WARN-NACOS_ADDR=nacos:8848-MYSQL_HOST=mysql-REDIS_HOST=redisdepends_on:-nacos-mysql-redis-skywalking-oapports:-"8084:8084"volumes:mysql-data:es-data:4.2 业务服务的Dockerfile模板
每个服务的Dockerfile需要包含Agent挂载:
# user-service/Dockerfile FROM openjdk:11-jre-slim # 复制应用jar包 COPY target/user-service.jar /app/user-service.jar # 复制SkyWalking Agent COPY skywalking-agent /skywalking-agent # 激活Gateway插件(如果需要) # RUN mv /skywalking-agent/optional-plugins/apm-xxx-plugin.jar /skywalking-agent/plugins/ ENTRYPOINT ["java", \ "-javaagent:/skywalking-agent/skywalking-agent.jar", \ "-jar", "/app/user-service.jar"]5. 验证追踪数据正常上报
5.1 启动环境
# 启动所有服务docker-composeup-d# 查看服务状态docker-composeps# 查看OAP日志docker-composelogs skywalking-oap|tail-20# 查看Agent日志docker-composelogs user-service|grep"skywalking"5.2 验证步骤
┌──────────────────────────────────────────────────────────────────┐ │ 追踪数据验证流程 │ │ │ │ 步骤一:验证OAP正常启动 │ │ └──→ curl http://localhost:12800/api/status │ │ └──→ 返回200表示OAP正常 │ │ │ │ 步骤二:验证UI可访问 │ │ └──→ 打开 http://localhost:9090 │ │ └──→ 能看到Dashboard表示UI正常 │ │ │ │ 步骤三:发送测试请求 │ │ └──→ curl http://localhost:8080/api/users/1 │ │ └──→ curl http://localhost:8080/api/orders/create │ │ └──→ 多发几个请求,确保有足够数据 │ │ │ │ 步骤四:查看UI中的拓扑图 │ │ └──→ 打开UI → General → Service │ │ └──→ 拓扑图应显示5个服务节点和它们的调用关系 │ │ │ │ 步骤五:查看Trace数据 │ │ └──→ 打开UI → Trace │ │ └──→ 应能看到刚才发送的请求的Trace │ │ └──→ Trace中应包含多个Span(网关→用户→订单→库存→支付) │ │ │ │ 步骤六:查看Agent日志 │ │ └──→ docker-compose logs user-service │ │ └──→ 日志中应包含TraceID信息 │ │ └──→ 格式: TID:xxx PROC:xxx │ └──────────────────────────────────────────────────────────────────┘5.3 常见问题排查
| 问题 | 检查方法 | 常见原因 |
|---|---|---|
| UI看不到服务 | 检查OAP日志 | Agent没连上OAP(检查backend_service地址) |
| 拓扑图不显示链路 | 检查调用是否经过 | 服务之间没有互相调用 |
| Trace不完整 | 检查Agent插件 | 缺少必要的插件(如Gateway插件) |
| 数据延迟显示 | 检查OAP聚合周期 | 聚合周期是500ms,数据不会立即出现 |
| 只有部分Span | 检查采样率 | 采样率过低导致部分请求未被追踪 |
5.4 应用日志中的TraceID
如果Agent正常工作,应用日志中会自动输出TraceID:
# 查看user-service日志中的TraceIDdocker-composelogs user-service|grep"TID"# 日志格式示例:# 2026-07-02 14:30:00 INFO [TID:a3b2c1d4e5] UserService.getUser - userId=123# 2026-07-02 14:30:00 INFO [TID:a3b2c1d4e5] UserService.queryDB - SQL=SELECT...在Spring Boot中,需要添加logback的TraceID输出格式:
<!-- logback-spring.xml --><configuration><appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- %tid输出TraceID --><pattern>%d{yyyy-MM-dd HH:mm:ss} [%tid] %-5level %logger - %msg%n</pattern></encoder></appender><rootlevel="INFO"><appender-refref="CONSOLE"/></root></configuration>6. 小结
实战环境搭建是把理论变成实践的关键一步:
- 集群架构:5个微服务 + 基础设施 + SkyWalking全链路
- 服务名规划:业务语义命名,同服务多实例同名
- Agent配置:环境变量覆盖方式,统一管理
- K8s挂载:initContainer方式是标准做法,比Sidecar更高效
- Docker Compose:完整的本地实战环境
- 数据验证:OAP状态 → UI访问 → 发请求 → 看拓扑 → 看Trace → 看日志
下一篇文章,我们将用这个实战环境来观察微服务的各个维度——从告警出发,一步步定位问题。
上一篇【第16篇】SkyWalking UI使用手册:学会阅读指挥中心的作战地图
下一篇【第18篇】用SkyWalking观察微服务的各个维度:从宏观到微观的侦察术