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-5b6758e4159eJava配置管理
点击查看完整代码实现
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作为成熟的服务网格解决方案,凭借其丰富的功能特性、强大的多数据中心支持和完善的安全机制,为企业构建可靠的微服务基础设施提供了强有力的支撑。
