etcd 是一个分布式、高可用、强一致性的用于配置共享和服务发现的键值(Key-Value)存储系统,由 CoreOS(现属于 Red Hat)开发,最初用于服务发现和配置管理。它设计为轻量级、易部署,支持分布式环境下的数据可靠存储,是云原生生态(如 Kubernetes、Docker Swarm)的核心组件之一。
etcd中常用的术语
术语
描述
备注
Raft
Raft算法,etcd实现一致性的核心
etcd有etcd-raft模块
Follower
Raft中的从属节点
竞争Leader失败
Leader
Raft中的领导协调节点,用于处理数据提交
Leader节点协调整个集群
Candidate
候选节点
当Follower接收Leader节点的消息超时时,会转变为Candidate
Node
Raft状态机的实例
Raft中涉及多个节点
Member
etcd实例,管理者对应的Node节点
可处理客户端请求
Peer
同一个集群中的另一个Member
其他成员
Cluster
etcd集群
拥有多个etcd Member
Lease
租期
设置关键的租期,过期删除
Watch
监测机制
监控键值对的变化
Term
任期
某个节点成为Leader,到下一次竞选的时间
WAL
预写式日志
用于持久化存储的日志格式
Client
客户端
向etcd发起请求的客户端
核心特性 分布式一致性
基于Raft算法 :通过 Raft 共识算法实现领导者选举和日志复制,确保集群中数据的强一致性(即所有节点数据实时同步)。
高可用性 :集群至少需要3个节点(奇数个,防止脑裂),支持自动故障转移,部分节点宕机时仍能正常服务。
数据模型
分层键空间 :类似文件系统的目录结构(如/config/app1/key1
),支持前缀查询(如获取/config/app1/
下所有键)。
持久化与临时键 :键可设置 TTL(生存时间),临时键在租约(Lease)过期或连接中断时自动删除,适用于服务注册等场景。
Watch机制
支持对单个键或前缀路径的变更监听(创建、修改、删除),客户端可实时获取事件通知,用于实现配置动态更新、分布式协调等功能。
简单易用的 API
提供 HTTP/JSON 和 gRPC 接口,支持多语言客户端(Go、Python、Java 等),方便与现有系统集成。
安全与持久化
数据持久化 :通过预写日志(WAL)和快照(Snapshot)保证数据可靠性,支持自动压缩日志以减少存储开销。
安全认证 :支持 HTTPS 加密传输、用户认证(ACL)和角色权限管理,确保数据访问安全。
典型应用场景 服务注册与发现 微服务启动时将地址注册到 etcd(如/services/user-service/instance1
),其他服务通过查询或监听该路径获取可用实例列表,实现动态负载均衡。
分布式配置管理 存储应用配置(如数据库连接字符串、功能开关),配置变更时通过Watch机制实时通知所有客户端,避免重启服务即可更新配置。
分布式锁与同步 通过原子操作(如 Compare-And-Swap)实现分布式锁,确保多个节点对共享资源的互斥访问,典型场景包括分布式任务调度、资源抢占。
集群元数据管理 存储集群节点状态(如 Kubernetes 的节点、Pod、服务信息),作为分布式系统的 “大脑”,记录全局状态并保证各节点视图一致。
分布式协调 实现选主(Leader Election)、分布式队列等功能,例如在分布式系统中选举一个主节点负责集中管理任务。
etcd的核心架构
共识层:基于 Raft 算法的分布式共识
Raft 算法核心作用
领导者选举:集群启动或 Leader 故障时,通过投票选出唯一 Leader,确保写操作的集中处理。
日志复制:写请求由 Leader 接收,通过日志(Log Entry)复制到多数 Follower 节点,经多数确认(Quorum)后提交,保证数据强一致性。
成员变更:支持动态调整集群节点,通过 “两阶段成员变更” 避免脑裂。
节点角色
Leader:
处理所有写请求,生成日志并同步给 Follower。
响应 Follower 的心跳请求(Heartbeat),维持领导地位。
Follower:
接收并持久化 Leader 同步的日志,响应读请求(或转发给 Leader)。
超时未收到心跳时发起选举,转为 Candidate 角色。
Observer(可选):
不参与共识算法(不投票、不存储日志),仅用于扩展读性能,提升大规模集群的读吞吐量。
数据层:分层键空间与存储引擎
数据模型
分层键空间:类似文件系统的树形结构(如 /app/config/db/url),支持前缀查询和范围操作,便于组织复杂配置。
租约(Lease)与 TTL:键可绑定租约,租约过期时键自动删除,实现临时数据(如服务注册信息)的动态管理。
存储引擎
BoltDB:嵌入式键值数据库,提供高效的磁盘存储,支持事务性读写,确保数据持久化。
预写日志(WAL):所有写操作先写入 WAL,保证故障恢复时数据不丢失,通过定期快照(Snapshot)压缩日志,提升恢复效率。
内存存储:键值数据同时存在于内存中,通过索引加速查询,兼顾性能与可靠性。
通信层
节点间通信(集群内部)
Raft 协议通信:通过 peerURLs 暴露端口(默认 2380),用于 Leader 与 Follower 同步日志、心跳交互。
gRPC 协议:v3 版本后基于 gRPC 实现,支持高效的远程过程调用(RPC),包括日志复制、成员变更等操作。
客户端通信(外部接口)
gRPC/HTTP 接口:通过 clientURLs 暴露端口(默认 2379),支持 HTTP/JSON 和 gRPC 协议,提供键值操作(PUT/GET/DELETE)、Watch 事件监听等功能。
负载均衡:客户端可连接任意节点,Follower 会将写请求转发给 Leader,读请求可在本地节点处理(需确保数据最新,或通过 readIndex 机制强一致性读)。
部署与启动 单机部署(非高可用,适合开发 / 测试) 适用场景
本地开发调试、单节点临时存储、非关键业务轻量使用。
不建议生产环境使用(无容错、单点故障)。
部署步骤
下载二进制文件:从etcd官网下载对应系统的二进制包(以 Linux 为例)
1 2 3 wget https://github.com/etcd-io/etcd/releases/download/v3.5.10/etcd-v3.5.10-linux-amd64.tar.gz tar -xzvf etcd-v3.5.10-linux-amd64.tar.gz cd etcd-v3.5.10-linux-amd64
1 2 3 4 5 ./etcd \ --name=node1 \ --data-dir=/var/lib/etcd \ --listen-client-urls=http://0.0.0.0:2379 \ --advertise-client-urls=http://<机器IP>:2379
1 etcdctl --endpoints=http://<机器IP>:2379 endpoint status
集群部署(生产环境,高可用性) 适用场景
生产环境必须使用集群(至少 3 个节点,奇数节点容错能力强,如3/5/7个节点)。
支持自动选举领导者,故障节点自动剔除(需满足多数节点存活)。
部署步骤(手动指定成员列表方式)
3 个节点示例(IP 分别为 192.168.1.101、192.168.1.102、192.168.1.103),每个节点执行以下操作:
以192.168.1.101节点为例,其他节点需修改ETCD_NAME、ETCD_ADVERTISE_CLIENT_URLS和ETCD_INITIAL_ADVERTISE_PEER_URLS的值,配置文件(/etc/etcd/etcd.conf
)如下:
1 2 3 4 5 6 7 8 9 ETCD_NAME="node1" ETCD_DATA_DIR="/var/lib/etcd" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.101:2379" ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380" # 节点间通信端口 ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.101:2380" ETCD_INITIAL_CLUSTER="node1=http://192.168.1.101:2380,node2=http://192.168.1.102:2380,node3=http://192.168.1.103:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" # 集群唯一标识符 ETCD_INITIAL_CLUSTER_STATE="new" # 初始化新集群
1 2 3 systemctl start etcd ./etcd --config-file=/etc/etcd/etcd.conf
1 2 etcdctl --endpoints=http://192.168.1.101:2379 member list
注意 :集群的部署方式还支持以动态发现的方式来部署
使用 DNS 发现 或工具(如 etcd discovery service)自动获取节点列表,适合云环境动态扩缩容。
核心配置项:ETCD_DISCOVERY(指定发现服务 URL),其余步骤与静态配置类似。
容器化部署 Docker部署
1 2 3 4 5 6 7 8 9 10 docker run -d \ --name=etcd \ --net=host \ -v /var/lib/etcd:/var/lib/etcd \ quay.io/coreos/etcd:v3.5.10 \ etcd \ --name=node1 \ --data-dir=/var/lib/etcd \ --listen-client-urls=http://0.0.0.0:2379 \ --advertise-client-urls=http://<主机IP>:2379
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 version: '3' services: etcd1: image: quay.io/coreos/etcd:v3.5.10 command: - etcd - --name etcd1 - --data-dir - /etcd-data - --listen-client-urls - http://0.0.0.0:2379 - --advertise-client-urls - http://etcd1:2379 - --listen-peer-urls - http://0.0.0.0:2380 - --initial-advertise-peer-urls - http://etcd1:2380 - --initial-cluster - etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380 - --initial-cluster-token - etcd-cluster - --initial-cluster-state - new volumes: - etcd-data1:/etcd-data networks: - etcd-network etcd2: ... volumes: etcd-data1: etcd-data2: networks: etcd-network:
Kubernetes 部署(StatefulSet) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 apiVersion: apps/v1 kind: StatefulSet metadata: name: etcd spec: serviceName: etcd-headless replicas: 3 selector: matchLabels: app: etcd template: metadata: labels: app: etcd spec: containers: - name: etcd image: quay.io/coreos/etcd:v3.5.10 command: - etcd - --name=$(POD_NAME) - --data-dir=/var/lib/etcd - --listen-client-urls=http://0.0.0.0:2379 - --advertise-client-urls=http://$(POD_NAME).etcd-headless:2379 - --listen-peer-urls=http://0.0.0.0:2380 - --initial-advertise-peer-urls=http://$(POD_NAME).etcd-headless:2380 - --initial-cluster=etcd-0=http://etcd-0.etcd-headless:2380,etcd-1=http://etcd-1.etcd-headless:2380,etcd-2=http://etcd-2.etcd-headless:2380 - --initial-cluster-token=etcd-cluster - --initial-cluster-state=new volumeClaimTemplates: - metadata: name: etcd-data spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 10Gi --- apiVersion: v1 kind: Service metadata: name: etcd-headless spec: clusterIP: None ports: - port: 2379 name: client - port: 2380 name: peer selector: app: etcd
部署注意事项 安全配置
1 2 3 4 5 6 7 --client-cert-auth \ --trusted-ca-file=/etc/etcd/ca.pem \ --cert-file=/etc/etcd/node.pem \ --key-file=/etc/etcd/node-key.pem \ --peer-trusted-ca-file=/etc/etcd/ca.pem \ --peer-cert-file=/etc/etcd/peer.pem \ --peer-key-file=/etc/etcd/peer-key.pem
启用ACL认证 (通过etcdctl auth enable
初始化)。
存储优化
使用 SSD 存储数据目录(–data-dir),提升 IO 性能。
定期执行etcdctl compact
和etcdctl defragment
清理历史版本。
监控与备份
监控指标:通过--metrics=prometheus
暴露Prometheus接口,结合Grafana监控集群健康(如领导者变更、请求延迟、存储大小)。
定期快照备份:
1 etcdctl snapshot save /backup/etcd_snapshot_$(date +%Y%m%d_%H%M%S).db
节点数量
遵循奇数节点原则(3/5/7 个节点),容错能力为 (n-1)/2(如3节点容忍1个故障)。
常用命令 基础键值操作
1 2 3 4 5 etcdctl put /config/db/url "mysql://user:pass@localhost:3306" etcdctl lease grant 10 | etcdctl put --lease="$(awk '{print $2}') " /service/user/instance1 "192.168.1.1:8080"
1 2 3 4 5 6 7 8 etcdctl get /config/db/url etcdctl get /service/user/ --prefix etcdctl get /config/db/url --rev=2
1 2 3 4 5 etcdctl del /config/db/url etcdctl del /service/user/ --prefix
1 2 3 4 5 etcdctl watch /config/db/url etcdctl watch /config/ --prefix
租约管理(临时键生命周期)
1 2 3 etcdctl lease grant 10
1 etcdctl put --lease=694d4... /lease-key "value"
1 2 3 4 5 etcdctl lease keep-alive 694d4... etcdctl lease keep-alive 694d4... --forever
1 etcdctl lease revoke 694d4...
集群状态与管理
1 2 3 4 5 6 7 8 etcdctl member list etcdctl member add node2 --peer-urls=http://192.168.1.2:2380 etcdctl member remove 123
1 2 3 4 5 etcdctl endpoint health etcdctl endpoint status --write-out=table
1 2 etcdctl endpoint leader
监控与维护
1 2 etcdctl endpoint leader
1 2 3 4 5 etcdctl snapshot save etcd_backup.db etcdctl snapshot status etcd_backup.db
1 2 etcdctl snapshot restore etcd_backup.db --data-dir=/new/data/path
安全和认证
1 2 3 4 5 6 7 8 9 etcdctl user add admin --password=pass123 etcdctl role add read-only etcdctl role grant-permission read-only read --prefix=/config/ etcdctl user grant-role admin read-only
常用选项
选项
说明
–endpoints
指定集群端点(默认:http://localhost:2379)
–prefix
前缀匹配(用于 GET/DEL/WATCH 递归操作)
–rev
指定版本号(历史查询或回滚)
–lease
绑定租约 ID(创建临时键)
–write-out=json
以 JSON 格式输出(适合脚本解析)
–cacert
启用 HTTPS 时指定 CA 证书(生产环境必填)