为什么要配置多数据中心
单数据中心的微服务架构在面对机房级故障(如网络中断、断电)时会完全瘫痪。多数据中心(Multi-Datacenter)架构是解决这类问题的核心方案,它确保当一个数据中心不可用时,流量可以自动切换到其他数据中心。
本节使用 Bitnami Consul 镜像通过 Docker Compose 快速搭建两个 Consul 数据中心,模拟异地容灾场景。
Docker Compose 配置
完整配置文件
# docker-compose.consul.yml
version: '3.8'
services:
consul:
image: bitnami/consul:latest
container_name: consul
ports:
- '8500:8500' # HTTP API & UI
# - '8600:8600/udp' # DNS
# - '8300:8300' # Server RPC
# - '8301:8301' # Serf LAN
# - '8302:8302' # Serf WAN
environment:
- CONSUL_BIND_ADDR=0.0.0.0
- CONSUL_ENABLE_SERVER=yes
- CONSUL_BOOTSTRAP_EXPECT=1
- CONSUL_UI_ENABLED=true
- CONSUL_DATAcenter=dc1 # 数据中心 1 名称
volumes:
- ./consul/data:/bitnami/consul # 数据持久化
- ./consul/config:/bitnami/consul/conf
networks:
- consul-network
consul1:
image: bitnami/consul:latest
container_name: consul1
ports:
- '8501:8500' # 注意:映射到宿主机 8501,避免与 consul 冲突
environment:
- CONSUL_BIND_ADDR=0.0.0.0
- CONSUL_ENABLE_SERVER=yes
- CONSUL_BOOTSTRAP_EXPECT=1
- CONSUL_UI_ENABLED=true
- CONSUL_DATAcenter=dc2 # 数据中心 2 名称
# 配置 WAN 连接(跨数据中心互访)
- CONSUL_RETRY_JOIN_WAN=[\"consul\"] # 连接到 consul(dc1)
volumes:
- ./consul/data1:/bitnami/consul
- ./consul/config:/bitnami/consul/conf
depends_on:
- consul
networks:
- consul-network
networks:
consul-network:
driver: bridge
yaml
配置要点解析
端口映射原理
Docker 容器的网络与宿主机是隔离的。两个容器内部都使用 8500 端口是完全合法的——映射规则是 宿主机端口:容器内端口:
consul: 宿主机 8500 → 容器内 8500
consul1: 宿主机 8501 → 容器内 8500 # 容器内的 8500 不冲突
text
Windows 用户注意事项
在 Windows 上配置数据卷挂载路径时,需要使用绝对路径和反斜线:
volumes:
- D:\\Projects\\consul\\data:/bitnami/consul
yaml
如果觉得路径配置比较麻烦,推荐使用 WSL2 或虚拟机(Ubuntu)来运行 Docker 环境。
启动与验证
启动双数据中心
# 先清理旧数据
rm -rf consul/data consul/data1
# 启动两个 Consul 容器
docker compose -f docker-compose.consul.yml up -d
# 查看运行状态
docker compose -f docker-compose.consul.yml ps
bash
验证独立运行
# 访问数据中心 1
open http://localhost:8500
# 页面顶部显示 "dc1"
# 访问数据中心 2
open http://localhost:8501
# 页面顶部显示 "dc2"
bash
验证跨数据中心互访
配置了 CONSUL_RETRY_JOIN_WAN 后,在任一 Consul UI 的左侧导航栏应该能看到 dc1 和 dc2 两个数据中心,并可以自由切换。
retry_join_wan 的作用与局限
它能做什么
retry_join_wan 建立的是数据中心之间的 WAN(Wide Area Network)连接,其核心作用包括:
- 统一管理视图:在任一数据中心可以查看和管理其他数据中心的服务
- KV 存储同步:跨数据中心的键值对配置可以保持一致
- 策略同步:安全策略、ACL 策略可以跨数据中心同步
它不能做什么
服务注册信息不会自动同步。注册到 dc1 的服务不会自动出现在 dc2 的服务列表中。这是 Consul 的设计决策——每个数据中心保持独立的服务注册表。
如果需要跨数据中心的服务发现,可以通过 API 显式查询:
# 在 dc1 中查询 dc2 的服务
curl "http://localhost:8500/v1/catalog/service/user-service?dc=dc2"
bash
或者在 NestJS 中注册服务时,向多个数据中心同时注册:
// 向多个数据中心注册
const registrations = [
{ address: 'localhost:8500', datacenter: 'dc1' },
{ address: 'localhost:8501', datacenter: 'dc2' },
];
typescript
跨数据中心服务查询
HTTP API 方式
# 查询当前数据中心的所有服务
curl http://localhost:8500/v1/agent/services
# 跨数据中心查询 dc2 的服务
curl "http://localhost:8500/v1/catalog/service/user-service?dc=dc2"
bash
通过 UI 查看
在 Consul UI 中切换数据中心时,会自动使用对应的 API 接口获取服务列表。左上角会标注当前查看的是哪个数据中心,以及标记 local 数据中心。
管理命令速查
# 停止并删除容器
docker compose -f docker-compose.consul.yml down
# 停止并删除容器及数据卷
docker compose -f docker-compose.consul.yml down -v
# 重启(修改配置后)
docker compose -f docker-compose.consul.yml up -d --force-recreate
# 查看容器日志
docker logs consul -f
docker logs consul1 -f
bash
架构示意
┌─────────────────────────────────────────────┐
│ Consul WAN Network │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ DC1 │ │ DC2 │ │
│ │ localhost │◄────►│ localhost │ │
│ │ :8500 │ WAN │ :8501 │ │
│ │ │ │ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │User Svc │ │ │ │User Svc │ │ │
│ │ │Inst 1 │ │ │ │Inst 3 │ │ │
│ │ ├─────────┤ │ │ └─────────┘ │ │
│ │ │User Svc │ │ │ │ │
│ │ │Inst 2 │ │ │ │ │
│ │ └─────────┘ │ │ │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────┘
text
↑