Go 中整合 etcd 实现配置中心

Go 中整合 etcd 实现配置中心

在 go-Gin 框架中整合 etcd 配置中心,并实现配置热加载,通常需要以下几个步骤:

  1. 连接到 etcd:使用 etcd 的客户端库连接到 etcd 服务器。
  2. 监听配置变化:在 etcd 中监听配置的键(key)变化。
  3. 更新配置:当检测到配置变化时,更新应用的配置。
  4. 重启或重新加载服务:根据配置的变化,可能需要重启服务或重新加载特定的组件。

下面是详细步骤:

安装相关依赖

etcd客户端

1
go get github.com/coreos/etcd/clientv3

gin

1
go get github.com/gin-gonic/gin

全局配置

编写好全局变量,包括 etcd 客户端、要监听的配置的 key以及在项目中使用的全局的 config 配置对象

1
2
3
4
// etcd 分布式配置中心 配置热加载
var etcdClient *clientv3.Client
var appConfigKey = "name"
var GlobalConfig map[string]interface{} // 全局配置

创建 etcd 客户端

1
2
3
4
5
6
7
8
9
10
11
// 初始化 etcd 客户端
func InitEtcdClient() {
var err error
etcdClient, err = clientv3.New(clientv3.Config{
Endpoints: []string{"127.0.0.1:2379"}, // 这里需要替换成 实际的 etcd 服务的地址
DialTimeout: 5 * time.Second,
})
if err != nil {
goLog.Fatalf("etcd client init err: %v", err)
}
}

创建监听函数

创建 etcd 监听函数,实时监听配置变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 监听配置变化
func WatchConfig() {
// 首次加载配置
getResp, err := etcdClient.Get(context.Background(), appConfigKey)
if err != nil {
goLog.Fatalf("Error getting config from etcd: %v", err)
}
if len(getResp.Kvs) > 0 {
fmt.Println(getResp.Kvs[0].Value)
err = json.Unmarshal(getResp.Kvs[0].Value, &GlobalConfig)
if err != nil {
goLog.Fatalf("Error unmarshalling config: %v", err)
}
goLog.Printf("Config first load success")
} else {
goLog.Printf("Config not found in etcd")
}

// 监听配置的键变化
rch := etcdClient.Watch(context.Background(), appConfigKey, clientv3.WithPrevKV())
for wresp := range rch {
for _, ev := range wresp.Events {
if ev.Type == clientv3.EventTypePut {
// 配置已更新,重新加载配置
err := json.Unmarshal(ev.Kv.Value, &GlobalConfig)
if err != nil {
goLog.Printf("Error unmarshal config update: %v", err)
continue
}
goLog.Printf("Updated config successfully")
}
}
}
}

注意:这里是默认存储在 etcd 中的配置文件信息为 json 格式,若使用的是其他类型的格式,可以使用对应的解析库,如 yml 的 yaml.Unmarshal 等

启动 Web 服务和 etcd 客户端协程

在一个单独的协程中处理配置的热更新,如果需要主动更新配置,可以新增一个更新配置的http接口,方便调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func main() {
// 初始化 etcd 客户端
initEtcdClient()
// 在一个独立的协程中监听配置变化
go watchConfig()

r := gin.Default()
// 设置一个路由来重新加载配置
r.GET("/reload", func(c *gin.Context) {
// 这里可以调用重新加载配置的函数
// reloadService()
c.JSON(200, gin.H{"message": "Config reloaded"})
})

r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务
}

若其他中间件依赖配置中心的配置信息,必须要保证 etcd 客户端首先执行,可以放在 init 函数中,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 初始化
func init() {
// 初始化 etcd 客户端
conf.InitEtcdClient()
// 监听配置变化
go conf.WatchConfig()
// 数据库初始化
if err := db.Init(); err != nil {
panic(fmt.Sprintf("db init fail: %+v", err))
}
// 缓存初始化
if err := redis.SetUpRedisDb(); err != nil {
panic(fmt.Sprintf("redis init fail: %+v", err))
}
}

Go 中整合 etcd 实现配置中心
https://wuwanhao.github.io/2024/12/13/Gin整合 etcd,实现配置热加载/
作者
Wuuu
发布于
2024年12月13日
许可协议