深入理解 etcd:Kubernetes 的分布式基石

深入理解 etcd:Kubernetes 的分布式基石

引言

在 Kubernetes(K8s)集群中,etcd 扮演着独一无二且至关重要的角色——它是集群状态的唯一真实来源(Single Source of Truth)。所有关于集群配置、期望状态、实际状态的数据都存储在 etcd 中。理解 etcd 的工作原理、特性和最佳实践,对于管理和维护一个稳定、高效的 Kubernetes 集群至关重要。本文将深入探讨 etcd 的核心概念、Raft 一致性协议、存储机制、Watch 机制、高可用部署、在 Kubernetes 中的具体应用、性能优化及故障排查。

1. 什么是 etcd?

etcd 是一个由 CoreOS(现隶属于 Red Hat)开发的开源、分布式、强一致性的键值存储系统。它专为分布式系统设计,用于可靠地存储关键数据。

核心特性:

  • 简单接口: 提供基于 gRPC 的 API(v3)以及兼容 HTTP+JSON 的网关,易于集成和使用(如 etcdctl)。
  • 键值存储: 数据以键值对形式存储,支持按 Key 或 Key 前缀范围查询。
  • 监听机制 (Watch): 客户端可以监听(Watch)指定的 Key 或 Key 前缀范围,当数据发生变化时获得实时通知。这是 Kubernetes 控制器模型的基础。
  • 基于 Raft 的一致性: 使用 Raft 协议保证集群中多个节点数据的一致性和高可用性。即使部分节点故障,集群仍能正常工作(需要超过半数节点存活)。
  • 安全性: 支持 TLS 客户端证书认证,确保通信安全。
  • 事务支持: 支持原子性的 Compare-and-Swap (CAS) 和 Compare-and-Delete (CAD) 操作,可用于实现分布式锁、领导者选举等。
  • 多版本并发控制 (MVCC): 每个 Key 的修改都会创建一个新版本(Revision),支持查询历史版本数据。

2. etcd 的核心功能与应用场景

etcd 的核心功能使其在分布式系统中应用广泛:

  • 服务发现与注册: 服务实例启动时将其信息(如 IP、端口)注册到 etcd 的特定 Key 下,并设置 TTL(租约)。服务消费者监听这些 Key 来发现可用的服务实例。实例通过续约 TTL 来表明其存活状态。
  • 配置共享: 将应用的配置信息存储在 etcd 中,应用实例启动时读取配置,并监听配置 Key 的变化以实现动态更新。
  • 分布式协调:
    • 分布式锁: 利用 Lease(租约)和原子操作(如事务)实现分布式锁,确保同一时间只有一个进程能访问共享资源。
    • 领导者选举: 多个实例竞争写入一个特定的 Key(通常带有 Lease),成功写入者成为 Leader。
  • Kubernetes 集群状态存储: 这是 etcd 最重要的应用场景。存储所有 Kubernetes 对象(Pods, Services, Deployments 等)的定义和状态。API Server 是唯一直接与 etcd 交互的 K8s 组件。

服务注册与发现示例(Mermaid 流程图):

graph LR
    subgraph 服务注册
        A[服务提供者] -- 注册服务信息 (Key: /services/my-app/instance-1, Value: ip:port, Lease: ttl=10s) --> E[etcd]
        A -- 定期续约 Lease --> E
    end

    subgraph 服务发现
        C[服务消费者] -- Watch /services/my-app/ 前缀 --> E
        E -- 返回当前实例列表 --> C
        E -- 当实例增/删/过期时通知 --> C
    end

    subgraph 服务调用
        C -- 根据获取的列表 --> G[服务提供者实例]
    end

配置共享示例(Mermaid 流程图):

graph LR
    subgraph 配置发布
        A[管理员/CI/CD] -- 更新配置 (Key: /config/app/db_url, Value: new_url) --> E[etcd]
    end

    subgraph 配置订阅与应用
        C[应用实例] -- Watch /config/app/db_url --> E
        E -- 配置变更通知 --> C
        C -- 应用新配置 --> C
    end

3. 深入理解 Raft 一致性协议

Raft 是一种旨在比 Paxos 更易于理解和实现的分布式一致性算法。etcd 使用 Raft 来确保集群数据的一致性和容错性。

核心概念:

  • 角色:
    • Leader(领导者): 集群中同一时间只有一个 Leader。负责处理所有客户端写请求,并将日志条目复制给 Follower。定期向 Follower 发送心跳以维持领导地位。
    • Follower(跟随者): 被动接收 Leader 的日志条目和心跳。如果超时未收到 Leader 心跳,会转变为 Candidate并发起选举。响应 Candidate 的投票请求。
    • Candidate(候选者): 在选举期间的角色。向其他节点请求投票,如果获得超过半数节点的投票,则成为新的 Leader。
    • Learner(学习者): v3.4 新增角色。只接收 Leader 的日志复制,不参与选举投票,也不计入 Quorum(法定人数)。用于在不影响集群写性能和可用性的情况下扩展集群或替换节点。
  • Term(任期): 一个单调递增的数字,表示一个 Leader 的任期。每次选举成功都会进入一个新的 Term。Term 用于检测过期的 Leader 或 Candidate。
  • Log Replication(日志复制): Leader 将客户端请求(命令)封装成日志条目,追加到自己的日志中,然后并行地发送给所有 Follower。当 Leader 收到超过半数 Follower 的成功响应后,该日志条目被视为已提交 (Committed)。Leader 会通知 Follower 提交相应的日志条目。只有已提交的日志条目才能被应用到状态机(即 KV 存储)。
  • Safety(安全性): Raft 通过以下机制保证安全性:
    • Election Safety: 每个 Term 最多只有一个 Leader 被选举出来。
    • Leader Append-Only: Leader 只能追加日志,不能覆盖或删除。
    • Log Matching: 如果两个日志在某个索引位置具有相同的 Term,那么它们在该索引之前的所有日志条目都相同。
    • Leader Completeness: 如果一个日志条目在某个 Term 被提交,那么它将出现在所有更高 Term 的 Leader 的日志中。
    • State Machine Safety: 如果一个节点已经将某个索引的日志条目应用到其状态机,那么其他节点不能在该索引应用不同的日志条目。
  • Leader Election(领导者选举):
    1. Follower 在 election timeout(通常是随机化的,如 150-300ms)内未收到 Leader 心跳,则增加当前 Term,转变为 Candidate。
    2. Candidate 投票给自己,并向其他节点发送 RequestVote RPC。
    3. 其他节点收到 RequestVote 后,如果在当前 Term 尚未投票,并且 Candidate 的日志至少和自己一样新(比较最后日志条目的 Term 和 Index),则投票给该 Candidate。
    4. Candidate 若收到超过半数节点的投票,则成为 Leader。
    5. 若选举超时仍未选出 Leader(可能发生选票分裂),则 Candidate 增加 Term,开始新一轮选举。
    6. Leader 选举成功后,立即向所有 Follower 发送心跳,确立领导地位。

Raft 协议流程(Mermaid 流程图):

graph TD
    Client[客户端] -- 写请求 --> Leader
    Leader -- 1. 追加日志条目 (uncommitted) --> Log_Leader[Leader 本地日志]
    Log_Leader -- 2. 并行发送 AppendEntries RPC --> Follower1 & Follower2
    Follower1 -- 3. 接收并追加日志 (uncommitted) --> Log_F1[Follower1 日志]
    Follower2 -- 3. 接收并追加日志 (uncommitted) --> Log_F2[Follower2 日志]
    Log_F1 -- 4. 发送成功 ACK --> Leader
    Log_F2 -- 4. 发送成功 ACK --> Leader
    Leader -- 5. 收到多数 ACK (包括自己) --> MarkCommitted{将日志标记为 Committed}
    MarkCommitted -- 6. 应用到状态机 --> StateMachine_L[Leader 状态机 (KV Store)]
    MarkCommitted -- 7. 响应客户端 --> Client
    Leader -- 8. 下次心跳/AppendEntries 通知 Follower --> Follower1 & Follower2
    Follower1 -- 9. 收到提交通知 --> Apply_F1{Follower1 应用日志到状态机}
    Follower2 -- 9. 收到提交通知 --> Apply_F2{Follower2 应用日志到状态机}
    Apply_F1 --> StateMachine_F1[Follower1 状态机]
    Apply_F2 --> StateMachine_F2[Follower2 状态机]

WAL 日志 (Write-Ahead Log):

etcd 将 Raft 日志持久化到磁盘上的 WAL 文件中。在将变更应用到内存状态(KV 存储)之前,必须先确保对应的 Raft 日志条目已成功写入 WAL。这保证了即使节点崩溃重启,也能通过回放 WAL 日志来恢复到崩溃前的状态,确保数据不丢失。WAL 文件是顺序写入的,通常性能较好。

WAL 日志条目主要包含:

  • Type: 日志类型(如普通条目、配置变更条目)。
  • Term: 该条目所属的 Leader 任期。
  • Index: 该条目的日志索引,单调递增。
  • Data: 实际的客户端请求数据(序列化格式)。

4. etcd 的存储核心:MVCC 与 BoltDB

etcd v3 采用了多版本并发控制(MVCC)模型,并使用 BoltDB 作为其底层的持久化存储引擎。

MVCC (Multi-Version Concurrency Control):

  • Revision(版本号): etcd 不直接修改 Key 的 Value,而是每次修改(Put、Delete)都创建一个新的 Key-Value 版本。每个版本都有一个全局唯一的、单调递增的 Revision 号。
    • Revision 构成: 一个 Revision 由两部分组成:main revisionsub revision
      • main revision: 每次 etcd 事务(可能包含多个操作)提交时递增 1。
      • sub revision: 在同一个事务内,每次操作(如 Put)递增 1。
    • 作用: MVCC 使得读操作可以访问某个特定 Revision 的数据快照,而不会被并发的写操作阻塞。同时,它也是实现 Watch 机制和历史数据查询的基础。
  • Tombstone(墓碑标记): 删除操作并不会立即移除数据,而是创建一个带有特殊标记(Tombstone)的新版本。被标记的数据在后续的 Compaction(压缩)过程中才会被物理删除。

BoltDB:

  • 是一个嵌入式的、事务性的、基于 B+ Tree 的键值存储库。
  • etcd 使用 BoltDB 来持久化存储 KV 数据和 Raft 日志(WAL 独立存储)。
  • 在 BoltDB 中,etcd 存储的主要内容是一个 B+ Tree,其 Key 是 RevisionValue 是 etcd 自身的 Key-Value 数据(序列化后的结构)。
    1
    2
    3
    // BoltDB 中的简化结构
    Bucket "key":
    Key (Revision) -> Value (LeaseID, etcd_Key, etcd_Value, CreateRevision, ModRevision, Version, Tombstone_flag)
  • 这种结构使得通过 Revision 查询特定版本的数据非常高效。

内存索引 (TreeIndex):

  • 为了加速 Key 的查询(用户关心的是 Key,而不是 Revision),etcd 在内存中维护了一个基于 B-Tree 的索引(treeIndex)。
  • 这个索引 Key 是用户指定的 etcd KeyValue 指向 BoltDB 中该 Key 的最新 Revision 或历史 Revision 信息。
  • 当查询某个 Key 时,先通过 treeIndex 找到对应的 Revision,再通过 Revision 去 BoltDB 中获取实际的 Value。

存储流程示意图:

graph LR
    subgraph "etcd Server (Leader)"
        A[gRPC/HTTP Request] --> B{API Layer}
        B -- Write Request --> C[Raft Module]
        C -- 1. Propose --> C
        C -- 2. Write WAL --> WAL[(WAL File)]
        C -- 3. Replicate to Followers & Wait Quorum --> C
        C -- 4. Commit Log Entry --> C
        C -- 5. Apply Committed Entry --> D[MVCC Storage]
        D -- Update --> E[treeIndex (In-Memory B-Tree: Key -> Revision)]
        D -- Write Revision -> Data --> F[BoltDB (Persistent B+ Tree: Revision -> Data)]
        B -- Read Request --> D
        D -- Query --> E
        E -- Get Revision(s) --> D
        D -- Get Data by Revision --> F
        F -- Return Data --> D
        D -- Return Result --> B
        B -- Response --> A
    end

Compaction (压缩) 与 Defragmentation (碎片整理):

  • Compaction: 由于 MVCC 会不断创建新版本,旧版本数据会累积。Compaction 用于清理指定 Revision 之前的历史版本(包括 Tombstone 标记的版本),回收 BoltDB 中的空间。可以通过 etcdctl compact 手动触发,或配置自动压缩策略。注意:Compaction 只标记空间可重用,不缩小文件大小。
  • Defragmentation: Compaction 后,BoltDB 文件内部可能存在很多碎片(已被回收但未释放给操作系统的空间)。Defragmentation 会重建 BoltDB 文件,将有效数据紧凑地排列,并将空闲空间返还给操作系统,从而缩小文件大小。这是一个 I/O 密集型操作,建议在低峰期执行 (etcdctl defrag)。

5. etcd 的 Watch 机制详解

Watch 机制是 etcd 的核心功能之一,允许客户端高效地追踪 Key 或 Key 范围的变化。Kubernetes 的控制器严重依赖此机制来响应集群状态的变化。

  • 基于 Revision 的事件流: Watch 不是轮询。客户端发起 Watch 请求时,可以指定一个起始 Revision。etcd 会从该 Revision 开始,将后续发生的所有变更事件(Put, Delete)按顺序推送给客户端。
  • Watch Stream: 每个 Watch 连接建立一个持久的 gRPC 流。etcd Server 会持续将匹配该 Watch 请求的事件发送到这个流上。
  • Watcher Group: etcd 内部为每个被监听的 Key 或 Key 范围维护 Watcher 集合。当一个 Key 被修改(产生新的 Revision)时,MVCC 模块会通知相关的 Watcher Group。
  • Synced vs Unsynced Watchers:
    • Synced Group: 包含那些已经追赶上当前最新 Revision 的 Watcher。当新的变更发生时,事件会直接发送给这些 Watcher。
    • Unsynced Group: 包含那些因为网络延迟或其他原因落后于当前最新 Revision 的 Watcher。etcd 会有一个后台任务(syncWatchersLoop)负责从 BoltDB 读取历史事件,发送给这些落后的 Watcher,直到它们追上进度,然后将其移入 Synced Group。
    • 性能考量: 如果有大量 Watcher 长期处于 Unsynced 状态,会增加 etcd 的 CPU 和 I/O 负担,因为需要不断读取旧数据。
  • 慢 Watcher 处理: 如果某个 Watcher 消费事件的速度过慢,etcd 的发送缓冲区可能会被占满,进而影响其他 Watcher 甚至整个 etcd 的性能。etcd 会有机制检测并可能断开过慢的 Watcher 连接。

6. etcd 的高可用部署方案

etcd 的高可用性依赖于 Raft 协议和集群部署。

  • 集群规模: 推荐部署奇数个节点(通常 3 或 5 个)。
    • 3 节点集群:可容忍 1 个节点故障。
    • 5 节点集群:可容忍 2 个节点故障。
    • 更多节点会增加 Raft 协议的网络通信开销和延迟,不一定带来更好的写性能。读性能可以通过增加 Learner 节点来扩展。
  • 部署拓扑:
    • 静态发现: 启动时通过 --initial-cluster 参数指定所有成员的地址。
    • DNS 发现: 通过预配置的 DNS SRV 记录来发现集群成员。
    • etcd 发现服务: 利用另一个 etcd 集群或公共发现服务 (discovery.etcd.io) 来引导新成员加入。
  • 故障转移: 当 Leader 节点故障或网络隔离时,剩余的节点(如果构成多数派)会自动发起选举,选出新的 Leader,集群继续提供服务。故障节点的恢复通常需要人工介入或自动化脚本。
  • 数据备份与恢复:
    • 快照 (Snapshot): 定期使用 etcdctl snapshot save 创建集群状态的快照。快照包含了某个时间点的完整 KV 数据。
    • 恢复: 可以从快照恢复整个集群。恢复过程需要停止所有 etcd 实例,使用 etcdctl snapshot restore 在新数据目录中恢复数据,然后使用新的集群配置重新启动所有节点。恢复是有损操作,会丢失快照点之后的数据。
  • 自动化运维工具:
    • etcd Operator (已归档): 早期用于在 Kubernetes 上管理 etcd 集群的 Operator。
    • Helm Charts (如 Bitnami): 提供标准化的部署模板,简化在 Kubernetes 上部署高可用 etcd 集群(通常使用 StatefulSet)。

使用 Bitnami Helm chart 安装 etcd 高可用集群(示例):

1
2
3
4
5
# 添加 Bitnami Helm 仓库
helm repo add bitnami https://charts.bitnami.com/bitnami

# 安装 etcd (默认会创建 3 副本的 StatefulSet)
helm install my-etcd bitnami/etcd --set replicaCount=3

7. etcd 在 Kubernetes 中的核心作用

etcd 是 Kubernetes 控制平面的大脑,存储了整个集群的状态。

  • API Server 的唯一后端: Kubernetes API Server 是唯一直接与 etcd 通信的组件。所有其他组件(kubelet, controller-manager, scheduler)都通过 API Server 间接读写集群状态。
  • 存储对象: 所有 Kubernetes 资源对象(Pods, Services, ConfigMaps, Secrets, Custom Resources 等)的 YAML/JSON 定义都以 Key-Value 的形式存储在 etcd 中。Key 通常遵循 /registry/<resource_type>/<namespace>/<resource_name> 的路径格式。
    1
    2
    3
    4
    # 示例 Key 路径
    /registry/pods/default/my-nginx-pod
    /registry/services/kube-system/kube-dns
    /registry/configmaps/my-namespace/my-config
  • Watch 与控制器模型: Kubernetes 的控制器(如 Deployment Controller, ReplicaSet Controller)通过 API Server Watch 相关的资源类型。当 etcd 中有资源变更时,API Server 会收到 Watch 事件,并将其转发给相应的控制器。控制器根据这些事件来调整集群状态,使其趋向于期望状态(例如,创建/删除 Pod)。
  • Resource Version (RV): Kubernetes API 中的 resourceVersion 字段直接映射到 etcd 中该资源的 ModRevision。客户端(如 kubectl, 控制器)在发起 Watch 请求时会带上已知的最新 RV,API Server 会基于此 RV 从 etcd 获取后续的变更事件。这确保了事件的有序性和不丢失。
  • API Server 与 etcd 的连接: API Server 启动时通过 --etcd-servers 参数指定 etcd 集群的地址列表。通过 --etcd-cafile, --etcd-certfile, --etcd-keyfile 配置 TLS 连接。
  • 健康检查: API Server 会定期对 etcd 集群进行健康检查(现在是真实的 API 调用,而非简单的 Ping),以确保后端存储可用。

Kubernetes 集群中 etcd 的部署拓扑:

  1. 堆叠式 (Stacked) / 托管式 (Hosted): etcd 成员与 Kubernetes 控制平面组件(API Server, Scheduler, Controller Manager)运行在相同的节点上。
    • 优点: 部署简单,所需节点较少。控制平面和 etcd 之间的通信是本地的,延迟低。
    • 缺点: 控制平面节点故障可能同时影响 API Server 和 etcd 成员,降低了容错性。资源竞争可能更激烈。
  2. 外部式 (External): etcd 集群运行在独立的专用节点上,与 Kubernetes 控制平面节点分离。
    • 优点: 提高了容错性,控制平面故障不直接影响 etcd,反之亦然。资源隔离更好。可以独立扩展 etcd 集群。
    • 缺点: 需要更多的主机。控制平面与 etcd 之间的通信需要跨网络,可能引入更高延迟。管理更复杂。

8. etcd 最佳实践与性能优化

维护一个健康的 etcd 集群对 Kubernetes 的稳定至关重要。

  1. 硬件要求:
    • CPU: 2-4 核起步,根据集群规模调整。
    • 内存: 8GB 起步,建议 16GB 或更高。etcd 会缓存数据和索引在内存中。监控 etcd_mvcc_db_total_size_in_bytesprocess_resident_memory_bytes
    • 磁盘: 必须使用低延迟的 SSD(最好是 NVMe)。磁盘 I/O 性能是 etcd 最关键的瓶颈。将 WAL 文件和数据文件放在不同的物理磁盘上可以进一步提升性能 (--wal-dir)。监控磁盘 I/O 延迟 (etcd_disk_wal_fsync_duration_seconds, etcd_disk_backend_commit_duration_seconds),应保持在 10ms 以下。
    • 网络: 低延迟、高带宽的网络。节点间 RTT (Round Trip Time) 应尽可能低。监控 etcd_network_peer_round_trip_time_seconds
  2. 集群配置:
    • 规模: 3 或 5 节点。避免偶数节点。
    • 地域: 部署在同一数据中心或可用区内,避免跨地域部署导致的高延迟。
    • 时间同步: 所有节点必须保持精确的时间同步(使用 NTP)。时间偏差可能导致 Raft 协议异常和 TLS 证书验证失败。
  3. 参数调优:
    • 心跳间隔 (--heartbeat-interval): Leader 发送心跳的频率。默认为 100ms。
    • 选举超时 (--election-timeout): Follower 等待 Leader 心跳的超时时间。默认为 1000ms。通常应设置为心跳间隔的 5-10 倍。这两个值需要根据实际网络延迟调整。 网络延迟高时应适当增加。
    • 快照频率 (--snapshot-count): 每隔多少次事务提交后创建一次快照。默认为 100,000。频繁快照会增加 I/O 负担,但能更快地回收 WAL 日志空间。
  4. 存储维护:
    • 配额 (--quota-backend-bytes): 设置 etcd 数据库大小的上限(默认为 2GB,建议调大至 8GB 或更高),防止无限增长耗尽磁盘。
    • 自动压缩 (--auto-compaction-retention): 配置自动压缩策略,保留指定时间段的历史版本(如 --auto-compaction-mode=revision --auto-compaction-retention=1000 保留最近 1000 个版本,或 --auto-compaction-mode=periodic --auto-compaction-retention=1h 每小时压缩一次,保留 1 小时数据)。
    • 定期碎片整理 (etcdctl defrag): 在低峰期定期执行,回收磁盘空间。注意:Defrag 是阻塞操作,需要逐个节点执行。
  5. 安全性:
    • 启用 TLS: 对 Peer(成员间)和 Client(API Server 到 etcd)通信启用双向 TLS 认证 (--peer-client-cert-auth=true, --client-cert-auth=true)。
    • RBAC (未来可能): 关注 etcd 未来可能引入的更细粒度的访问控制。
    • 数据加密 (可选): etcd 支持静态数据加密 (--experimental-encryption-key),但会带来性能开销。
  6. 监控:
    • 关键指标:
      • etcd_server_has_leader: 是否有 Leader (0 或 1)。
      • etcd_server_leader_changes_seen_total: Leader 切换次数。频繁切换表明不稳定。
      • etcd_mvcc_db_total_size_in_bytes: 数据库文件大小。
      • etcd_network_peer_round_trip_time_seconds: Peer 间网络延迟。
      • etcd_disk_wal_fsync_duration_seconds: WAL fsync 延迟。
      • etcd_disk_backend_commit_duration_seconds: 后端存储提交延迟。
      • etcd_server_proposals_failed_total: 提案失败次数。
      • grpc_server_handled_total (按 grpc_method 区分): 各 API 调用频率。
      • etcd_debugging_mvcc_keys_total: 总 Key 数量。
      • etcd_debugging_mvcc_pending_events_total: 待处理的 Watch 事件数。
    • 日志: 关注 etcd 日志中的 WARN 和 ERROR 信息。
  7. 事件分离 (大规模集群): 对于非常大的 Kubernetes 集群,可以将 K8s 事件(Events)存储在单独的 etcd 集群中 (--etcd-servers-overrides=/events#<event-etcd-urls>),减轻主 etcd 集群的压力。

9. etcd 常见问题与故障排查

  1. 频繁的 Leader 选举:
    • 症状: etcd_server_leader_changes_seen_total 指标快速增加,日志中出现选举相关信息。
    • 原因: 网络延迟高或不稳定、节点负载过高(CPU/内存/磁盘 I/O)、心跳或选举超时设置不合理、时间不同步。
    • 排查:
      • 检查节点间网络连通性和延迟 (ping, traceroute, etcd_network_peer_round_trip_time_seconds)。
      • 检查节点资源使用情况 (top, iostat, vmstat)。
      • 检查 etcd 日志,查找超时或慢请求信息。
      • 验证 NTP 服务是否正常工作。
      • 检查并调整 --heartbeat-interval--election-timeout
  2. 集群分裂 (Split Brain):
    • 症状: 集群中出现多个 Leader(理论上 Raft 能避免,但可能由配置错误或严重网络分区导致)。
    • 原因: 错误的 --initial-cluster 配置、网络分区导致多数派无法形成。
    • 排查:
      • 使用 etcdctl endpoint status --cluster -w table 检查每个成员视角下的集群状态和 Leader。
      • 检查网络防火墙和路由配置。
      • 确保 --initial-cluster-state 配置正确(新建集群为 new,加入现有集群为 existing)。
  3. etcd 请求慢或超时:
    • 症状: API Server 延迟高,kubectl 操作缓慢或失败,日志中出现 “context deadline exceeded”。
    • 原因: 磁盘 I/O 瓶颈、网络延迟、etcd 节点 CPU/内存不足、大量并发请求、数据库过大需要 Compaction/Defrag。
    • 排查:
      • 检查磁盘 I/O 延迟指标 (etcd_disk_wal_fsync_duration_seconds, etcd_disk_backend_commit_duration_seconds)。
      • 检查节点资源使用。
      • 检查网络延迟。
      • 查看 grpc_server_handled_total 确定是否有异常高频的请求。
      • 检查数据库大小 (etcd_mvcc_db_total_size_in_bytes) 和是否达到配额。考虑执行 Compaction 和 Defrag。
  4. 磁盘空间不足:
    • 症状: etcd 无法写入,日志报错 “database space exceeded”。
    • 原因: 未配置或达到存储配额 (--quota-backend-bytes)、未进行 Compaction 导致历史版本过多、WAL 文件累积(快照失败或频率过低)。
    • 排查:
      • 检查配额设置和当前数据库大小。
      • 执行 etcdctl compactetcdctl defrag
      • 检查自动压缩配置。
      • 检查快照是否成功创建,调整 --snapshot-count
      • 检查是否有异常大量的写操作。
  5. 成员节点 Down 或 Unhealthy:
    • 症状: etcdctl endpoint health 显示部分节点 unhealthy。
    • 原因: 节点宕机、网络不通、etcd 进程崩溃、磁盘故障。
    • 排查:
      • 检查节点状态和网络连通性。
      • 查看故障节点的 etcd 服务日志 (journalctl -u etcd 或容器日志)。
      • 检查磁盘健康状态。
      • 如果节点无法恢复,需要从集群中移除 (etcdctl member remove),并可能需要替换新节点 (etcdctl member add)。

结论

etcd 作为 Kubernetes 的核心存储,其稳定性、性能和可靠性直接决定了整个集群的健康状况。深入理解 etcd 的内部机制、部署策略、优化方法和故障排查技巧,是每一位 Kubernetes 管理员和运维工程师的必备技能。通过合理的配置、持续的监控和及时的维护,可以确保 etcd 稳定高效地支撑 Kubernetes 集群运行。


深入理解 etcd:Kubernetes 的分布式基石
https://mfzzf.github.io/2025/03/13/etcd/
作者
Mzzf
发布于
2025年3月13日
许可协议