
上一篇【第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 Gateway3.1.x服务框架Spring Boot2.7.x注册中心Nacos2.2.x数据库MySQL8.0缓存Redis7.x消息队列RocketMQ5.x监控SkyWalking9.3.0存储Elasticsearch8.122. 各服务的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-gatewayecommerce-gateway8080user-serviceuser-service8081order-serviceorder-service8082payment-servicepayment-service8083inventory-serviceinventory-service80842.2 各服务Agent配置每个服务的Agent配置核心参数# user-gateway agent.service_nameecommerce-gateway collector.backend_serviceskywalking-oap:11800 agent.sample_n_per_3_secs-1 logging.levelWARN # user-service agent.service_nameuser-service collector.backend_serviceskywalking-oap:11800 agent.sample_n_per_3_secs-1 logging.levelWARN # order-service agent.service_nameorder-service collector.backend_serviceskywalking-oap:11800 agent.sample_n_per_3_secs-1 logging.levelWARN # payment-service agent.service_namepayment-service collector.backend_serviceskywalking-oap:11800 agent.sample_n_per_3_secs-1 logging.levelWARN # inventory-service agent.service_nameinventory-service collector.backend_serviceskywalking-oap:11800 agent.sample_n_per_3_secs-1 logging.levelWARN2.3 网关服务的特殊处理Spring Cloud Gateway是基于WebFlux的响应式框架需要额外激活Gateway插件# 激活Gateway插件mvoptional-plugins/apm-spring-cloud-gateway-2.x-plugin.jar plugins/# 同时需要激活WebFlux插件如果Gateway使用WebFluxmvoptional-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_NAMEuser-service-SW_AGENT_COLLECTOR_BACKEND_SERVICESskywalking-oap:11800-SW_LOGGING_LEVELWARNvolumes:-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:WARNvolumeMounts:-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:11800SW_LOGGING_LEVEL:WARNSW_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.8services:# 基础设施 # 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:3306volumes:-mysql-data:/var/lib/mysql# Redis缓存redis:image:redis:7-alpineports:-6379:6379# Elasticsearchelasticsearch:image:elasticsearch:8.12.0environment:-discovery.typesingle-node-ES_JAVA_OPTS-Xms1g -Xmx1g-xpack.security.enabledfalseports:-9200:9200volumes:-es-data:/usr/share/elasticsearch/data# SkyWalking # OAP Serverskywalking-oap:image:apache/skywalking-oap-server:9.3.0environment:-SW_STORAGEelasticsearch-SW_CLUSTER_NODESelasticsearch:9200-SW_CORE_RECORD_DATA_TTL3-SW_CORE_OTHER_METRICS_DATA_TTL7depends_on:-elasticsearchports:-11800:11800-12800:12800# SkyWalking UIskywalking-ui:image:apache/skywalking-ui:9.3.0environment:-SW_OAP_ADDRESSskywalking-oap:12800depends_on:-skywalking-oapports:-9090:8080# 业务服务 # 用户网关user-gateway:build:context:./user-gatewaydockerfile:Dockerfileenvironment:-SW_AGENT_NAMEecommerce-gateway-SW_AGENT_COLLECTOR_BACKEND_SERVICESskywalking-oap:11800-SW_LOGGING_LEVELWARN-NACOS_ADDRnacos:8848depends_on:-nacos-skywalking-oapports:-8080:8080# 用户服务user-service:build:context:./user-servicedockerfile:Dockerfileenvironment:-SW_AGENT_NAMEuser-service-SW_AGENT_COLLECTOR_BACKEND_SERVICESskywalking-oap:11800-SW_LOGGING_LEVELWARN-NACOS_ADDRnacos:8848-MYSQL_HOSTmysql-REDIS_HOSTredisdepends_on:-nacos-mysql-redis-skywalking-oapports:-8081:8081# 订单服务order-service:build:context:./order-servicedockerfile:Dockerfileenvironment:-SW_AGENT_NAMEorder-service-SW_AGENT_COLLECTOR_BACKEND_SERVICESskywalking-oap:11800-SW_LOGGING_LEVELWARN-NACOS_ADDRnacos:8848-MYSQL_HOSTmysqldepends_on:-nacos-mysql-skywalking-oapports:-8082:8082# 支付服务payment-service:build:context:./payment-servicedockerfile:Dockerfileenvironment:-SW_AGENT_NAMEpayment-service-SW_AGENT_COLLECTOR_BACKEND_SERVICESskywalking-oap:11800-SW_LOGGING_LEVELWARN-NACOS_ADDRnacos:8848-MYSQL_HOSTmysqldepends_on:-nacos-mysql-skywalking-oapports:-8083:8083# 库存服务inventory-service:build:context:./inventory-servicedockerfile:Dockerfileenvironment:-SW_AGENT_NAMEinventory-service-SW_AGENT_COLLECTOR_BACKEND_SERVICESskywalking-oap:11800-SW_LOGGING_LEVELWARN-NACOS_ADDRnacos:8848-MYSQL_HOSTmysql-REDIS_HOSTredisdepends_on:-nacos-mysql-redis-skywalking-oapports:-8084:8084volumes: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|grepskywalking5.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|grepTID# 日志格式示例# 2026-07-02 14:30:00 INFO [TID:a3b2c1d4e5] UserService.getUser - userId123# 2026-07-02 14:30:00 INFO [TID:a3b2c1d4e5] UserService.queryDB - SQLSELECT...在Spring Boot中需要添加logback的TraceID输出格式!-- logback-spring.xml --configurationappendernameCONSOLEclassch.qos.logback.core.ConsoleAppenderencoder!-- %tid输出TraceID --pattern%d{yyyy-MM-dd HH:mm:ss} [%tid] %-5level %logger - %msg%n/pattern/encoder/appenderrootlevelINFOappender-refrefCONSOLE//root/configuration6. 小结实战环境搭建是把理论变成实践的关键一步集群架构5个微服务 基础设施 SkyWalking全链路服务名规划业务语义命名同服务多实例同名Agent配置环境变量覆盖方式统一管理K8s挂载initContainer方式是标准做法比Sidecar更高效Docker Compose完整的本地实战环境数据验证OAP状态 → UI访问 → 发请求 → 看拓扑 → 看Trace → 看日志下一篇文章我们将用这个实战环境来观察微服务的各个维度——从告警出发一步步定位问题。上一篇【第16篇】SkyWalking UI使用手册学会阅读指挥中心的作战地图下一篇【第18篇】用SkyWalking观察微服务的各个维度从宏观到微观的侦察术