Consul注册中心 #

一、Consul概述 #

1.1 什么是Consul #

Consul是HashiCorp公司开源的服务发现和配置管理工具,提供了完整的服务网格解决方案。

text
┌─────────────────────────────────────────────────────────────┐
│                    Consul核心功能                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│   │ 服务发现     │  │ 健康检查     │  │ KV存储      │        │
│   │ Service     │  │ Health      │  │ Key-Value   │        │
│   │ Discovery   │  │ Checking    │  │ Store       │        │
│   └─────────────┘  └─────────────┘  └─────────────┘        │
│                                                             │
│   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│   │ 多数据中心   │  │ 服务网格     │  │ 安全通信     │        │
│   │ Multi       │  │ Service     │  │ Secure      │        │
│   │ Datacenter  │  │ Mesh        │  │ Communication│        │
│   └─────────────┘  └─────────────┘  └─────────────┘        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 Consul特性 #

特性 说明
服务发现 支持DNS和HTTP接口
健康检查 多种健康检查方式
KV存储 分布式键值存储
多数据中心 支持多数据中心部署
服务网格 支持服务网格
安全通信 TLS加密通信

1.3 Consul vs Nacos vs Eureka #

特性 Consul Nacos Eureka
CAP CP AP/CP AP
一致性 Raft Distro/Raft 弱一致
健康检查 TCP/HTTP/gRPC TCP/HTTP/MySQL 心跳
KV存储
多数据中心
配置中心

二、安装部署 #

2.1 下载安装 #

bash
# macOS
brew install consul

# Linux
wget https://releases.hashicorp.com/consul/1.17.0/consul_1.17.0_linux_amd64.zip
unzip consul_1.17.0_linux_amd64.zip
sudo mv consul /usr/local/bin/

2.2 开发模式启动 #

bash
consul agent -dev

2.3 访问控制台 #

访问 http://localhost:8500

2.4 Docker部署 #

bash
docker run -d \
  --name consul \
  -p 8500:8500 \
  -p 8600:8600/udp \
  consul:1.17.0 agent -server -ui -bootstrap-expect=1 -client=0.0.0.0

三、服务注册发现 #

3.1 添加依赖 #

xml
<dependencies>
    <!-- Spring Cloud Consul Discovery -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    </dependency>
    
    <!-- Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

3.2 配置文件 #

yaml
spring:
  application:
    name: service-provider
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        enabled: true
        register: true
        service-name: ${spring.application.name}
        instance-id: ${spring.application.name}:${server.port}
        health-check-path: /actuator/health
        health-check-interval: 10s
        health-check-timeout: 5s
        prefer-ip-address: true
        ip-address: ${IP_ADDRESS:127.0.0.1}
        port: ${server.port}
        tags: version=1.0.0,author=team-a

server:
  port: 8001

management:
  endpoints:
    web:
      exposure:
        include: health,info
  endpoint:
    health:
      show-details: always

3.3 启动类 #

java
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}

3.4 服务接口 #

java
@RestController
public class ProviderController {
    
    @Value("${server.port}")
    private String port;
    
    @GetMapping("/hello")
    public String hello() {
        return "Hello from Consul Provider, port: " + port;
    }
}

四、服务调用 #

4.1 使用RestTemplate #

java
@Configuration
public class RestTemplateConfig {
    
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
java
@RestController
public class ConsumerController {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("/consume")
    public String consume() {
        return restTemplate.getForObject(
            "http://service-provider/hello", 
            String.class
        );
    }
}

4.2 使用DiscoveryClient #

java
@RestController
public class DiscoveryController {
    
    @Autowired
    private DiscoveryClient discoveryClient;
    
    @GetMapping("/services")
    public List<String> getServices() {
        return discoveryClient.getServices();
    }
    
    @GetMapping("/instances/{serviceName}")
    public List<ServiceInstance> getInstances(@PathVariable String serviceName) {
        return discoveryClient.getInstances(serviceName);
    }
}

五、健康检查 #

5.1 健康检查配置 #

yaml
spring:
  cloud:
    consul:
      discovery:
        health-check-path: /actuator/health
        health-check-interval: 10s
        health-check-timeout: 5s
        health-check-critical-timeout: 30s

5.2 自定义健康检查 #

java
@RestController
public class HealthController {
    
    @GetMapping("/health")
    public Map<String, Object> health() {
        Map<String, Object> health = new HashMap<>();
        health.put("status", "UP");
        health.put("timestamp", System.currentTimeMillis());
        return health;
    }
}

5.3 健康检查类型 #

类型 说明
HTTP HTTP请求检查
TCP TCP端口检查
TTL 时间间隔检查
gRPC gRPC服务检查
Script 脚本检查

六、集群部署 #

6.1 集群架构 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Consul集群架构                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│   │   Server    │  │   Server    │  │   Server    │        │
│   │  (Leader)   │  │ (Follower)  │  │ (Follower)  │        │
│   │   :8300     │  │   :8300     │  │   :8300     │        │
│   └──────┬──────┘  └──────┬──────┘  └──────┬──────┘        │
│          │                │                │                │
│          └────────────────┼────────────────┘                │
│                           │                                 │
│          ┌────────────────┼────────────────┐                │
│          │                │                │                │
│   ┌──────┴──────┐  ┌──────┴──────┐  ┌──────┴──────┐        │
│   │   Client    │  │   Client    │  │   Client    │        │
│   │   Agent     │  │   Agent     │  │   Agent     │        │
│   └─────────────┘  └─────────────┘  └─────────────┘        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6.2 Server配置 #

创建 server.json

json
{
  "datacenter": "dc1",
  "data_dir": "/opt/consul/data",
  "server": true,
  "bootstrap_expect": 3,
  "bind_addr": "0.0.0.0",
  "client_addr": "0.0.0.0",
  "ui": true,
  "retry_join": ["consul-server1", "consul-server2", "consul-server3"]
}

6.3 启动Server #

bash
# Server 1
consul agent -config-dir=/etc/consul.d/server.json -node=server1

# Server 2
consul agent -config-dir=/etc/consul.d/server.json -node=server2

# Server 3
consul agent -config-dir=/etc/consul.d/server.json -node=server3

6.4 Client配置 #

创建 client.json

json
{
  "datacenter": "dc1",
  "data_dir": "/opt/consul/data",
  "server": false,
  "bind_addr": "0.0.0.0",
  "retry_join": ["consul-server1", "consul-server2", "consul-server3"]
}

6.5 Docker Compose部署 #

yaml
version: '3'
services:
  consul-server1:
    image: consul:1.17.0
    container_name: consul-server1
    command: agent -server -bootstrap-expect=3 -node=server1 -client=0.0.0.0 -ui
    ports:
      - "8500:8500"
    networks:
      - consul-net

  consul-server2:
    image: consul:1.17.0
    container_name: consul-server2
    command: agent -server -bootstrap-expect=3 -node=server2 -retry-join=consul-server1
    networks:
      - consul-net

  consul-server3:
    image: consul:1.17.0
    container_name: consul-server3
    command: agent -server -bootstrap-expect=3 -node=server3 -retry-join=consul-server1
    networks:
      - consul-net

networks:
  consul-net:
    driver: bridge

七、KV存储 #

7.1 使用KV存储 #

java
@RestController
public class KvController {
    
    @Autowired
    private ConsulClient consulClient;
    
    @GetMapping("/kv/{key}")
    public String getValue(@PathVariable String key) {
        Response<GetValue> response = consulClient.getKVValue(key);
        if (response.getValue() != null) {
            return response.getValue().getDecodedValue();
        }
        return null;
    }
    
    @PutMapping("/kv/{key}")
    public boolean setValue(@PathVariable String key, @RequestBody String value) {
        consulClient.setKVValue(key, value);
        return true;
    }
    
    @DeleteMapping("/kv/{key}")
    public boolean deleteValue(@PathVariable String key) {
        consulClient.deleteKVValue(key);
        return true;
    }
}

7.2 配置KV存储 #

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

八、配置详解 #

8.1 完整配置 #

yaml
spring:
  application:
    name: service-provider
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        enabled: true
        register: true
        deregister: true
        service-name: ${spring.application.name}
        instance-id: ${spring.application.name}:${server.port}
        health-check-path: /actuator/health
        health-check-interval: 10s
        health-check-timeout: 5s
        health-check-critical-timeout: 30s
        health-check-tls-skip-verify: false
        prefer-ip-address: true
        ip-address: ${IP_ADDRESS:127.0.0.1}
        port: ${server.port}
        scheme: http
        tags: 
          - version=1.0.0
          - author=team-a
        metadata:
          version: 1.0.0
        acl-token: 
        query-passing: true
        catalog-services-watch-delay: 10s
        catalog-services-watch-timeout: 5s
        heartbeat:
          enabled: false
          ttl-value: 30
          ttl-unit: s
          interval-ratio: 2.0
      config:
        enabled: true
        prefix: config
        default-context: application
        profile-separator: ','
        data-key: data
        format: YAML
        watch:
          enabled: true
          delay: 1000

8.2 配置项说明 #

配置项 默认值 说明
host localhost Consul服务器地址
port 8500 Consul服务器端口
enabled true 是否启用服务发现
register true 是否注册服务
service-name $ 服务名称
health-check-interval 10s 健康检查间隔
prefer-ip-address false 是否优先使用IP

九、多数据中心 #

9.1 多数据中心架构 #

text
┌─────────────────────────────────────────────────────────────┐
│                    多数据中心架构                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────────────────────────────────────────────┐  │
│   │                   数据中心 DC1                        │  │
│   │  ┌─────────┐  ┌─────────┐  ┌─────────┐             │  │
│   │  │ Server  │  │ Server  │  │ Server  │             │  │
│   │  └─────────┘  └─────────┘  └─────────┘             │  │
│   └─────────────────────────────────────────────────────┘  │
│                          │                                  │
│                     WAN Gossip                             │
│                          │                                  │
│   ┌─────────────────────────────────────────────────────┐  │
│   │                   数据中心 DC2                        │  │
│   │  ┌─────────┐  ┌─────────┐  ┌─────────┐             │  │
│   │  │ Server  │  │ Server  │  │ Server  │             │  │
│   │  └─────────┘  └─────────┘  └─────────┘             │  │
│   └─────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

9.2 配置多数据中心 #

json
{
  "datacenter": "dc1",
  "data_dir": "/opt/consul/data",
  "server": true,
  "bootstrap_expect": 3,
  "bind_addr": "0.0.0.0",
  "client_addr": "0.0.0.0",
  "ui": true,
  "retry_join": ["server1.dc1", "server2.dc1", "server3.dc1"],
  "retry_join_wan": ["server1.dc2", "server2.dc2", "server3.dc2"]
}

十、最佳实践 #

10.1 生产环境配置 #

yaml
spring:
  application:
    name: service-provider
  cloud:
    consul:
      host: ${CONSUL_HOST:localhost}
      port: ${CONSUL_PORT:8500}
      discovery:
        enabled: true
        register: true
        service-name: ${spring.application.name}
        instance-id: ${spring.application.name}:${server.port}
        health-check-path: /actuator/health
        health-check-interval: 10s
        health-check-timeout: 5s
        prefer-ip-address: true
        ip-address: ${IP_ADDRESS:}
        port: ${server.port}
        tags:
          - version=@project.version@
          - region=${REGION:default}
        acl-token: ${CONSUL_TOKEN:}

server:
  port: ${PORT:8001}

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics
  endpoint:
    health:
      show-details: when-authorized

10.2 注意事项 #

注意点 说明
集群节点 Server至少3个
网络延迟 节点间延迟应小于50ms
数据一致性 CP系统,保证强一致性
健康检查 合理配置检查间隔

十一、总结 #

11.1 核心要点 #

要点 说明
服务发现 支持DNS和HTTP接口
健康检查 多种检查方式
KV存储 分布式配置存储
多数据中心 支持跨数据中心
CP系统 保证强一致性

11.2 下一步 #

现在你已经掌握了Consul注册中心的使用,接下来让我们学习 服务调用,了解微服务间的通信方式!

最后更新:2026-03-28