在分布式系统的复杂世界中,确保有效的数据管理至关重要。分布式可靠的键值存储在维护跨分布式环境的数据一致性和可伸缩性方面起着关键作用。
在这个全面的教程中,我们将深入研究etcd,这是一个开源的分布式键值存储。我们将探索其基本概念、特性和用例,并提供一个动手快速入门指南。最后,我们将把etcd与其他几个分布式键值存储进行比较,以了解它的优势和独特之处。
分布式KV存储
分布式键值存储是一种NoSQL数据库,它将数据存储为跨多个物理机或虚拟机的键值对。这种分布本质上增强了可伸缩性、容错性和性能。此外,每个数据(值)都与唯一标识符(键)相关联。该模型对于某些用例非常高效,例如缓存、配置管理和快速数据检索。
Apache Zookeeper、Consul和Redis是一些提供可靠键值存储的例子。
分布式键值存储是许多分布式系统的支柱,为存储和检索数据提供了简单而强大的机制。
下面是分布式键值存储的一些重要特点:
- 简单性:包含键值对的基本数据结构,使其易于理解和用于特定类型的应用程序。
- 可伸缩性:系统通过跨多个节点分配工作负载来高效处理不断增长的数据量和负载。
- 可靠性:它们确保数据一致性、容错性和可伸缩性。
- 性能:键值机制提供对数据的快速有效访问。此外,通过将其分布在多个节点上,减少单个机器上的负载。
- 分布式:由于数据分布在多个节点上,因此性能得到了增强。
分布式键值存储已在各种场景中得到实际应用,例如配置管理、缓存、会话存储、服务发现、主节点选举等。
Etcd简介
Etcd是一个分布式的、可靠的键值存储,用于存储分布式系统中最关键的数据。它是一种简单、安全、快速和可靠的键值存储,专为分布式系统的配置管理、服务发现和协调而设计。
Etcd是由CoreOS团队开发的,现在是CNCF(云原生计算基金会)项目,它提供了一个可靠的分布式数据存储,可以在动态和可扩展的环境中协调配置和发现服务。
Etcd丰富的特性集使其成为分布式系统的通用且可靠的选择,为云原生环境中的配置管理、服务发现和协调提供了必要的构建块。在某些情况下,它可以达到每秒10,000次写。
让我们来了解一下它的一些主要特性:
-
HTTP/gRPC API: etcd提供HTTP和gRPC API,使其可与各种编程语言进行访问和互操作,并轻松集成到不同类型的应用程序和框架中。
-
分布式一致性:它在分布式设置中保持强一致性,确保集群中的所有节点具有一致的数据视图。
-
高可用性:etcd设计为高可用性,具有自动领导选举和故障转移机制。因此,etcd集群即使面对节点故障也能保持运行,有助于提高系统的弹性。
-
支持监听机制:etcd支持强一致性监听机制,允许应用程序实时监视特定键值存储的更改。
-
原子事务:它支持原子事务,允许将多个键值操作组合在一起并作为单个原子单元执行,从而维护数据一致性。
-
租约管理:etcd引入了租约的概念,允许键具有相关的生存时间(TTL)值,从而在指定的期限之后自动删除它们。
-
基于角色的访问控制(RBAC):支持RBAC,允许管理员为与集群交互的用户和应用程序定义角色和权限。
-
快照和备份:提供了创建集群状态快照的机制,并支持备份和恢复过程。因此,它确保了灾难恢复和数据持久性。
-
可插拔存储后端:etcd提供了一个可插拔的存储后端,允许用户选择最适合他们需求的底层存储引擎(例如,etcd的默认存储引擎,LevelDB,或RocksDB)。因此,它提供了灵活性,并允许基于特定用例和性能考虑进行优化。
-
与Kubernetes集成:etcd是Kubernetes中的一个关键组件,作为配置和状态信息的主要数据存储。这使得etcd成为容器编排的核心部分,确保分布式系统可以有效地管理配置和扩展。
-
etcdctl:这是命令行客户端工具,用于与etcd集群进行交互和管理。
与etcd类似的解决方案还有:Apache ZooKeeper和Consul等,实际选择取决于具体的项目需求。
etcd由于其简单性和云原生计算基金会(CNCF)的支持,适合Kubernetes这样的云原生环境。Apache ZooKeeper是大规模部署的强大选择,它提供了强大的一致性,但也带来了额外的复杂性。另一方面,Consul以简单和有效的服务发现而闻名,它与HashiCorp堆栈无缝集成。
安全性、易用性和集成需求在决策过程中扮演着关键角色。每种工具都有其优势,因此根据所需的特性和用例做出明智的选择对我们来说是至关重要的。
安装与配置
让我们了解如何配置和设置etcd以使其运行。etcd兼容Linux发行版,如Ubuntu、CentOS和Windows。这里以Ubuntu为示例进行安装,其他系统可以参考官方文档:
shell
$ sudo apt update
$ sudo apt install etcd
$ etcd --verison
etcd Version: 3.3.25
Git SHA: Not provided (use ./build instead of go build)
Go Version: go1.18.1
Go OS/Arch: linux/amd64
我们有多钟方式配置etcd,本文采用配置文件方式,我们将创建具有基本设置的配置文件。
etcd配置文件是一个YAML文件,其中包含用于配置etcd节点行为的设置和参数。这个文件对于定制etcd的各个方面非常重要,比如网络设置、集群信息、身份验证和存储选项。让我们来看一个例子:
yaml
# Example etcd-config.yml
# Node name, a unique identifier, in the etcd cluster
name: node-1
# Data directory where etcd will store its data
data-dir: /var/lib/etcd/default.etcd
# Listen addresses for client communication
listen-client-urls: http://127.0.0.1:2379,http://<NODE-IP>:2379
# Advertise addresses for client communication
advertise-client-urls: http://<NODE-IP>:2379
# Listen addresses for peer communication
listen-peer-urls: http://<NODE-IP>:2380
# Advertise addresses for peer communication
initial-advertise-peer-urls: http://<NODE-IP>:2380
# Initial cluster configuration
initial-cluster: node-1=http://<NODE-IP>:2380,node-2=http://<NODE-IP>:2380
# Unique token for the etcd cluster
initial-cluster-token: etcd-cluster-1
# Initial cluster state (new, existing, or standby)
initial-cluster-state: new
# Enable authentication with a shared secret token
auth-token: "some-secret-token"
# Enable authorization with RBAC
enable-authorization: true
# Enable automatic compaction of the etcd key-value store
auto-compaction-mode: periodic
auto-compaction-retention: "1h"
# Secure communication settings (TLS)
client-transport-security:
cert-file: /etc/etcd/server.crt
key-file: /etc/etcd/server.key
client-cert-auth: true
trusted-ca-file: /etc/etcd/ca.crt
peer-transport-security:
cert-file: /etc/etcd/peer.crt
key-file: /etc/etcd/peer.key
client-cert-auth: true
trusted-ca-file: /etc/etcd/ca.crt
1. 节点相关基础配置
-
name
含义 :指定节点在
etcd
集群中的名称,它是集群内该节点的唯一标识符。在集群通信、识别等场景中起到关键作用,便于区分不同节点。示例中值 :
node-1
,表示这个节点的名称为node-1
,如果集群中有多个节点,其他节点就会通过这个名称来识别它。 -
data-dir
含义 :定义了
etcd
存储其数据的目录路径。etcd
在运行过程中会将诸如键值对数据、集群相关的元数据等信息存储在此目录下,需要确保对应的目录有合适的读写权限。示例中值 :
/var/lib/etcd/default.etcd
,表明数据会存储在该指定路径下。
2. 客户端通信相关配置
-
listen-client-urls
含义 :指定
etcd
节点监听客户端连接请求的地址列表。客户端通过这些地址来与etcd
节点进行交互,比如发送读写键值对的请求等。可以配置多个地址,通常包含本地回环地址(如127.0.0.1
)方便本地测试,以及对外暴露的节点 IP 地址(<NODE-IP>
处需替换为实际节点可访问的 IP)。示例中值 :
http://127.0.0.1:2379,http://<NODE-IP>:2379
,意味着客户端既可以通过本地回环地址127.0.0.1
的2379
端口,也可以通过节点实际 IP 对应的2379
端口与该etcd
节点通信。 -
advertise-client-urls
含义 :对外宣告给客户端的用于连接该
etcd
节点的地址。客户端实际使用这些地址来发起请求,一般来说就是节点可被外部访问到的地址,和listen-client-urls
中的对外地址部分通常是对应的。示例中值 :
http://<NODE-IP>:2379
,告知客户端通过这个节点 IP 和2379
端口来连接此etcd
节点进行操作。
3. 节点间(对等体)通信相关配置
-
listen-peer-urls
含义 :设置
etcd
节点监听其他节点(对等体)连接请求的地址,用于集群内节点之间互相通信、同步数据、选举等集群相关操作,指定的端口(通常是2380
)区别于客户端通信端口。示例中值 :
http://<NODE-IP>:2380
,表示节点会在自身的这个 IP 和2380
端口上监听来自其他节点的连接。 -
initial-advertise-peer-urls
含义:在集群初始化阶段,向其他节点宣告自己用于对等通信的地址,方便其他节点能准确找到并与之建立连接,进行数据交互等集群协作操作。
示例中值 :
http://<NODE-IP>:2380
,同样是用节点 IP 和2380
端口来宣告给其他节点用于对等通信。
4. 集群初始化相关配置
-
initial-cluster
含义 :定义了集群初始的节点配置情况,格式为
节点名称=节点对等通信地址
的形式,多个节点用逗号分隔。在集群启动初始化时,各节点依据此配置来发现并连接其他节点,构建起集群的初始拓扑结构。示例中值 :
node-1=http://<NODE-IP>:2380,node-2=http://<NODE-IP>:2380
,表明初始集群包含名为node-1
和node-2
的两个节点,并且给出了它们用于对等通信的地址,后续节点会按照此信息去相互连接组成集群。 -
initial-cluster-token
含义 :为
etcd
集群提供唯一的标识令牌。主要用于区分不同的集群,特别是在多个集群存在于同一网络环境等场景下,避免节点误加入到错误的集群中,保证集群的独立性和唯一性。示例中值 :
etcd-cluster-1
,此为这个etcd
集群的唯一标识。 -
initial-cluster-state
含义 :指定集群的初始状态,有
new
(新创建集群)、existing
(加入已存在的集群)、standby
(备用状态,比如用于容灾切换等场景)等选项。这里配置为new
表示要初始化创建一个全新的etcd
集群。示例中值 :
new
,表明当前配置是用于启动新的etcd
集群。
5. 安全认证与授权相关配置
-
auth-token
含义 :用于启用基于共享秘密令牌的身份验证机制。客户端在与
etcd
节点交互时,需要提供这个对应的秘密令牌来证明自己的身份,增强集群访问的安全性。示例中值 :
"some-secret-token"
,这就是集群中使用的共享秘密令牌,实际使用中要妥善保管该值。 -
enable-authorization
含义:设置是否启用基于角色的访问控制(RBAC)授权机制。启用后,可以通过配置不同的角色、权限规则等来控制哪些用户(或客户端)能够对哪些键值对资源进行何种操作(如读、写等),进一步细化访问控制,提升安全性。
示例中值 :
true
,表示在该etcd
集群中启用 RBAC 授权机制。
6. 数据自动压缩相关配置
-
auto-compaction-mode
含义 :定义
etcd
键值存储的自动压缩模式,periodic
表示按照一定的时间周期来自动触发压缩操作,以清理过期的、冗余的数据版本等,节省存储空间,优化存储性能。示例中值 :
periodic
,采用周期性自动压缩的模式。 -
auto-compaction-retention
含义 :配合自动压缩模式,指定数据保留的时长,示例中
1h
表示保留最近一小时的数据版本,超过这个时间范围的数据版本会在自动压缩时被清理掉,具体时长可根据实际需求和存储资源等情况进行调整。示例中值 :
1h
,即按一小时来设定数据保留期限用于自动压缩。
7. 安全通信(TLS)相关配置
-
client-transport-security
部分cert-file
:指定客户端与etcd
节点通信时,节点使用的证书文件路径。该证书用于向客户端证明节点的身份合法性,基于 TLS 机制保障通信安全。示例中值 :
/etc/etcd/server.crt
,是节点对应的服务器证书文件所在路径。key-file
:定义节点私钥文件的路径,私钥与证书配合使用,用于在 TLS 加密通信中进行解密、签名等操作,确保通信的安全性和数据完整性。示例中值 :
/etc/etcd/server.key
,指明了节点私钥文件存放位置。client-cert-auth
:设置是否启用客户端证书认证。若为true
,则客户端在连接etcd
节点时也需要提供有效的证书来证明自己身份,进一步增强客户端到节点通信的安全性。示例中值 :
true
,表示启用客户端证书认证机制。trusted-ca-file
:指定信任的证书颁发机构(CA)的证书文件路径。节点通过此 CA 文件来验证客户端证书是否合法,判断客户端是否可信,构建起完整的证书信任链体系用于安全通信。示例中值 :
/etc/etcd/ca.crt
,即信任的 CA 证书文件所在路径。 -
peer-transport-security
部分这部分配置与
client-transport-security
类似,不过它主要针对的是集群内节点之间(对等体)通信的安全保障,各个参数(如cert-file
、key-file
、client-cert-auth
、trusted-ca-file
)含义与客户端通信安全配置对应参数一致,只是作用于节点间通信场景,确保节点间通信的保密性、完整性和身份验证等安全需求。
最后,我们应该确保根据特定的需求和安全考虑来定制配置文件。编辑完文件后,我们可以重新启动etcd服务以使更改生效。
启动etcd与交互
我们可以使用以下命令启动指定配置的etcd:
$ ./etcd --config-file=etcd-config.yml
此外,我们可以使用etcdctl命令行工具与etcd交互,该工具是为与etcd集群交互和管理而设计的。它便于管理员和开发人员直接从命令行在etcd集群上执行各种操作。让我们用几个例子来理解:
shell
# 存储值
$ etcdctl put mykey "Hello, etcd!"
# 获取值
$ etcdctl get mykey
mykey
Hello, etcd!
# 监听值
$ etcdctl watch mykey
在etcd中观察键允许我们接收有关键更改的实时通知,无论值被修改还是键被删除。Watch事件提供有关更改性质的详细信息,使应用程序能够动态地对etcd键值存储中的更新作出反应。
重要的是要注意,监视键并不能防止它被删除。监听是用来观察变化的机制,而不是用来控制或限制变化的。最后,我们可以使用以下命令检查etcd集群的健康状况:
$ etcdctl endpoint health
如果我们使用的是安全的etcd集群,那么我们可能需要提供额外的身份验证和安全选项,例如在检查运行状况时指定-cacert、-cert和-key标志以指向证书和密钥文件。
etcd 开发示例
golang示例
首先确保已经安装了 go.etcd.io/etcd/clientv3
库,示例代码如下:
golang
package main
import (
"context"
"fmt"
"go.etcd.io/etcd/clientv3"
"time"
)
func main() {
// 配置客户端连接参数
client, err := clientv3.New(clientv3.Config{
Endpoints: []string{"127.0.0.1:2379"}, // etcd服务端地址,可按需修改
DialTimeout: 5 * time.Second,
})
if err!= nil {
fmt.Printf("连接etcd失败:%v\n", err)
return
}
defer client.Close()
// 写入键值对到etcd
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
_, err = client.Put(ctx, "my-key", "my-value")
cancel()
if err!= nil {
fmt.Printf("写入数据到etcd失败:%v\n", err)
return
}
// 从etcd读取键值对
ctx, cancel = context.WithTimeout(context.Background(), time.Second)
resp, err := client.Get(ctx, "my-key")
cancel()
if err!= nil {
fmt.Printf("从etcd读取数据失败:%v\n", err)
return
}
for _, ev := range resp.Kvs {
fmt.Printf("键:%s,值:%s\n", ev.Key, ev.Value)
}
}
简要解释代码如下:
连接 etcd :通过 clientv3.New
方法,按照配置的连接端点(示例中是本地 127.0.0.1:2379
)和超时时间来创建与 etcd
服务端的客户端连接。如果连接失败,会打印错误信息并退出程序。
写入键值对 :使用 client.Put
方法向 etcd
中写入一个键为 my-key
,值为 my-value
的键值对,操作设置了超时控制,通过 context
来管理操作的生命周期。
读取键值对 :调用 client.Get
方法从 etcd
中读取键为 my-key
的键值对,同样设置了超时,读取成功后遍历返回结果并打印出键和值。
Rust示例
在cargo.toml中增加依赖
[dependencies]
etcd-client = "0.12"
rust与etcd交互代码:
rust
use etcd_client::{Client, Error};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Error> {
// 连接etcd服务端
let client = Client::connect(vec!["http://127.0.0.1:2379"], Some(Duration::from_secs(5))).await?;
// 写入键值对到etcd
client
.put("my-rust-key", "my-rust-value", None)
.await?;
// 从etcd读取键值对
let resp = client.get("my-rust-key", None).await?;
for kv in resp.kvs() {
println!("键:{},值:{}", kv.key_str()?, kv.value_str()?);
}
Ok(())
}
需要注意的是,这些示例只是最基础的操作演示,在实际应用中你可以根据具体需求进一步扩展功能,比如处理更复杂的事务、使用租约、实现分布式锁等基于 etcd
的高级功能。同时,确保 etcd
服务已经正确启动并能被访问到,且相应的网络配置(如端口等)是准确的。
总结
在本文中,我们全面地探讨了etcd,讨论了它的基本概念、关键特性和实际应用。快速入门指南将帮助我们快速设置etcd并以编程方式与之交互。此外,与其他分布式键值存储的比较突出了etcd的独特优势,使其成为各种分布式系统场景的可靠选择。
了解分布式可靠的键值存储、分布式系统中数据的重要性以及etcd的功能,将有助于我们在设计和实现分布式应用程序时做出明智的决策。最后,作为许多分布式系统的骨干,etcd的简单性、一致性和高可用性使其成为开发人员在复杂的分布式环境中有价值的工具。