- 2021/12/09, etcd 的应用
- 2022/08/26, 服务发现框架比较
- 2022/11/18, Viper 从 etcd 读取配置
- 2023/03/30, APISIX + etcd 做 API 网关 + 服务发现 + 配置服务
- 2023/04/02, etcd UI 工具
- 2023/06/26, etcd 实现服务发现与配置中心
简介
etcd 是 CoreOS 的一个子项目,KV 数据库,原是设计用于存储集群共享配置数据,基于 Apache 协议开源。
PS: CoreOS 2018 年被 RedHat 收购,然后更名为 Container Linux, 后来和 RedHat 的 Project Atomic 合并,形成 Fedora CoreOS 项目。
本质是一个 KV 存储,从这个角度看和 Redis 很像。但:
Item | etcd | Redis |
---|---|---|
性能 | 高 | 非常高 |
存储方式 | 磁盘 + 内存缓存 | 内存 |
持久化 | boltdb | AOF + rdb |
数据类型 | string | 丰富 |
API | gRPC | RESP |
一致性 | Raft | 复制 |
PS:性能:更高 QPS + 更低延迟
PS:RESP:REdis Serialization Protocol(TCP 文本协议)
作用
本质就是一个轻量级的 KV 存储系统,由于其高并发、支持分布式(强一致性)、支持版本控制、支持实时更新通知等特点,所以常用于:
- 服务发现:帮助分布式系统中的服务相互找到并建立连接。
- 配置管理:集中管理和动态更新分布式系统的配置信息。
- 分布式锁:确保在分布式环境中,同一时间只有一个客户端能获取锁,避免资源冲突。
概念
-
Raft 算法
Raft 是一种用于管理复制日志的一致性算法,节点之间通过复制日志来达成一致状态。
当客户端发起写请求时,领导者(Leader)节点接收请求并将其记录到日志中,接着把日志条目复制到其他跟随者(Follower)节点。
只有当多数节点都成功复制了该日志条目后,该条目才会被提交,数据更新才会被应用。 -
角色相关概念
- Node(节点)/Member(成员):指 etcd 集群中的单个服务器实例,每个节点都有一个唯一标识,存储着部分或全部的数据副本,并且参与集群的一致性协议。
- Leader(领导者):负责处理客户端写请求和协调日志复制的节点。同一时刻集群中只有一个领导者,它会接收客户端的写操作,并将这些操作广播给其他跟随者节点。
- Follower(跟随者):跟随领导者的指令,接收并复制领导者发送的日志条目。跟随者不直接处理客户端的写请求,只响应领导者的请求。
- Candidate(候选人):在 Raft 算法的选举过程中,当跟随者在一定时间内没有收到领导者的心跳信息时,它会转变为候选人状态。
候选人会发起新一轮的选举,向其他节点请求投票。如果获得多数节点的投票,候选人就会成为新的领导者。 - Peer(对等节点):指集群中地位平等的其他节点,节点之间相互通信以实现数据复制、选举等功能。
-
Term(任期)
逻辑时间概念,用于划分不同的选举周期,确保选举的正确性和防止过期的领导者重新掌权,同时在日志复制和消息传递中也起到重要的同步和协调作用。
每个任期从一次选举开始,有一个唯一的递增编号。
在一个任期内,最多只能有一个领导者。
如果选举失败或领导者故障,会开启一个新的任期。
结构
和 Redis 对比
- 两者都是 key-value 类型存储
- Redis 是 C 写的,而 etcd 是 Go 写的
- Redis 支持多种数据类型,而 etcd 不支持
- Redis 支持 Lua 编程,而 etcd 不支持
- Redis 支持简单的权限控制,而 etcd 不支持
- Redis 采用 RESP 私有协议,而 etcd 采用 GRPC 或 HTTP (JSON)
- Redis 支持复制集的方式同步数据,而 etcd 则是通过 Raft 实现强一致性
- Redis 通过 RDB (快照) / AOF (增量) 的方式持久化
部署 (Ubuntu)
sudo apt install -y etcd
etcd --version
sudo systemctl start etcd
sudo systemctl status etcd
部署 (Docker)
docker-compose.yml
:
version: "3"
networks:
etcd_net:
driver: bridge
ipam:
driver: default
config:
- subnet: ${NETWORK_CONFIG_SUBNET}
services:
etcd-0:
networks:
etcd_net:
ipv4_address: ${ETCD_01_NETWORKS_ETCD_NET_ADDRESS}
image: quay.io/coreos/etcd:latest
ports:
- ${ETCD_01_NETWORKS_ETCD_NET_ADDRESS}:4001:4001
- ${ETCD_01_NETWORKS_ETCD_NET_ADDRESS}:2380:2380
- ${ETCD_01_NETWORKS_ETCD_NET_ADDRESS}:2379:2379
hostname: etcd-0
environment:
- GOMAXPROCS=2
command: >-
/usr/local/bin/etcd
-name etcd-0
-advertise-client-urls http://etcd-0:2379,http://etcd-0:4001
-listen-client-urls http://${ETCD_01_NETWORKS_ETCD_NET_ADDRESS}:2379,http://${ETCD_01_NETWORKS_ETCD_NET_ADDRESS}:4001
-initial-advertise-peer-urls http://etcd-0:2380
-listen-peer-urls http://${ETCD_01_NETWORKS_ETCD_NET_ADDRESS}:2380
-initial-cluster-token etcd-cluster
-initial-cluster etcd-0=http://etcd-0:2380,etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380
-initial-cluster-state new
etcd-1:
networks:
etcd_net:
ipv4_address: ${ETCD_02_NETWORKS_ETCD_NET_ADDRESS}
image: quay.io/coreos/etcd:latest
ports:
- ${ETCD_02_NETWORKS_ETCD_NET_ADDRESS}:4001:4001
- ${ETCD_02_NETWORKS_ETCD_NET_ADDRESS}:2380:2380
- ${ETCD_02_NETWORKS_ETCD_NET_ADDRESS}:2379:2379
hostname: etcd-1
environment:
- GOMAXPROCS=2
command: >-
/usr/local/bin/etcd
-name etcd-1
-advertise-client-urls http://etcd-1:2379,http://etcd-1:4001
-listen-client-urls http://${ETCD_02_NETWORKS_ETCD_NET_ADDRESS}:2379,http://${ETCD_02_NETWORKS_ETCD_NET_ADDRESS}:4001
-initial-advertise-peer-urls http://etcd-1:2380
-listen-peer-urls http://${ETCD_02_NETWORKS_ETCD_NET_ADDRESS}:2380
-initial-cluster-token etcd-cluster
-initial-cluster etcd-0=http://etcd-0:2380,etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380
-initial-cluster-state new
etcd-2:
networks:
etcd_net:
ipv4_address: ${ETCD_03_NETWORKS_ETCD_NET_ADDRESS}
image: quay.io/coreos/etcd:latest
ports:
- ${ETCD_03_NETWORKS_ETCD_NET_ADDRESS}:4001:4001
- ${ETCD_03_NETWORKS_ETCD_NET_ADDRESS}:2380:2380
- ${ETCD_03_NETWORKS_ETCD_NET_ADDRESS}:2379:2379
hostname: etcd-2
environment:
- GOMAXPROCS=2
command: >-
/usr/local/bin/etcd
-name etcd-2
-advertise-client-urls http://etcd-2:2379,http://etcd-2:4001
-listen-client-urls http://${ETCD_03_NETWORKS_ETCD_NET_ADDRESS}:2379,http://${ETCD_03_NETWORKS_ETCD_NET_ADDRESS}:4001
-initial-advertise-peer-urls http://etcd-2:2380
-listen-peer-urls http://${ETCD_03_NETWORKS_ETCD_NET_ADDRESS}:2380
-initial-cluster-token etcd-cluster
-initial-cluster etcd-0=http://etcd-0:2380,etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380
-initial-cluster-state new
etcdctl
etcdctl - A simple command line client for etcd.
ENDPOINTS=ip:port,ip:port,ip:port
# set
etcdctl --endpoints=$ENDPOINTS put test1 111
etcdctl --endpoints=$ENDPOINTS put test2 222
etcdctl --endpoints=$ENDPOINTS put test3 333
# get
etcdctl --endpoints=$ENDPOINTS get test1
etcdctl --endpoints=$ENDPOINTS get test1 --write-out="json"
etcdctl --endpoints=$ENDPOINTS get test --prefix
# delete
etcdctl --endpoints=$ENDPOINTS del test1
etcdctl --endpoints=$ENDPOINTS del test --prefix
# 集群信息
etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status
etcdctl --write-out=table --endpoints=$ENDPOINTS member list
示例 (Golang)
go get go.etcd.io/etcd/client/v3
package main
import (
"context"
"fmt"
"time"
etcd "go.etcd.io/etcd/client/v3"
)
func main() {
cli, err := etcd.New(etcd.Config{
Endpoints: []string{"192.168.31.204:2379"},
DialTimeout: 3 * time.Second,
})
if err != nil {
fmt.Printf("etcd ConnectError: %v\n", err)
return
}
defer cli.Close()
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
resp, err := cli.Get(ctx, "test1")
cancel()
if err != nil {
fmt.Printf("etcd GetError: %v\n", err)
}
for _, kv := range resp.Kvs {
fmt.Printf("etcd KeyVlue: %s, %s\n", kv.Key, kv.Value)
}
}
示例 (Python)
https://github.com/jplana/python-etcd
太久没有更新,忽略- https://github.com/kragniz/python-etcd3
https://python-etcd3.readthedocs.io/
python3 -m pip install -u etcd3
import etcd3
etcd = etcd3.client(host='etcd-host-01', port=2379)
testkey = '/key'
testval = '1234'
etcd.put(testkey, testval)
v = etcd.get(testkey)
print(v)
assert v == testval
etcd.delete(testkey)
参考资料与拓展阅读
- 维基百科(en), Container Linux
- RedHat, What was CoreOS and CoreOS container Linux?
- 博客园, 烟花易冷, 服务发现系统 etcd 介绍
- 腾讯云开发者社区,加菲的博客,使用 Go 语言操作 etcd——配置中心
- 博客园,走向人生巅峰,你想了解的关于 ETCD 都在这了
- CSDN 博客,oceanweave,etcd 架构原理学习(来自 etcd 实战)