Skip to content

Consul — 多数据中心服务网格

架构概览

Consul 是 HashiCorp 出品的服务发现、配置管理和服务网格工具,原生支持多数据中心。

Data Center 1 (us-east)          Data Center 2 (us-west)
┌─────────────────────┐          ┌─────────────────────┐
│  Server 1 (Leader)  │◄────────►│  Server 4 (Leader)  │
│  Server 2           │  WAN     │  Server 5           │
│  Server 3           │  Gossip  │  Server 6           │
│                     │          │                     │
│  Agent  Agent  Agent│          │  Agent  Agent  Agent│
│  (Client Mode)      │          │  (Client Mode)      │
└─────────────────────┘          └─────────────────────┘

组件说明

组件说明
Server存储集群状态,参与 Raft 选举,建议 3 或 5 个
Client(Agent)部署在每个服务节点,转发请求到 Server,执行健康检查
Gossip 协议节点发现和故障检测(LAN Gossip 和 WAN Gossip)
Raft 协议Server 间数据一致性

服务注册与健康检查

服务定义(JSON)

json
{
  "service": {
    "id": "order-service-1",
    "name": "order-service",
    "tags": ["v1.2", "primary"],
    "address": "192.168.1.100",
    "port": 8080,
    "meta": {
      "version": "1.2.0",
      "env": "production"
    },
    "checks": [
      {
        "id": "http-check",
        "name": "HTTP Health Check",
        "http": "http://192.168.1.100:8080/actuator/health",
        "interval": "10s",
        "timeout": "3s",
        "deregister_critical_service_after": "30s"
      },
      {
        "id": "tcp-check",
        "name": "TCP Check",
        "tcp": "192.168.1.100:8080",
        "interval": "10s"
      }
    ]
  }
}

API 注册

bash
# 注册服务
curl -X PUT http://localhost:8500/v1/agent/service/register \
  -H "Content-Type: application/json" \
  -d @service.json

# 查询健康服务
curl "http://localhost:8500/v1/health/service/order-service?passing=true"

# 注销服务
curl -X PUT http://localhost:8500/v1/agent/service/deregister/order-service-1

Spring Cloud Consul 集成

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
yaml
spring:
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: order-service
        health-check-path: /actuator/health
        health-check-interval: 10s
        instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
        tags:
          - version=1.2.0

KV 存储(配置中心)

Consul 内置 KV 存储,可作为轻量级配置中心:

bash
# 写入配置
consul kv put config/order-service/db.url "jdbc:mysql://mysql:3306/orders"
consul kv put config/order-service/timeout "5000"

# 读取配置
consul kv get config/order-service/db.url

# 监听变更(长轮询)
consul kv get -wait=5m -index=<last-index> config/order-service/db.url

# 导入配置(JSON 格式)
consul kv import @config.json

Spring Cloud Config + Consul

yaml
spring:
  cloud:
    consul:
      config:
        enabled: true
        prefix: config
        default-context: application
        profile-separator: ','
        format: YAML
        data-key: data

配置路径规则:

config/order-service,prod/data    # 最高优先级
config/order-service/data
config/application,prod/data
config/application/data           # 最低优先级

Consul Connect(服务网格)

Consul Connect 提供基于 mTLS 的服务间安全通信:

hcl
# 服务配置(HCL 格式)
service {
  name = "order-service"
  port = 8080
  
  connect {
    sidecar_service {
      proxy {
        upstreams = [
          {
            destination_name = "payment-service"
            local_bind_port  = 9090
          }
        ]
      }
    }
  }
}
bash
# 启动 Envoy Sidecar
consul connect envoy -sidecar-for order-service

Intention(访问控制)

bash
# 允许 order-service 访问 payment-service
consul intention create order-service payment-service

# 拒绝所有到 db-service 的访问(默认拒绝)
consul intention create -deny '*' db-service

# 查看 Intention
consul intention list

多数据中心

bash
# 查询其他数据中心的服务
curl "http://localhost:8500/v1/catalog/service/order-service?dc=us-west"

# 跨数据中心 DNS 查询
dig @127.0.0.1 -p 8600 order-service.service.us-west.consul

# 配置 WAN 联邦
consul join -wan <us-west-server-ip>

ACL 安全配置

bash
# 启用 ACL
# consul.hcl
acl {
  enabled = true
  default_policy = "deny"
  enable_token_persistence = true
}

# 初始化 ACL(生成 bootstrap token)
consul acl bootstrap

# 创建服务 Token
consul acl token create \
  --description "order-service token" \
  --policy-name order-service-policy

# 创建 Policy
consul acl policy create \
  --name order-service-policy \
  --rules @order-policy.hcl
hcl
# order-policy.hcl
service "order-service" {
  policy = "write"
}
service_prefix "" {
  policy = "read"
}
node_prefix "" {
  policy = "read"
}

故障处理案例

案例一:服务健康检查频繁失败

现象:服务实例频繁在 passing/critical 状态切换,导致流量抖动。

排查

bash
# 查看健康检查详情
consul health checks order-service

# 查看 Agent 日志
journalctl -u consul -f

常见原因与解决

  • 健康检查超时太短 → 调整 timeoutinterval
  • 服务启动慢 → 增加 deregister_critical_service_after 时间
  • 网络抖动 → 使用 TCP 检查替代 HTTP 检查

案例二:Leader 选举频繁

现象:Consul Server 频繁发生 Leader 选举,集群不稳定。

排查

bash
# 查看 Raft 状态
consul operator raft list-peers

# 查看集群成员
consul members -detailed

原因

  • Server 节点资源不足(CPU/内存)
  • 网络延迟过高(Raft 心跳超时)
  • 时钟不同步

解决

hcl
# 调整 Raft 超时参数
performance {
  raft_multiplier = 1  # 默认 5,减小可加快选举但增加网络敏感性
}

案例三:KV 数据不一致

现象:从不同 Server 读取 KV 数据不一致。

原因:默认读取使用 default 一致性级别(可能读到 Stale 数据)。

解决

bash
# 强一致性读(必须从 Leader 读)
curl "http://localhost:8500/v1/kv/config/db.url?consistent"

# 最终一致性读(允许 Stale,性能最好)
curl "http://localhost:8500/v1/kv/config/db.url?stale"

监控指标

bash
# Consul 内置 Telemetry
curl http://localhost:8500/v1/agent/metrics?format=prometheus
指标说明
consul.raft.leader是否为 Leader(1=是)
consul.raft.commitTimeRaft 提交延迟
consul.catalog.service.query服务查询次数
consul.health.service.query健康检查查询次数
consul.serf.eventsGossip 事件数

PaaS 中间件生态系统深度学习文档