Mastering etcd with Go: From Basics to Distributed Locks
This article introduces etcd as a reliable distributed key‑value store built on Raft, outlines its key features and common use cases such as service discovery and configuration management, and provides a complete Go tutorial covering dependency setup, server launch, client implementation, read/write testing, and distributed lock usage.
etcd is a distributed key‑value store developed by CoreOS that provides reliable configuration management and service discovery for distributed systems, built on the Raft consensus algorithm to guarantee strong consistency and high availability.
Key Features and Typical Use Cases
Simple key‑value data model with watch and atomic transaction support.
Strong consistency via Raft, ensuring only one leader handles writes.
High availability through automatic leader election and majority quorum.
Scalable cluster size with dynamic node addition or removal.
Watch/notification mechanism for real‑time configuration changes.
RBAC‑based access control, authentication and transport encryption.
RESTful HTTP API and multi‑language client libraries for easy integration.
Common scenarios include service discovery, configuration management, distributed locking, leader election, cluster state storage (e.g., Kubernetes), metadata storage for big‑data pipelines, and general coordination in distributed systems.
Go Language Practice
Dependency
Add the client library: go get go.etcd.io/etcd/client/v3 The go.mod file will include:
go.etcd.io/etcd/api/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/v3 v3.5.14 // indirectSetup
Initialize a global logger using zap:
var Logger *zap.SugaredLogger
func init() {
encoderConfig := zapcore.EncoderConfig{
TimeKey: "T",
LevelKey: "L",
NameKey: "log",
CallerKey: "C",
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
encoder := zapcore.NewConsoleEncoder(encoderConfig)
atomicLevel := zap.NewAtomicLevel()
atomicLevel.SetLevel(zap.InfoLevel)
core := zapcore.NewCore(encoder, zapcore.Lock(os.Stdout), atomicLevel)
Logger = zap.New(core, zap.AddCaller(), zap.Development()).Sugar()
}Server
Start a single‑node etcd instance (for demo) with:
brew install etcd
etcdThe default client port is 2379.
Client
Define a global client and a close helper:
const timeOut = 5 * time.Second
var cli *clientv3.Client
func init() {
client, err := clientv3.New(clientv3.Config{
Endpoints: []string{"localhost:2379"},
DialTimeout: timeOut,
})
if err != nil {
panic("failed to connect to server")
}
cli = client
}
func close() {
if err := cli.Close(); err != nil {
Logger.Error("failed to close connection")
}
}Read/Write Test
A simple test writes a key, reads all keys, prints them, and deletes them:
func TestEtcd(t *testing.T) {
defer close()
ctx, cancel := context.WithTimeout(context.Background(), timeOut)
_, _ = cli.Put(ctx, "key", "value")
cancel()
ctx, cancel = context.WithTimeout(context.Background(), timeOut)
resp, _ := cli.Get(ctx, "", clientv3.WithPrefix())
cancel()
for _, kv := range resp.Kvs {
Logger.Infof("%s: %s", kv.Key, kv.Value)
cli.Delete(context.Background(), string(kv.Key))
}
}Sample output shows the key/value pair and successful deletion.
Distributed Lock
Using etcd’s concurrency package to acquire and release a lock:
func TestLock(t *testing.T) {
defer close()
session, _ := concurrency.NewSession(cli)
defer session.Close()
mutex := concurrency.NewMutex(session, "/funtester/")
ctx := context.Background()
if err := mutex.Lock(ctx); err != nil {
Logger.Error("lock failed:", err)
return
}
Logger.Info("lock acquired")
if err := mutex.Unlock(ctx); err != nil {
Logger.Error("unlock failed:", err)
return
}
Logger.Info("unlock succeeded")
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
