Skip to main content

etcd

1. etcd 是什么?

etcd 通过 Raft 共识协议保证集群中所有副本的数据一致。它提供 REST/gRPC 接口,通常被当作“分布式字典”或“配置中心”,也是 Kubernetes 的默认存储。

了解 TCP、HTTP 和基础 Python 即可。若对“共识算法”或“租约”不熟悉,可先阅读本节的简短说明。

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:2379

2.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,即可观察到实时的事件输出。