演示场景概述
这一节通过完整的实战演示,展示 Consul 注册中心配合 NestJS 微服务实现故障转移的全过程。整个实验环境由两个数据中心(Datacenter)组成:
- Datacenter 1:运行两个 NestJS 微服务实例(user-service-1 和 user-service-2)
- Datacenter 2:运行一个 NestJS 微服务实例
这种多实例、多数据中心的架构模拟了生产环境中的异地容灾场景。当某个服务实例发生故障时,系统需要自动将请求转发到健康的实例上,确保服务不中断。
正常请求基线测试
首先测试所有服务正常状态下的响应情况:
# 使用 Bruno 或 curl 发起请求
curl http://localhost:40003/api/v1/user/health
bash
正常情况下,响应时间约 54ms,这个数据非常重要——后续的故障转移请求会与这个基线进行对比。
故障模拟与转移过程
第一次故障转移
手动停止 Datacenter 1 中的一个实例(端口 40003),模拟服务宕机:
# 查看正在运行的服务
pnpm dev:user1 # 假设这个实例运行在 40003 端口
# Ctrl+C 停止服务
bash
再次发起请求后,观察到的变化:
| 指标 | 正常状态 | 故障转移时 |
|---|---|---|
| 响应时间 | ~54ms | ~1.8s |
| 请求目标 | 40003 实例 | 自动切换到 40002 实例 |
| 故障感知 | 无 | Consul 健康检查检测到下线 |
故障转移的请求链路如下:
- 客户端请求到达 Gateway(网关)
- Gateway 尝试请求 40003 实例 → 失败(服务已停止)
- Gateway 触发故障转移逻辑,向 Consul Server 请求健康的实例列表
- Consul Server 返回健康的 user-service-1 实例(40002 端口)
- Gateway 将请求转发到健康实例,成功返回结果
第二次故障转移
继续停止第二个实例,观察系统在只剩一个可用实例时的表现:
# 停止第二个实例
pnpm dev:user-service-1 # 40002 端口
# Ctrl+C 停止
bash
此时系统面临的情况更加严峻:
- Datacenter 1 中已无可用实例
- 请求需要跨数据中心转移到 Datacenter 2 的实例
需要注意 Consul Server 的健康状态更新存在滞后性。Consul 遵循 CAP 理论中的 CP 模型(一致性和分区容忍性优先),而不是 AP 模型(可用性优先)。这意味着在分区发生时,Consul 会牺牲一定的可用性来保证数据一致性。
实例恢复后的自动回切
将之前停止的实例重新启动后:
# 重新启动所有实例
pnpm dev:user1
pnpm dev:user-service-1
pnpm dev:user2
bash
观察到的现象:
- 实例启动后,Consul 健康检查需要一定时间才能将状态标记为"健康"
- 后续请求会自动恢复到正常的响应时间(几十毫秒级别)
- Consul 会根据负载策略将请求分发到不同实例
Consul 健康检查的关键细节
健康状态更新的滞后问题
在整个演示过程中,Consul 的健康检查存在明显的滞后性,这是因为:
- 检查间隔:Consul 默认的健康检查间隔约为 10 秒
- 状态同步延迟:多数据中心之间通过 WAN gossip 协议同步,会有额外延迟
- ** deregister 时间**:服务停止后不会立即被标记为不健康
可以通过 Consul 配置文件调整检查频率来缩短滞后时间:
{
"check": {
"id": "user-service-health",
"name": "User Service Health Check",
"http": "http://localhost:40002/health",
"interval": "5s",
"timeout": "3s",
"deregister_critical_service_after": "30s"
}
}
json
deregister_critical_service_after 参数表示当服务持续处于 critical 状态超过 30 秒后,自动从注册中心移除。
健康检查接口的 Scope 优化
在开发调试阶段,建议将健康检查 Controller 的 Scope 设置为 REQUEST,确保每次请求都创建新的实例,避免缓存干扰:
import { Controller, Scope } from '@nestjs/common';
@Controller({
path: 'health',
scope: Scope.REQUEST, // 每次请求创建新实例
})
export class HealthController {
// ...
}
typescript
故障转移架构总结
生产环境建议
| 配置项 | 开发/测试建议 | 生产环境建议 |
|---|---|---|
| 健康检查间隔 | 10s | 5s |
| 超时时间 | 5s | 3s |
| 自动注销时间 | 不设置 | 30s-60s |
| 实例数量 | 1-2 个 | 3 个以上(奇数个) |
| 数据中心数量 | 1 个 | 2 个以上(异地容灾) |
相关资源
↑