1. etcd 是什么? #
etcd 通过 Raft 共识协议保证集群中所有副本的数据一致。它提供 REST/gRPC 接口,通常被当作“分布式字典”或“配置中心”,也是 Kubernetes 的默认存储。
2.1 运行一个测试环境 #
解压 官方 release后即可在本地启动单节点实例,以下命令假设 etcd 可执行文件位于当前目录。
# 说明:Windows PowerShell 中启动单节点 etcd
cd C:\etcd
.\etcd.exe --data-dir=data --listen-client-urls=http://127.0.0.1:2379 --advertise-client-urls=http://127.0.0.1:2379# 说明:macOS 终端中启动单节点 etcd
cd /usr/local/Cellar/etcd/*/bin
./etcd --data-dir=data --listen-client-urls=http://127.0.0.1:2379 --advertise-client-urls=http://127.0.0.1:23792.2 Raft共识速览 #
Raft 集群只允许一个 Leader 接受写请求。Leader 把日志复制到半数以上节点后才确认写入成功,任何节点宕机都不会破坏数据一致性。
2.3 租约(Lease)与 TTL #
租约类似带倒计时的句柄,可以绑定多个键。租约到期不续租,所有关联键会自动删除,适用于服务注册、心跳检测、分布式锁。
2.4 Watch 机制 #
客户端可以 watch 任意键或前缀,一旦值发生改变就能立刻收到通知。这是构建配置热更新和服务发现的关键能力。
3. 核心特性 #
本节按照模型、共识、租约、Watch 四个角度梳理 etcd 的关键优势。
3.1 层级键值模型 #
键采用 /services/api/instance-1 这样的层级结构,值可以是字符串、JSON 或二进制,便于按业务或环境划分命名空间。
3.2 Raft 带来的强一致 #
所有写请求经 Leader 排队并复制到多数节点,只有在“多数派认可”后才算成功,因此不会出现读到旧数据的情况。etcd 属于 CAP 中的 CP 系统。
3.3 租约与 KeepAlive #
为键绑定租约后,客户端需要定期 KeepAlive,否则租约到期会删除键。该机制可用于“临时节点”“服务心跳”或“自动释放的锁”。
3.4 Watch 即时通知 #
watch 允许客户端订阅键前缀,一旦键创建、修改或删除,就会按顺序推送事件。这样可以在配置变化或服务上下线时第一时间做出响应。
4. 典型应用场景 #
etcd 的特性组合能覆盖大量分布式协调场景。
4.1 服务发现 #
服务实例在 /services/<name>/<instance-id> 写入自己的地址并绑定租约,消费者 watch 同一前缀即可实时维护实例列表。
4.2 分布式配置中心 #
将配置集中存储在 /config/...,业务进程启动时读取并 watch 对应前缀,收到事件后立即刷新内存中的配置,实现热更新。
4.3 分布式锁 #
在 /locks/<resource> 位置创建带租约的键即可实现互斥访问。谁先写入成功谁持有锁,租约过期或删除键就意味着释放锁。
5. Python 实战示例 #
以下代码默认 etcd 在 127.0.0.1:2379 运行,并安装了 python-etcd3。
5.1 读写键值 #
该示例通过 etcd3 在 Python 中写入和读取键值,并处理键不存在的情况。 运行前先安装依赖。
# 说明:Windows PowerShell 中安装 etcd3
python -m pip install etcd3# 说明:macOS 终端中安装 etcd3
python3 -m pip install etcd3# 说明:使用 etcd3 读写键值
import etcd3
client = etcd3.client(host="127.0.0.1", port=2379)
def write_message(key: str, value: str) -> None:
# 说明:向 etcd 写入字符串键值对
client.put(key, value)
def read_message(key: str) -> str:
# 说明:读取键值,不存在时返回提示
value, meta = client.get(key)
if value is None:
return "key not found"
return value.decode()
if __name__ == "__main__":
write_message("/demo/msg", "Hello etcd")
print(read_message("/demo/msg"))Protocol Buffers 版本兼容性问题临时解决
# Windows PowerShell
$env:PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION="python"
# Windows CMD
set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
# Linux/Mac
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
5.2 Watch 与租约示例 #
展示如何监听配置键并使用租约自动过期。
# 说明:监听键变化并演示租约续期
import threading
import time
import etcd3
client = etcd3.client(host="127.0.0.1", port=2379)
def watch_config() -> None:
# 说明:持续监听 /config/db-url 的变化
events, cancel = client.watch("/config/db-url")
for event in events:
print(f"Watch Event: {event.value.decode()}")
def main() -> None:
watcher = threading.Thread(target=watch_config, daemon=True)
watcher.start()
# 说明:创建 20 秒租约并写入键
lease = client.lease(20)
client.put("/config/db-url", "mysql://localhost", lease=lease)
# 说明:更新键值并续租
time.sleep(5)
client.put("/config/db-url", "mysql://prod-host", lease=lease)
lease.refresh()
# 说明:等待租约过期,键被自动删除
time.sleep(25)
if __name__ == "__main__":
main()6. etcdctl 常用命令 #
etcdctl 是官方 CLI 工具,以下展示常见操作。
# 说明:Windows PowerShell 中写、读、watch 键
set ETCDCTL_API=3
.\etcdctl.exe put /demo/key "value-from-windows"
.\etcdctl.exe get /demo/key
.\etcdctl.exe watch /demo/key# 说明:macOS 终端中的等效操作
export ETCDCTL_API=3
./etcdctl put /demo/key "value-from-macos"
./etcdctl get /demo/key
./etcdctl watch /demo/key在一个终端执行 watch,在另一个终端执行 put,即可观察到实时的事件输出。