方案1:直接使用etcd
代码示例:
func main(){
key := "etcd_data/test2" // 服务配置 键名
res,err := cli.Get(context.Background(), key)
if err != nil {
fmt.Println("获取数据出错, err:", err)
return
}
// 循环打印出值
for _, ev := range res.Kvs {
// 此处用于演示,仅打印查看,实际这里是获取配置后,解析并放入全局变量中
fmt.Printf("%s:%s\n", ev.Key, ev.Value)
}
// 监视 key 的数据变动,返回一个只读通道 // <-chan WatchResponse
// watch key:address change 监控etcd中key的变化-创建、更改、删除
rch := cli.Watch(context.Background(), key)
for wresp := range rch {
// 读取 WatchResponse 响应
// 检查事件变化
for _, ev := range wresp.Events {
// 输出变化后数据,以及变化类型,这里用于演示,仅输出变化
fmt.Printf("Type: %s Key:%s Value:%s\n", ev.Type, ev.Kv.Key, ev.Kv.Value)
// 实际应用时,此处做全局配置变量的变化解析,并进行热重载
}
}
}
方案2:viper + etcd(或其他开源配置中心)
注意:需引入 go get github.com/spf13/viper/remote
func main(){
// viper 读取本地文件配置
//configByFile(viper.New())
// viper 读取 etcd 配置
configByEtcd(viper.New())
select{}
}
func configByEtcd(vp *viper.Viper){
var err error
key := "etcd_data/test2"
if err = vp.AddRemoteProvider("etcd3", "http://127.0.0.1:2379", key); err != nil {
log.Fatal(err)
}
vp.SetConfigType("json")
if err = vp.ReadRemoteConfig();err != nil {
log.Fatal(err)
}
conf := make(map[string]interface{})
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, conf)
// 或者使用管道监听
//err = vp.WatchRemoteConfigOnChannel()
//if err != nil {
// log.Fatal("unable to read remote config: ", err)
//}
//if err = vp.Unmarshal(&conf); nil != err{
// log.Fatal(err)
//}
//fmt.Println("获取的配置信息 ",conf)
}
func watchRemoteConfig(vp *viper.Viper, conf map[string]interface{}){
for {
// 循环调用,每隔5秒调用一次
time.Sleep(5 * time.Second) // delay after each request
// 监听远程配置,其实这个也是调用读取配置的接口,不是实际意义上的监听,需要循环调用
// 可以使用 vp.WatchRemoteConfigOnChannel() 代替 循环调用,备注 vp.WatchRemoteConfigOnChannel() 会出现并发不安全的问题
err := 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 changes
// 将新配置解组到我们的运行时配置结构中。
// 您还可以使用通道实现信号以通知系统更改
if err = vp.Unmarshal(&conf); nil != err{
log.Printf("unable to read remote config: %v", err)
continue
}
fmt.Println("获取的配置信息 ",conf)
}
}
// 使用 viper 从文件中读取配置
func configByFile(vp *viper.Viper){
var err error
vp.SetConfigName("app")
vp.SetConfigType("json")
vp.AddConfigPath("./config/")
// 读取文件
if err = vp.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found; ignore error if desired
log.Fatal("找不到配置文件")
} else {
// Config file was found but another error was produced
log.Fatal("其他未知错误")
}
}
conf := make(map[string]interface{})
if err = vp.Unmarshal(&conf); err != nil {
log.Fatal("Unmarshal ",err)
}
fmt.Println("从本地读取 conf: ", conf)
// watch
go 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()
}()
}
作者:joker.liu 创建时间:2023-05-30 17:24
最后编辑:joker.liu 更新时间:2023-05-30 17:35
最后编辑:joker.liu 更新时间:2023-05-30 17:35