跳到主要内容

微服务测试与可观测性

问题

微服务架构下如何做测试?如何实现全链路的可观测性?

答案

微服务测试金字塔

测试类型说明工具
单元测试测试单个类/方法JUnit 5、Mockito
集成测试测试服务与 DB/Redis 等的集成Testcontainers、@SpringBootTest
契约测试验证服务间 API 契约一致性Spring Cloud Contract、Pact
E2E 测试端到端全链路测试Selenium、Playwright

契约测试

服务 A 调用服务 B 的 API,契约测试确保 B 的 API 变更不会破坏 A。

Spring Cloud Contract DSL
Contract.make {
description("扣减库存成功")
request {
method POST()
url "/api/inventory/deduct"
headers { contentType(applicationJson()) }
body([productId: "P001", quantity: 1])
}
response {
status 200
body([success: true, remainStock: 99])
}
}

集成测试(Testcontainers)

使用 Testcontainers 启动真实数据库
@SpringBootTest
@Testcontainers
class OrderServiceIntegrationTest {

@Container
static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0")
.withDatabaseName("order_db");

@Container
static GenericContainer<?> redis = new GenericContainer<>("redis:7-alpine")
.withExposedPorts(6379);

@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", mysql::getJdbcUrl);
registry.add("spring.datasource.username", mysql::getUsername);
registry.add("spring.datasource.password", mysql::getPassword);
registry.add("spring.redis.host", redis::getHost);
registry.add("spring.redis.port", () -> redis.getMappedPort(6379));
}

@Autowired
private OrderService orderService;

@Test
void shouldCreateOrder() {
OrderDTO dto = new OrderDTO("user1", "product1", 2);
Order order = orderService.create(dto);
assertThat(order.getId()).isNotNull();
assertThat(order.getStatus()).isEqualTo("CREATED");
}
}

可观测性三大支柱

支柱说明工具
日志(Logs)离散事件记录ELK、Loki
指标(Metrics)聚合数值(QPS、延迟、错误率)Prometheus + Grafana
链路追踪(Traces)请求在多个服务间的调用链路SkyWalking、Zipkin

链路追踪

每个请求带一个全局 traceId,每次服务调用产生一个 spanId。通过链路追踪可以看到完整的调用链和每个节点的耗时。

日志中自动携带 TraceId
// Micrometer Tracing(Spring Boot 3.x)自动注入
// 日志输出:2024-01-15 10:30:00 [traceId=abc123, spanId=def456] INFO OrderService - 创建订单

// logback-spring.xml 配置
// <pattern>%d [traceId=%X{traceId}, spanId=%X{spanId}] %-5level %logger - %msg%n</pattern>

监控告警

指标含义告警阈值(参考)
QPS每秒请求数超过容量的 80%
P99 延迟99% 请求在此时间内完成> 3 秒
错误率5xx 响应占比> 1%
CPU 使用率容器 CPU 使用> 80%
内存使用率容器内存使用> 85%
GC 频率Full GC 次数> 1 次/分钟

常见面试问题

Q1: 微服务架构下如何排查线上问题?

答案

  1. 看日志:通过 traceId 在 ELK/Loki 中搜索完整调用链路的日志
  2. 看链路:在 SkyWalking 中查看调用拓扑和各节点耗时
  3. 看指标:在 Grafana 中查看 QPS、延迟、错误率等指标变化
  4. 看告警:根据告警信息快速定位哪个服务出问题

排查流程:告警触发 → Grafana 看指标 → SkyWalking 看链路 → ELK 看日志 → 定位根因。

Q2: 如何保证微服务上线质量?

答案

  1. 单元测试:覆盖核心业务逻辑(> 80% 覆盖率)
  2. 集成测试:Testcontainers 验证 DB/Redis 等集成
  3. 契约测试:保证服务间 API 兼容
  4. 灰度发布:先小比例流量验证
  5. 监控告警:发布后重点关注错误率和延迟

Q3: traceId 如何在服务间传递?

答案

  1. 第一个服务(通常是网关)生成 traceId
  2. 通过 HTTP Header(如 X-B3-TraceId)在服务间传递
  3. 每个服务的日志框架(如 Logback MDC)自动记录 traceId
  4. 异步场景(MQ)通过消息属性传递 traceId

Spring Boot 3.x 使用 Micrometer Tracing 自动完成这些工作。

相关链接