概述
项目启动肯定少不了配置文件,一般我们会放在单独的目录,例如config
中,有yaml、ini、json等等格式,一般用开源的读取相应问的文件映射到结构体中。
但是当一个项目秒杀频繁控制库存和限流策略等、或者其他需要频繁的变更配置文件的时候,就需要频繁的更改代码,打包,上线。时间成本高,实效性也低。所以一般都做配置热更新。
做配置热更新的有很多consul、Firestore、etcd、也有redis等等KV存储,今天我们要讲的是viper和etcd的热更新操作
准备工作
我用的是mac m1
安装etcd
生产环境肯定就是集群,测试我们直接单机模式了
brew install etcd
启动
etcd
测试
$ etcdctl version
etcdctl version: 3.5.5
API version: 3.5
或者docker,k8s安装测试环境
viper
go get github.com/spf13/viper
使用配置文件
func configByFile(vp *viper.Viper){var err error//设置配置文件的名字vp.SetConfigName("config") // name of config file (without extension)//设置配置文件后缀vp.SetConfigType("json") // REQUIRED if the config file does not have the extension in the name//设置配置文件的路径vp.AddConfigPath("/Users/xxxx/Desktop/test/testCode/") // path to look for the config file invp.Set("verbose", true) // 设置默认参数//读取文件if err = vp.ReadInConfig(); err != nil {if _, ok := err.(viper.ConfigFileNotFoundError); ok {// Config file not found; ignore error if desiredlog.Fatal("not found")} else {// Config file was found but another error was produced}}if err = vp.Unmarshal(&conf);nil != err{log.Fatal("Unmarshal ",err)}fmt.Println(conf)//watchgo func() {vp.OnConfigChange(func(e fsnotify.Event) {fmt.Println("Config file changed:", e.Name)fmt.Println(e.String())fmt.Println(e.Op.String())})vp.WatchConfig()}()}
配置文件发生修改等行为时候回接收到调用回调函数,做相应的处理
etcd做配置
func configByEtcd(vp *viper.Viper){var err errorif err = vp.AddRemoteProvider("etcd3", "http://127.0.0.1:2379", "/config/viper-test/config");err != nil {log.Fatal(err)}vp.SetConfigType("json")if err = vp.ReadRemoteConfig();err != nil {log.Fatal(err)}if err = vp.Unmarshal(conf);err != nil {log.Fatal(err)}fmt.Println("获取的配置信息 ",conf)//fmt.Println(vp.Get("addr"))//fmt.Println(vp.Get("port"))go watchRemoteConfig(vp)select {}
}func watchRemoteConfig(vp *viper.Viper) {for {time.Sleep(time.Second * 5) // delay after each request// currently, only tested with etcd supporterr := vp.WatchRemoteConfig()if err != nil {log.Printf("unable to read remote config: %v", err)continue}// unmarshal new config into our runtime config struct. you can also use channel// to implement a signal to notify the system of the changesif err = vp.Unmarshal(&conf); nil != err{log.Printf("unable to read remote config: %v", err)continue}fmt.Println("获取的配置信息 ",conf)}
}
修改 ertcdkeeper内容
查看结果
获取的配置信息 &{127.0.0.1 3307}
获取的配置信息 &{127.0.0.1 3307}
获取的配置信息 &{127.0.0.1 3307}
获取的配置信息 &{127.0.0.1 3306}
获取的配置信息 &{127.0.0.1 3306}
^Csignal: interrupt
可以看到改变了 就收到了
上边只是一个简单的使用,更具体的应用可以自己封装下 ,还是很实用的