Consul从零到生产级:Agent、Gossip、Raft、Catalog、Health、DNS与Service Mesh
Consul 是面向服务网络的分布式控制面,核心能力包括服务注册发现、健康检查、KV、Session、DNS/HTTP查询、多数据中心和Service Mesh。它最容易被讲错的地方是把Gossip和Raft混成“Consul一致性算法”:Gossip负责成员关系和故障信息扩散,Raft负责Server集群内一致状态的排序与提交,两者解决的是不同问题。
本页从Agent、Catalog和Health对象开始,沿Provider注册、健康检查、Consumer DNS/HTTP查询、Blocking Query、Session锁、Connect mTLS、跨数据中心和生产恢复建立完整链路。
一、学习目标
- 区分Client Agent、Server Agent、LAN Gossip、WAN Gossip与Raft。
- 解释服务从本地Agent注册到Catalog可查询的完整过程。
- 区分Catalog存在、Health Passing和业务真正可用。
- 使用DNS、HTTP Health API和Blocking Query发现服务。
- 理解KV ModifyIndex、CAS、Transaction、Session和Lock Delay。
- 解释Session失效后为什么仍需要Fencing Token。
- 解释Consul Connect如何通过代理、证书和Intentions实现Service Mesh。
- 设计多数据中心发现、ACL/TLS和生产Runbook。
二、Consul适合什么场景
| 场景 | Consul能力 |
|---|---|
| VM/裸机服务发现 | Agent注册、Catalog、DNS/HTTP |
| 健康实例过滤 | HTTP/TCP/gRPC/TTL等Health Check |
| 多数据中心服务目录 | 每DC独立Server集群、WAN Federation或Peering |
| 少量控制面配置 | KV、Blocking Query、Watch |
| Leader选举和低频锁 | Session + KV acquire/release |
| Service Mesh | Connect、sidecar/Envoy、mTLS、Intentions |
不适合:
- 高频订单和业务流水。
- 大文件和日志。
- 把Health Passing当作所有业务依赖都健康。
- 用Session锁替代数据库唯一约束和幂等。
- 认为跨数据中心存在一个全球Raft集群。
三、Agent架构
flowchart TD
A["业务服务"] --> B["本机或同节点Consul Client Agent"]
B --> C["LAN Gossip成员池"]
B --> D["把注册、查询和RPC转发给Consul Server"]
D --> E["Server Leader和Raft集群"]
E --> F["Catalog、KV、ACL等一致状态"]
G["其他数据中心Server"] --> H["WAN Federation或Peering"]Client Agent
- 通常部署在每个工作节点。
- 接收本机服务注册和检查配置。
- 执行本地Health Check。
- 参与LAN Gossip。
- 把需要一致状态的RPC转发给Server。
- 可提供本地DNS和HTTP入口。
Server Agent
- 参与Raft选举和一致状态复制。
- 保存Catalog、KV、ACL等状态。
- 也参与LAN Gossip。
- 多数据中心传统WAN Federation中,Server还参与WAN Gossip。
业务应用可以直接访问Server API,但典型生产拓扑通过本地Client Agent降低Server连接压力并提供节点级能力。
四、Gossip和Raft严格区分
| 机制 | 参与者 | 保存/传播内容 | 一致性目标 |
|---|---|---|---|
| LAN Gossip | 同数据中心Client与Server Agent | 成员、地址、故障怀疑、事件 | 快速最终传播 |
| WAN Gossip | 传统多DC模式中的Server Agent | 数据中心Server成员和跨DC路由信息 | 最终传播 |
| Raft | 单数据中心Server投票成员 | Catalog、KV、ACL、Session等一致状态 | 多数派安全提交 |
Gossip成员列表不是Catalog的强一致事实源。节点被Gossip标记suspect/dead会影响Catalog和检查处理,但Catalog写入仍由Server Raft提交。
五、LAN Gossip、SWIM思想与Serf
Consul使用Serf构建成员通信,底层采用SWIM类故障检测和Gossip传播思想:
flowchart TD
A["Agent周期选择成员Ping"] --> B{"直接ACK是否成功"}
B -- "是" --> C["成员保持Alive"]
B -- "否" --> D["请求其他成员间接Ping"]
D --> E{"间接ACK是否成功"}
E -- "是" --> C
E -- "否" --> F["进入Suspect并传播怀疑"]
F --> G{"在怀疑窗口内是否反驳"}
G -- "是" --> C
G -- "否" --> H["判定Failed/Dead并继续传播"]为什么先Suspect而不是立刻Dead:
- UDP丢包不等于进程死亡。
- 单节点网络视角可能错误。
- 间接探测降低单路径故障误判。
- 怀疑窗口允许活节点传播更高incarnation信息反驳。
Gossip不是每次状态变化都由中心Server广播,成员相互交换摘要并最终扩散,具有短暂不一致窗口。
六、Server Raft集群
单个数据中心通常部署3或5个Consul Server:
3 Server → Quorum 2 → 容忍1个投票Server故障
5 Server → Quorum 3 → 容忍2个投票Server故障一致写流程:
flowchart TD
A["Client Agent发送注册/KV/Session请求"] --> B["Server Leader追加Raft日志"]
B --> C["复制给Follower Server"]
C --> D{"获得多数派确认"}
D -- "否" --> E["无法提交,等待或重新选举"]
D -- "是" --> F["提交并Apply到状态机"]
F --> G["Catalog/KV/Session状态更新"]Server失去Quorum后,LAN Gossip仍可能看到成员,但Catalog一致写、Session等依赖Raft的能力会受阻。不能用 consul members 全Alive证明Raft健康。
七、查询一致性模式
Consul HTTP查询常见一致性选项包括默认、consistent和stale,精确实现和默认优化随版本:
- 默认模式通常由Leader/Leader Lease等机制提供较强一致视图,在极端领导权窗口中的语义应按版本文档理解。
consistent要求Leader确认仍具有Quorum,提供最强线性一致读取,但延迟和可用性成本更高。stale允许任意Server从本地状态读取,不要求Leader,可在无Leader时继续返回但可能陈旧。
不要把DNS查询、Agent缓存和HTTP consistent视为完全相同的读路径。所有权裁决和锁状态查询应使用有明确强一致保证的API;服务发现可以按可用性目标接受短暂陈旧。
八、Node、Service、Service Instance与Check
| 对象 | 例子 | 说明 |
|---|---|---|
| Node | vm-10-0-0-11 | 运行Agent的节点身份 |
| Service | stock-api | 逻辑服务名 |
| Service Instance | stock-api-a | 某节点上的具体实例ID、地址、端口、Tags、Meta |
| Check | service:stock-api-a | 节点或服务健康检查 |
同一Node可注册多个Service Instance;同一Service可跨多个Node。Service ID在Agent/Node作用域中需要稳定唯一,不能只用服务名导致同节点多个实例互相覆盖。
九、Provider注册完整流程
flowchart TD
A["Provider启动并通过readiness"] --> B["向本地Agent注册Service"]
B --> C["Agent保存本地服务和Check定义"]
C --> D["Agent把注册同步给Server"]
D --> E["Leader经Raft提交Catalog变更"]
E --> F["Catalog出现Service Instance"]
F --> G["Agent开始执行Health Check"]
G --> H["Health状态经Server更新"]
H --> I["DNS/HTTP健康查询可返回实例"]注册成功和健康Passing是两个状态:实例先进入Catalog,检查可能仍initializing、warning或critical。Consumer应查询健康接口或使用只返回健康实例的DNS语义,而不是直接读取Catalog所有注册。
9.1 Agent HTTP注册示例
{
"ID": "stock-api-a",
"Name": "stock-api",
"Address": "10.0.0.11",
"Port": 20880,
"Tags": ["v2", "zone-a"],
"Meta": {
"protocol": "dubbo",
"build": "20260718.1"
},
"Check": {
"HTTP": "http://10.0.0.11:8080/actuator/health/readiness",
"Interval": "10s",
"Timeout": "2s",
"DeregisterCriticalServiceAfter": "10m"
}
}注册命令:
curl --request PUT \
--header "X-Consul-Token: ${CONSUL_HTTP_TOKEN}" \
--data @stock-service.json \
http://127.0.0.1:8500/v1/agent/service/registerToken不应写入仓库或Shell历史;生产使用HTTPS和Secret注入。
十、Health Check类型和边界
| 类型 | 检查什么 | 风险 |
|---|---|---|
| HTTP | 状态码、可选Body/TLS | Endpoint可能依赖过多下游,抖动扩散 |
| TCP | 端口能否建立连接 | 端口开不等于业务可用 |
| gRPC | gRPC健康协议 | 服务必须实现标准Health |
| TTL | 应用定期主动Pass | 应用卡死或上报线程异常会Critical |
| Script | 执行本地脚本 | 安全、资源和命令注入风险 |
| Docker等集成 | 容器状态/命令,依版本 | Agent权限过大风险 |
状态通常包括Passing、Warning、Critical。健康查询是否包含Warning要按API和业务策略明确,不能只写“健康”而不定义。
10.1 TTL Check不是Session Lease
TTL Check要求应用在TTL内调用Pass/Warning/Fail更新检查状态;超时后Check进入Critical。它主要影响健康筛选,不自动删除任意KV,也不是Consul Session TTL。
应用进程正常但上报线程阻塞,会误Critical;上报线程正常但业务线程池死锁,也可能继续Passing。最佳实践是让检查覆盖必要的业务readiness,但避免把所有非核心下游都绑定成硬失败。
10.2 Critical后自动注销
DeregisterCriticalServiceAfter可在持续Critical后从Catalog删除服务,最小值和实际清理节奏依版本。它不是精确定时器;设置过短会因网络/依赖抖动频繁注销,恢复后还需Agent重新注册。
十一、Catalog查询与Health查询区别
| API | 返回内容 | 是否自动过滤健康 |
|---|---|---|
| Catalog Service | 注册的服务实例 | 通常不代表健康 |
| Health Service | 实例及聚合Check | 可用passing=true只取Passing |
| Agent Services | 本Agent本地注册 | 不是整个数据中心全局目录 |
生产Consumer通常使用Health API或Consul DNS,而不是Catalog API直接负载均衡。
十二、DNS服务发现
Consul Agent提供DNS接口,典型名称:
stock-api.service.consul
stock-api.service.dc1.consul常见记录:
- A/AAAA返回实例地址。
- SRV返回主机、端口和优先级/权重信息。
- Tag/Prepared Query可提供更复杂选择,语法依版本。
dig @127.0.0.1 -p 8600 stock-api.service.consul A
dig @127.0.0.1 -p 8600 stock-api.service.consul SRV12.1 DNS缓存边界
DNS结果受:
- Consul Agent缓存。
- 递归DNS缓存。
- 操作系统缓存。
- JVM DNS缓存。
- 应用连接池。
实例下线后,旧地址可能在各层TTL内继续存在。Java项目应检查JVM DNS缓存策略和HTTP/RPC客户端是否在长连接池中继续复用旧连接,不能认为Consul Health变Critical后所有请求立刻停止。
十三、HTTP Health API发现
curl \
--header "X-Consul-Token: ${CONSUL_HTTP_TOKEN}" \
'https://consul.service.local:8501/v1/health/service/stock-api?passing=true'响应同时包含Node、Service和Checks。客户端应:
- 校验HTTP和JSON。
- 只接受目标DC、Tag、Meta和协议兼容实例。
- 构建完整新快照后原子替换。
- 复用未变化连接,销毁移除实例。
- 控制空结果策略,避免瞬时错误清空目录。
十四、Blocking Query原理
轮询每秒请求会让Server承受大量无变化查询。Consul Blocking Query使用响应索引:
- 首次请求返回数据和
X-Consul-Index=R。 - 下一次请求带
index=R&wait=5m。 - 若相关状态未变化,Server挂起请求直到变化或wait超时。
- 变化后返回新数据和新Index。
flowchart TD
A["Client首次查询得到Index R"] --> B["请求index=R并设置wait"]
B --> C{"相关状态是否变化"}
C -- "否" --> D["Server挂起到超时"]
D --> B
C -- "是" --> E["返回新快照和Index R2"]
E --> F["Client原子替换本地目录"]
F --> B14.1 Blocking Query恢复边界
- wait超时返回不一定表示数据变化,比较Index和内容。
- Index可能因集群恢复/实现语义变化而回退或异常,客户端应在Index不前进或变小的情况下重建全量状态,而不是永久等待。
- HTTP连接中断后使用最后已应用Index重新查询。
- Server会为wait加入随机抖动,避免大量查询同一时刻超时;客户端仍应退避。
- 不要在一个请求上设置无限wait并假定网络永不断开。
较新API可能使用内容Hash等Blocking机制,具体Header和参数按目标Endpoint文档确认。
14.2 curl实验
curl --include \
'http://127.0.0.1:8500/v1/health/service/stock-api?passing=true'
curl --include \
'http://127.0.0.1:8500/v1/health/service/stock-api?passing=true&index=123&wait=5m'生产需要ACL Token和TLS,Index 123应来自第一次响应,不能写死。
十五、Consumer本地快照
无论DNS还是HTTP,Consumer最终都需要线程安全地址快照:
Consul返回完整健康实例集
↓
按Tag/Zone/Protocol过滤
↓
复用未变化客户端连接
↓
创建新增Invoker/Client
↓
原子发布不可变List
↓
延迟销毁已移除连接这和Dubbo RegistryDirectory思想相同。Consul只提供发现控制面,不转发普通业务RPC,除非使用Connect代理数据面。
十六、Consul KV和Index
KV响应常包含:
- Key。
- Base64编码Value。
- CreateIndex。
- ModifyIndex。
- LockIndex。
- Session。
- Flags。
CreateIndex表示首次创建的Raft索引位置,ModifyIndex表示最近修改位置。它们不是时间戳。
16.1 CAS更新
cas=0 → 仅Key不存在时创建
cas=N → 仅ModifyIndex等于N时更新curl --request PUT \
--data 'timeout=1500' \
'http://127.0.0.1:8500/v1/kv/config/order?cas=123'返回false表示比较失败,应重新GET并合并,不得改成无条件PUT覆盖。
16.2 KV Transaction
Consul Transaction API可原子执行多个KV/Node/Service/Check相关操作,支持检查索引、设置、删除等动词;单Txn操作数有实现上限,常见版本为有限数量。它只覆盖Consul一致状态,不能原子包含MySQL和MQ。
十七、Session是什么
Consul Session把Node、Health Check、TTL和KV锁所有权组合起来。Session可配置:
- 关联Node。
- 关联Checks。
- TTL和续约。
Behavior=release或delete。- Lock Delay。
Session失效原因可能包括:
- TTL未续约。
- 关联Node/Check进入失效条件。
- 主动Destroy。
- Catalog中的Node被移除。
17.1 release与delete
release:释放KV的Session绑定,Key和值保留。delete:Session失效时删除持有的Key。
选择取决于锁记录是否需要保留诊断信息。两者都不保证外部业务事务回滚。
17.2 Lock Delay
Session失效后,Consul可在一段Lock Delay内阻止同Key立即被新Session取得,用于减少旧Leader暂停/网络延迟带来的快速双执行窗口。它是缓冲,不是Fencing:Delay结束后旧客户端仍可能恢复并写外部资源。
十八、KV锁Acquire/Release
概念流程:
flowchart TD
A["创建Session"] --> B["PUT key?acquire=sessionId"]
B --> C{"KV当前是否可取得"}
C -- "否" --> D["返回false并Blocking Query等待"]
C -- "是" --> E["KV记录Session并增加LockIndex"]
E --> F["执行业务并携带Fencing Token"]
F --> G["PUT key?release=sessionId"]
G --> H["释放成功或Session失效自动处理"]Acquire不是普通CAS的替代:必须校验返回布尔值。Release只有持有Session才能成功;ConnectionLoss时结果可能UNKNOWN,应查询KV的Session和LockIndex。
十九、LockIndex与Fencing Token
KV锁被新Session成功Acquire时,LockIndex用于表达所有权授予次数,可作为构造Fencing Token的候选。外部资源必须原子记录并拒绝旧Token:
UPDATE scheduler_owner
SET owner = :owner,
fencing_token = :token
WHERE job_name = :job
AND fencing_token < :token;边界:
- Token必须来自同一锁Key的单调所有权序列。
- Key删除重建、集群恢复和跨DC不能未经分析直接比较。
- Session失效后客户端必须停止。
- 相同Token重试仍需业务幂等。
二十、Prepared Query
Prepared Query可以预定义服务查询、Failover、Near排序等策略,让DNS/HTTP通过查询名执行较复杂发现。功能细节、跨DC行为和部分高级能力具有版本/版本类型边界。
使用原则:
- 查询定义要版本化和审计。
- Failover不能掩盖数据协议不兼容。
- 跨DC回退要评估延迟、数据主权和下游容量。
- 客户端仍需超时、熔断和幂等。
二十一、多数据中心原理
每个数据中心有独立Server Raft集群和Catalog,不是全球所有Server组成一个Raft Quorum:
flowchart TD
A["DC1 Server Raft Cluster"] --> B["DC1 Catalog"]
C["DC2 Server Raft Cluster"] --> D["DC2 Catalog"]
A --> E["WAN Federation或Consul Peering"]
C --> E
F["DC1 Client查询DC2服务"] --> A
A --> E
E --> C传统WAN Federation使用Server WAN Gossip和请求转发;较新版本提供Cluster Peering等连接方式,拓扑、安全和传递性不同,应按版本选择。
网络分区时DC1本地Raft可继续服务本地Catalog,但跨DC查询/转发可能失败或使用陈旧信息。跨DC服务调用还受WAN延迟和数据面网络影响。
二十二、Consul Connect Service Mesh
Connect把身份和授权从IP提升到服务身份:
flowchart TD
A["服务A"] --> B["本地Sidecar Proxy"]
B --> C["mTLS连接"]
C --> D["服务B Sidecar Proxy"]
D --> E["服务B"]
F["Consul控制面"] --> G["下发证书、发现、Intentions和代理配置"]
G --> B
G --> D核心组件:
- Connect CA签发服务证书。
- 服务注册声明sidecar proxy。
- Envoy等代理建立mTLS。
- Intentions决定服务身份之间是否允许通信。
- Consul通过xDS等机制下发动态代理配置,具体协议/版本演进。
22.1 Service Mesh没有消除业务问题
- mTLS验证服务身份,不验证订单权限。
- 代理重试可能重复写,接口仍需幂等。
- 代理超时和应用超时要共享总预算。
- 两侧代理增加延迟、CPU和排障层次。
- 控制面短暂不可用时代理可能继续旧配置,配置年龄要监控。
- Intentions允许不代表Provider健康。
二十三、安全体系
| 层 | 机制 | 目的 |
|---|---|---|
| Gossip | Gossip Encryption Key | 防止未授权成员读取/注入Gossip流量 |
| RPC/HTTP | TLS | 加密并认证Agent/Server/API |
| ACL | Token和Policy | 限制Service、Node、KV、Session等操作 |
| Mesh | Connect CA、mTLS、Intentions | 服务身份和服务间授权 |
Gossip加密不等于HTTP/RPC TLS;ACL Token也不等于传输加密。生产应启用ACL默认拒绝、最小Policy、Token轮换和审计,避免使用全局Management Token给业务应用。
二十四、常见端口
| 默认端口 | 作用 |
|---|---|
| 8300 | Server RPC |
| 8301 TCP/UDP | LAN Serf Gossip |
| 8302 TCP/UDP | WAN Serf Gossip |
| 8500 | HTTP API |
| 8501 | HTTPS API,需配置 |
| 8502 | gRPC/xDS等,版本相关 |
| 8600 TCP/UDP | DNS |
端口可配置,云防火墙和NetworkPolicy必须区分Client、Server、LAN/WAN和管理访问,不能全部暴露公网。
二十五、生产部署
- 每DC部署3或5个Server并分散故障域。
bootstrap_expect只用于初始引导预期Server数,形成集群后不要把bootstrap模式当日常修复工具。- Server使用持久低延迟磁盘。
- Client Agent靠近业务服务。
- 配置retry_join或云自动发现时限制身份和范围。
- 滚动升级一次一个Server,等Raft健康再继续。
- 使用Autopilot健康检查和清理能力时理解版本与配置,不自动删除未经确认的Server。
二十六、JDK 8 Demo:Catalog Index与Blocking Query
下面的无依赖Demo模拟首次快照、Index变化和Blocking Query等待。
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class ConsulBlockingQueryDemo {
static final class Snapshot {
final long index;
final List<String> healthyInstances;
Snapshot(long index, List<String> healthyInstances) {
this.index = index;
this.healthyInstances = healthyInstances;
}
}
static final class Catalog {
private long index;
private final Map<String, Boolean> passing = new LinkedHashMap<String, Boolean>();
synchronized void update(String instance, boolean isPassing) {
passing.put(instance, isPassing);
index++;
notifyAll();
}
synchronized Snapshot blockingQuery(long waitIndex, long waitMillis)
throws InterruptedException {
long deadlineNanos = System.nanoTime()
+ TimeUnit.MILLISECONDS.toNanos(waitMillis);
while (index == waitIndex) {
long remainingNanos = deadlineNanos - System.nanoTime();
if (remainingNanos <= 0L) break;
long remainingMillis = TimeUnit.NANOSECONDS.toMillis(remainingNanos);
wait(Math.max(1L, remainingMillis));
}
List<String> result = new ArrayList<String>();
for (Map.Entry<String, Boolean> entry : passing.entrySet()) {
if (Boolean.TRUE.equals(entry.getValue())) result.add(entry.getKey());
}
return new Snapshot(index, Collections.unmodifiableList(result));
}
}
public static void main(String[] args) throws Exception {
final Catalog catalog = new Catalog();
catalog.update("10.0.0.11:20880", true);
Snapshot first = catalog.blockingQuery(0L, 1L);
System.out.println("firstIndex=" + first.index + ", instances=" + first.healthyInstances);
Thread updater = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100L);
catalog.update("10.0.0.12:20880", true);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
});
updater.start();
Snapshot changed = catalog.blockingQuery(first.index, 1000L);
updater.join();
System.out.println("changedIndex=" + changed.index + ", instances=" + changed.healthyInstances);
}
}预期输出:
firstIndex=1, instances=[10.0.0.11:20880]
changedIndex=2, instances=[10.0.0.11:20880, 10.0.0.12:20880]真实Consul Index来自Raft/Catalog查询响应,不能用客户端本地计数替代;Demo只解释等待和快照发布模型。
二十七、运维命令与证据
consul members
consul members -wan
consul operator raft list-peers
consul operator autopilot health
consul catalog services
consul snapshot save consul.snapAPI证据:
curl -H "X-Consul-Token: ${CONSUL_HTTP_TOKEN}" \
https://127.0.0.1:8501/v1/status/leader
curl -H "X-Consul-Token: ${CONSUL_HTTP_TOKEN}" \
https://127.0.0.1:8501/v1/operator/autopilot/health命令名称、ACL要求和输出字段随版本变化,生产先用-help和目标版本文档确认。
二十八、关键监控指标
Gossip
- LAN/WAN成员Alive/Suspect/Failed。
- Gossip消息、probe失败、队列。
- 成员频繁Flap。
Raft和Server
- 是否存在Leader、Leader变化。
- Raft commit/apply延迟、last contact。
- Server RPC和请求队列。
- Autopilot健康。
- Snapshot、磁盘和GC。
Catalog与Health
- Service/Node/Check数量。
- Passing/Warning/Critical分布。
- 注册/注销速率。
- Blocking Query数量和等待时间。
- DNS/HTTP查询延迟与空结果率。
- Session数量、失效率和锁等待时间。
Mesh
- 证书过期时间和轮换失败。
- xDS配置版本/年龄。
- mTLS握手失败。
- Intention拒绝和代理上游健康。
二十九、Runbook:Server无Leader
consul members只证明LAN成员视图,继续检查Raft peers。- 确认Server可达数达到Quorum。
- 检查8300 RPC和LAN网络。
- 检查TLS证书、ACL不是Raft Peer本身的唯一问题,但RPC TLS会影响通信。
- 检查Server磁盘、fsync、CPU和GC。
- 检查是否同时重启/移除多数Server。
- 不要对多个Server同时启用bootstrap重新建集群。
三十、Runbook:成员频繁Suspect/Failed
- 检查8301 TCP/UDP双向连通。
- 检查丢包、MTU、NAT和安全组。
- 检查Agent CPU、GC和宿主机暂停。
- 对比多节点视角,区分局部故障和真实离线。
- 检查Gossip Encryption Key是否一致。
- 不要仅通过放大怀疑超时长期掩盖网络问题。
三十一、Runbook:服务已注册但Consumer发现不到
- 在Provider本地Agent查Service是否注册。
- 查Catalog是否已经经Raft提交。
- 查聚合Health Check是Passing、Warning还是Critical。
- 检查
passing=true、Tag、Meta、DC和Prepared Query条件。 - DNS场景查8600、递归DNS/JVM缓存和TTL。
- HTTP场景查Blocking Index、ACL Token和本地快照。
- 最后验证Consumer到Provider业务网络。
三十二、Runbook:地址下线后仍被调用
- Check变Critical到Catalog/查询传播有延迟。
- DNS和JVM缓存仍保留旧地址。
- Consumer连接池复用旧长连接。
- Consumer使用
stale读或本地快照未刷新。 - Provider被强杀但检查间隔尚未到。
DeregisterCriticalServiceAfter尚未清理。
用被动连接失败、超时和熔断缩短影响,不要只依赖注册中心推送。
三十三、Runbook:Session锁失效或双Leader
- 查询KV Session、LockIndex和Session详情。
- 检查关联Node/Check为何失效。
- 检查TTL Renew、网络和Agent暂停。
- 检查Lock Delay和新Session获取时间。
- 确认旧任务在Session失效后停止。
- 查看外部资源接受的最大Fencing Token。
- 对账重复任务,不要只删除KV后重新抢锁。
三十四、Runbook:Blocking Query不更新或请求暴涨
- 确认上次Index来自正确Endpoint和Query。
- Index回退/为0时执行全量重建。
- wait超时后不要立即无抖动重连。
- 检查代理/LB的HTTP idle timeout是否小于wait。
- 检查大量Consumer是否使用短wait造成轮询。
- 比较Catalog Index变化与本地applied Index。
三十五、Runbook:跨DC发现失败
- 本地DC Catalog和Raft是否健康。
- WAN members或Peering状态。
- Server间8302/相关Peering端口、TLS和ACL。
- 目标DC服务和Health。
- Prepared Query Failover规则。
- 跨DC数据面路由、延迟和防火墙。
三十六、Snapshot备份与恢复
Consul Server Snapshot包含Raft一致状态,应使用官方snapshot命令/API并保留:
- Consul精确版本。
- Server配置和数据中心名。
- Gossip Encryption Key。
- TLS CA/证书。
- ACL bootstrap与恢复材料。
- Connect CA相关密钥保护。
Restore可能覆盖Catalog、KV、ACL和Session相关状态,临时服务/Agent会在恢复后重新同步。必须在隔离环境演练,防止旧集群和恢复集群同时对外提供冲突控制面。
三十七、Consul、Nacos、Eureka、etcd和ZooKeeper对比
| 组件 | 核心能力 | 健康模型 | 多DC/云原生特点 |
|---|---|---|---|
| Consul | Agent、Catalog、Health、DNS、KV、Mesh | 主动Check丰富 | 多DC、Connect成熟 |
| Nacos | 服务发现和配置 | 临时/持久实例、客户端/Server检查依版本 | Spring Cloud Alibaba集成 |
| Eureka | 应用级注册发现 | Client续约、Server剔除、自我保护 | Netflix/Spring Cloud存量 |
| etcd | 强一致MVCC KV、Watch、Lease、Txn | Lease为主,健康需上层实现 | Kubernetes控制面 |
| ZooKeeper | znode、Session、Watch、Recipe | Session临时节点 | 传统Dubbo、协调Recipe |
不能只按“CP/AP”一列选型。要比较服务模型、检查方式、客户端生态、配置、跨DC、运维和数据面治理。
三十八、常见错误及后果
| 错误 | 后果 |
|---|---|
| Gossip就是Consul一致性协议 | 无法解释Catalog提交和Quorum故障 |
| members全Alive代表Raft健康 | 可能仍无Leader、无法写 |
| Catalog有实例就可调用 | Critical实例进入流量 |
| TTL Check等于Session TTL | 错误理解删除和锁所有权 |
| DNS更新后JVM立即丢旧地址 | 缓存和长连接继续调用旧实例 |
| Blocking Query每次短wait无退避 | Server请求风暴 |
| Session锁不需要Fencing | 暂停旧Leader覆盖新任务 |
| Gossip加密等于API TLS | HTTP/RPC仍可能明文 |
| 所有DC组成一个Raft集群 | 错误设计Quorum和故障域 |
| Mesh重试能提高写可靠性 | 重复副作用和故障放大 |
三十九、面试标准回答
Consul通常由每节点Client Agent和每数据中心3/5个Server组成。LAN Gossip使用Serf/SWIM类机制传播成员和故障怀疑,Server Raft则一致提交Catalog、KV、ACL和Session,两者不能混为一个协议。Provider向本地Agent注册Service和Check,Agent同步到Server Catalog;Consumer通过DNS或Health HTTP查询Passing实例。HTTP Blocking Query使用X-Consul-Index和wait避免高频轮询,客户端收到完整快照后原子替换。TTL Check只更新健康状态,Session则可关联Node/Checks/TTL并用于KV acquire锁;Session失效和Lock Delay仍不能阻止暂停旧客户端写外部资源,因此必须用LockIndex等单调Token做Fencing。多数据中心各自有独立Raft集群,通过WAN Federation或Peering互联;Connect再通过sidecar、mTLS、证书和Intentions提供Service Mesh。
四十、关联知识点
本章小结
Consul的完整链路是“Gossip维护成员视图 → Agent注册和执行Health Check → Server Raft提交Catalog → DNS/HTTP/Blocking Query发现健康实例 → Session/KV提供协调 → Connect下发mTLS数据面配置”。真正掌握它必须同时理解Gossip短暂不一致、Raft Quorum、DNS缓存、检查误判、Session失效和Mesh代理重试边界。
