Skip to content

Consul

Consul是HashiCorp开发的分布式服务网格解决方案,提供服务发现、健康检查、键值存储、多数据中心支持等功能,广泛应用于微服务架构和云原生环境。

核心功能

服务发现

  • 服务注册 - 服务实例自动注册到Consul
  • DNS接口 - 通过DNS查询服务实例
  • HTTP API - RESTful API查询服务信息
  • 健康检查 - 自动检测和移除不健康实例

健康检查

  • HTTP检查 - 定期发送HTTP请求检查服务状态
  • TCP检查 - 检查TCP端口连接性
  • 脚本检查 - 执行自定义脚本检查
  • TTL检查 - 基于TTL的心跳检查

键值存储

  • 配置管理 - 存储应用配置信息
  • 分布式锁 - 实现分布式协调
  • 领导者选举 - 选举机制支持
  • 事务支持 - 原子性操作保证

多数据中心

  • WAN连接 - 多数据中心间的WAN连接
  • 跨DC服务发现 - 跨数据中心的服务查询
  • 数据复制 - 关键数据跨数据中心复制
  • 故障隔离 - 数据中心级别的故障隔离

架构设计

核心组件

点击查看完整代码实现
Consul架构:
├── Consul Server
│   ├── Leader选举(Raft协议)
│   ├── 数据存储和复制
│   ├── 跨DC通信
│   └── API服务
├── Consul Client  
│   ├── 本地代理
│   ├── 健康检查执行
│   ├── 服务注册
│   └── DNS转发
└── Consul Connect(服务网格)
    ├── Sidecar代理
    ├── mTLS加密
    ├── 意图配置
    └── 流量管理

集群模式

单数据中心:
├── Server节点(3或5个)
│   ├── Leader(1个)
│   └── Follower(2或4个)
└── Client节点(多个)
    ├── 服务注册
    └── 健康检查

多数据中心:
DC1: Server集群 <-> WAN <-> DC2: Server集群
 ↓                             ↓
Client节点                    Client节点

基础使用

服务注册

HTTP API方式

点击查看完整代码实现
bash
# 注册服务
curl -X PUT http://localhost:8500/v1/agent/service/register \
  -d '{
    "ID": "web-01",
    "Name": "web", 
    "Tags": ["v1", "primary"],
    "Address": "192.168.1.100",
    "Port": 8080,
    "Check": {
      "HTTP": "http://192.168.1.100:8080/health",
      "Interval": "30s"
    }
  }'

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

配置文件方式

json
{
  "service": {
    "name": "web",
    "id": "web-01", 
    "port": 8080,
    "address": "192.168.1.100",
    "tags": ["v1", "primary"],
    "check": {
      "http": "http://192.168.1.100:8080/health",
      "interval": "30s",
      "timeout": "3s"
    }
  }
}

服务发现

DNS查询

bash
# 查询服务实例
dig @localhost -p 8600 web.service.consul SRV

# 查询结果示例
web.service.consul. 0 IN SRV 1 1 8080 web-01.node.consul.

HTTP API查询

点击查看完整代码实现
bash
# 查询健康的服务实例
curl http://localhost:8500/v1/health/service/web?passing

# 返回JSON格式的服务信息
[
  {
    "Node": {
      "ID": "40e4a748-2192-161a-0510-9bf59fe950b5",
      "Node": "consul-1",
      "Address": "192.168.1.100"
    },
    "Service": {
      "ID": "web-01",
      "Service": "web",
      "Tags": ["v1", "primary"],
      "Address": "192.168.1.100", 
      "Port": 8080
    },
    "Checks": [
      {
        "CheckID": "service:web-01",
        "Status": "passing"
      }
    ]
  }
]

Java客户端集成

Spring Cloud Consul

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
点击查看完整代码实现
yaml
# application.yml
spring:
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: user-service
        port: 8080
        health-check-path: /actuator/health
        health-check-interval: 30s
        tags: 
          - version=1.0
          - environment=production
        prefer-ip-address: true
点击查看完整代码实现
java
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

@RestController
public class UserController {
    
    @Autowired
    private DiscoveryClient discoveryClient;
    
    @GetMapping("/users")
    public List<String> getUsers() {
        // 获取服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances("order-service");
        return Arrays.asList("user1", "user2");
    }
}

Consul原生客户端

点击查看完整代码实现
java
import com.orbitz.consul.Consul;
import com.orbitz.consul.HealthClient;
import com.orbitz.consul.model.health.ServiceHealth;

public class ConsulService {
    private final Consul consul;
    
    public ConsulService() {
        this.consul = Consul.builder()
            .withUrl("http://localhost:8500")
            .build();
    }
    
    // 注册服务
    public void registerService(String serviceName, String serviceId, 
                               String address, int port) {
        consul.agentClient().register(
            ImmutableRegistration.builder()
                .id(serviceId)
                .name(serviceName)
                .address(address)
                .port(port)
                .addTags("version-1")
                .check(Registration.RegCheck.http(
                    String.format("http://%s:%d/health", address, port), 30))
                .build());
    }
    
    // 发现服务
    public List<ServiceHealth> discoverService(String serviceName) {
        HealthClient healthClient = consul.healthClient();
        return healthClient.getHealthyServiceInstances(serviceName).getResponse();
    }
}

键值存储

基本操作

bash
# 存储键值对
curl -X PUT http://localhost:8500/v1/kv/config/database/host -d 'localhost'
curl -X PUT http://localhost:8500/v1/kv/config/database/port -d '3306'

# 读取值
curl http://localhost:8500/v1/kv/config/database/host

# 删除键
curl -X DELETE http://localhost:8500/v1/kv/config/database/host

# 递归删除
curl -X DELETE http://localhost:8500/v1/kv/config/database?recurse

分布式锁

bash
# 获取锁
curl -X PUT http://localhost:8500/v1/session/create -d '{
  "Name": "my-lock",
  "TTL": "30s"
}'
# 返回: {"ID":"adf4238a-882b-9ddc-4a9d-5b6758e4159e"}

# 尝试获取锁
curl -X PUT http://localhost:8500/v1/kv/locks/my-resource?acquire=adf4238a-882b-9ddc-4a9d-5b6758e4159e -d 'lock-data'

# 释放锁
curl -X PUT http://localhost:8500/v1/kv/locks/my-resource?release=adf4238a-882b-9ddc-4a9d-5b6758e4159e

Java配置管理

点击查看完整代码实现
java
import com.orbitz.consul.Consul;
import com.orbitz.consul.KeyValueClient;

public class ConsulConfigManager {
    private final KeyValueClient kvClient;
    
    public ConsulConfigManager() {
        Consul consul = Consul.builder().build();
        this.kvClient = consul.keyValueClient();
    }
    
    public void setConfig(String key, String value) {
        kvClient.putValue(key, value);
    }
    
    public String getConfig(String key) {
        return kvClient.getValueAsString(key).orElse(null);
    }
    
    public void watchConfig(String keyPrefix, ConfigChangeListener listener) {
        // 实现配置监听
        kvClient.consulClient().preparedQuery()
            .list()
            .getResponse()
            .forEach(query -> {
                // 监听配置变化
            });
    }
}

集群部署

Server节点配置

点击查看完整代码实现
json
{
  "datacenter": "dc1",
  "data_dir": "/opt/consul/data",
  "log_level": "INFO",
  "server": true,
  "bootstrap_expect": 3,
  "bind_addr": "192.168.1.100",
  "client_addr": "0.0.0.0",
  "retry_join": ["192.168.1.101", "192.168.1.102"],
  "ui_config": {
    "enabled": true
  },
  "connect": {
    "enabled": true
  },
  "ports": {
    "grpc": 8502
  }
}

Client节点配置

点击查看完整代码实现
json
{
  "datacenter": "dc1",
  "data_dir": "/opt/consul/data",
  "log_level": "INFO", 
  "server": false,
  "bind_addr": "192.168.1.200",
  "client_addr": "127.0.0.1",
  "retry_join": ["192.168.1.100", "192.168.1.101", "192.168.1.102"],
  "services": [
    {
      "name": "web",
      "port": 8080,
      "check": {
        "http": "http://localhost:8080/health",
        "interval": "30s"
      }
    }
  ]
}

多数据中心配置

json
{
  "datacenter": "dc1",
  "primary_datacenter": "dc1", 
  "retry_join_wan": ["192.168.2.100"],
  "connect": {
    "enabled": true,
    "ca_provider": "consul",
    "ca_config": {
      "root_cert_ttl": "87600h"
    }
  }
}

Consul Connect服务网格

服务网格配置

json
{
  "connect": {
    "enabled": true
  },
  "ports": {
    "grpc": 8502
  }
}

Sidecar代理

点击查看完整代码实现
json
{
  "service": {
    "name": "web",
    "port": 8080,
    "connect": {
      "sidecar_service": {
        "proxy": {
          "upstreams": [
            {
              "destination_name": "database",
              "local_bind_port": 9191
            }
          ]
        }
      }
    }
  }
}

意图配置

bash
# 允许web服务访问database服务
consul intention create web database

# 拒绝访问
consul intention create -deny web database

# 查看意图
consul intention match web

监控管理

内置UI

访问Web UI: http://localhost:8500/ui/
功能:
├── 服务列表和健康状态
├── 节点信息
├── 键值存储浏览
├── 意图管理
└── ACL管理

监控指标

bash
# Prometheus指标端点
curl http://localhost:8500/v1/agent/metrics?format=prometheus

# 关键指标
consul_health_service_query_time
consul_raft_leader_elections_total
consul_memberlist_gossip_time

日志配置

json
{
  "log_level": "INFO",
  "enable_syslog": true,
  "log_json": true,
  "log_file": "/var/log/consul/",
  "log_rotate_duration": "24h",
  "log_rotate_max_files": 7
}

安全配置

ACL权限控制

点击查看完整代码实现
bash
# 启用ACL
{
  "acl": {
    "enabled": true,
    "default_policy": "deny",
    "enable_token_persistence": true
  }
}

# 创建管理员令牌
consul acl bootstrap

# 创建策略
consul acl policy create -name "service-read" -rules @service-read-policy.hcl

# service-read-policy.hcl
service_prefix "" {
  policy = "read"
}
node_prefix "" {
  policy = "read"
}

TLS加密

点击查看完整代码实现
bash
# 生成CA证书
consul tls ca create

# 生成服务器证书
consul tls cert create -server -dc dc1

# 配置TLS
{
  "ca_file": "/opt/consul/tls/consul-agent-ca.pem",
  "cert_file": "/opt/consul/tls/dc1-server-consul-0.pem", 
  "key_file": "/opt/consul/tls/dc1-server-consul-0-key.pem",
  "verify_incoming": true,
  "verify_outgoing": true,
  "verify_server_hostname": true
}

最佳实践

部署规划

  • 每个数据中心部署奇数个Server节点(3或5)
  • Client节点与应用服务部署在同一主机
  • 合理规划网络拓扑,减少网络延迟
  • 使用自动化工具管理集群

服务注册

  • 使用有意义的服务名称和标签
  • 配置合适的健康检查
  • 实现优雅的服务上线和下线
  • 避免频繁的服务注册注销

配置管理

  • 合理设计键值存储的层次结构
  • 使用命名空间隔离不同环境
  • 实现配置变更的审计日志
  • 定期备份重要配置数据

安全防护

  • 启用ACL权限控制
  • 配置TLS加密通信
  • 限制网络访问范围
  • 定期轮换访问令牌

监控运维

  • 监控集群健康状态
  • 设置关键指标告警
  • 定期检查日志文件
  • 建立故障恢复流程

Consul作为成熟的服务网格解决方案,凭借其丰富的功能特性、强大的多数据中心支持和完善的安全机制,为企业构建可靠的微服务基础设施提供了强有力的支撑。

正在精进