intro
etcd 是一个分布式键值存储系统,专为配置共享和服务发现而设计。它由 CoreOS 开发,具有高可用性和一致性,广泛用于微服务架构中。
以下是如何在 Go 中使用 etcd 的详细指南:
1. etcd 核心功能
- 分布式键值存储:支持高可用和一致性的键值存储。
- 服务发现:提供服务注册和发现功能。
- 分布式锁:实现高可用的分布式锁。
- 监听机制:通过 Watch 功能监听键值变化。
- 安全性:支持 TLS 和基于角色的权限控制。
2. 安装 etcd
安装方式
- 从 etcd 官方下载页面 下载二进制文件。
- 解压后将
etcd和etcdctl移动到系统路径下。
启动 etcd
bash
etcd --name my-etcd --data-dir ./data --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://127.0.0.1:2379默认情况下,etcd 监听 2379 端口用于客户端通信。
3. 在 Go 中使用 etcd
需要使用官方的 clientv3 库。
依赖安装
bash
go get go.etcd.io/etcd/client/v3基础操作
初始化客户端
go
package main
import (
"context"
"log"
"time"
"go.etcd.io/etcd/client/v3"
)
func main() {
// 创建 etcd 客户端
client, err := clientv3.New(clientv3.Config{
Endpoints: []string{"localhost:2379"}, // etcd 地址
DialTimeout: 5 * time.Second, // 连接超时时间
})
if err != nil {
log.Fatalf("Failed to connect to etcd: %v", err)
}
defer client.Close()
log.Println("Connected to etcd")
}键值操作
写入键值
go
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
_, err = client.Put(ctx, "foo", "bar")
if err != nil {
log.Fatalf("Failed to put key-value: %v", err)
}
log.Println("Key-value written successfully!")读取键值
go
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
resp, err := client.Get(ctx, "foo")
if err != nil {
log.Fatalf("Failed to get key-value: %v", err)
}
for _, kv := range resp.Kvs {
log.Printf("Key: %s, Value: %s", kv.Key, kv.Value)
}删除键值
go
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
_, err = client.Delete(ctx, "foo")
if err != nil {
log.Fatalf("Failed to delete key: %v", err)
}
log.Println("Key deleted successfully!")监听键值变化
etcd 提供 Watch 功能,可以监听键值的变化。
go
watchChan := client.Watch(context.Background(), "foo")
for watchResp := range watchChan {
for _, event := range watchResp.Events {
log.Printf("Type: %s, Key: %s, Value: %s", event.Type, event.Kv.Key, event.Kv.Value)
}
}服务注册与发现
服务注册
通过约定的键值对进行服务注册。
go
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
leaseResp, err := client.Grant(ctx, 10) // 创建一个 10 秒的租约
if err != nil {
log.Fatalf("Failed to create lease: %v", err)
}
_, err = client.Put(ctx, "service/my-service", "127.0.0.1:8080", clientv3.WithLease(leaseResp.ID))
if err != nil {
log.Fatalf("Failed to register service: %v", err)
}
log.Println("Service registered successfully!")服务发现
go
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
resp, err := client.Get(ctx, "service/", clientv3.WithPrefix())
if err != nil {
log.Fatalf("Failed to discover services: %v", err)
}
for _, kv := range resp.Kvs {
log.Printf("Service: %s, Address: %s", kv.Key, kv.Value)
}分布式锁
etcd 提供 concurrency 模块来实现分布式锁。
依赖安装
bash
go get go.etcd.io/etcd/client/v3/concurrency实现锁
go
import (
"go.etcd.io/etcd/client/v3/concurrency"
)
func main() {
session, err := concurrency.NewSession(client)
if err != nil {
log.Fatalf("Failed to create session: %v", err)
}
defer session.Close()
mutex := concurrency.NewMutex(session, "/my-lock/")
// 获取锁
if err := mutex.Lock(context.Background()); err != nil {
log.Fatalf("Failed to acquire lock: %v", err)
}
log.Println("Lock acquired")
// 释放锁
if err := mutex.Unlock(context.Background()); err != nil {
log.Fatalf("Failed to release lock: %v", err)
}
log.Println("Lock released")
}分布式键值存储
写入带 TTL 的键
可以为键设置生存时间,使用租约实现。
go
leaseResp, err := client.Grant(context.Background(), 5) // 创建 5 秒租约
if err != nil {
log.Fatalf("Failed to create lease: %v", err)
}
_, err = client.Put(context.Background(), "temp-key", "temp-value", clientv3.WithLease(leaseResp.ID))
if err != nil {
log.Fatalf("Failed to put key with lease: %v", err)
}
log.Println("Temporary key written successfully!")自动续约
go
ch, err := client.KeepAlive(context.Background(), leaseResp.ID)
if err != nil {
log.Fatalf("Failed to keep lease alive: %v", err)
}
for ka := range ch {
log.Printf("Lease %v renewed", ka.ID)
}最佳实践
- 健康检查与监控:
- 使用 Prometheus 或其他工具监控 etcd 集群。
- 高可用部署:
- 使用奇数节点(如 3 或 5)组成 etcd 集群。
- 权限控制:
- 启用身份认证和 TLS,保证数据安全。
- 分布式锁与事务:
- 在分布式场景中使用锁来避免数据竞争。
- Watch 谨慎使用:
- 避免 Watch 太多键值,以免影响性能。
etcd 是强一致性的分布式系统,非常适合需要高可靠性和一致性的场景。如果你有更具体的问题或需求,随时告诉我!