etcd使用技巧

 

背景

etcd在单独使用过程中,可能需要配合一些技巧食用

奇技淫巧

版本选择

如果自己涉及到etcd相关代码开发,最好是选择3.5版本以上。个人目前选择3.5.4

为什么呢?原因是此前etcd的module做过迁移(从github.com/coreos/etcd迁移到go.etcd.io/etcd),导致了一系列的go module引用混乱的问题。。可以参考一下这个博客: https://colobu.com/2020/04/09/accidents-of-etcd-and-go-module/,里面对于这个问题还有相关的github issue描述地比较详细。

本地替换

如果自己出于某些原因,想本地替换etcd的package来做部分测试,那么你可能需要同时替换多个package,否则一大堆引用错误在等着你

replace (
    go.etcd.io/etcd/api/v3 => /your/local/path/etcd/api
    go.etcd.io/etcd/client/pkg/v3 => /your/local/path/etcd/client/pkg
    go.etcd.io/etcd/client/v3 => /your/local/path/etcd/client/v3
    go.etcd.io/etcd/pkg/v3 => /your/local/path/etcd/pkg
    go.etcd.io/etcd/server/v3 => /your/local/path/etcd/server
)

单元测试

本着单元测试不经过实际中间件的原则,如果我们要测试etcd相关的内容(尤其是涉及到了etcd的消息发布订阅),那么有一个官方提供的轻量版etcd可以专门用来进行单元测试。

import (
	"net"
	"net/url"
	"os"
	"testing"

	"go.etcd.io/etcd/server/v3/embed"
)

func TestEtcdRelated(t *testing.T) {
	dir := t.TempDir()
	if err := os.Chmod(dir, 0777); err != nil {
		t.FailNow()
	}

	cfg := embed.NewConfig()
	cfg.Dir = dir

	// establish two tcp connections in advance
	// or you can just choose two ports that are not used
	lpap, err := net.Listen("tcp", ":0")
	if err != nil {
		t.FailNow()
	}
	lcac, err := net.Listen("tcp", ":0")
	if err != nil {
		t.FailNow()
	}

	lpapUrl := url.URL{Scheme: "http", Host: lpap.Addr().String()}
	lcacUrl := url.URL{Scheme: "http", Host: lcac.Addr().String()}

	cfg.LPUrls = []url.URL{lpapUrl}
	cfg.APUrls = []url.URL{lpapUrl}
	cfg.LCUrls = []url.URL{lcacUrl}
	cfg.ACUrls = []url.URL{lcacUrl}
	var cluster string
	for i := range cfg.APUrls {
		cluster = cluster + "," + "default" + "=" + cfg.APUrls[i].String()
	}
	cfg.InitialCluster = cluster[1:]

	if err = lpap.Close(); err != nil {
		t.FailNow()
	}
	if err = lcac.Close(); err != nil {
		t.FailNow()
	}
	etcdSvr, err := embed.StartEtcd(cfg)
	if err != nil {
		t.FailNow()
	}
	defer etcdSvr.Close()

	// do the unit tests you want
	// ...
}