kratos集成etcd配置中心

在kratos项目中使用etcd有两种方式

一种是使用kratos官方集成好的etcd客户端进行使用,还有一种是自己集成,下面我使用自定义的集成方式来实现配置的动态变化。

go 复制代码
type EtcdSource struct {
	client *clientv3.Client
	key    string
}

func NewEtcdSource(endpoints []string, key string) config.Source {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   endpoints,
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		log.Fatalf("failed to connect to etcd: %v", err)
	}
	return &EtcdSource{client: cli, key: key}
}

func (s *EtcdSource) Load() ([]*config.KeyValue, error) {
	resp, err := s.client.Get(context.Background(), s.key)
	if err != nil {
		return nil, err
	}
	if len(resp.Kvs) == 0 {
		log.Infof("key %s not found during load", s.key)
		return nil, nil
	}
	return []*config.KeyValue{{
		Key:    s.key,
		Value:  resp.Kvs[0].Value,
		Format: "yaml",
	}}, nil
}

这个是读取指定key的etcd数据,实现 config.Source 还需要一个watch方法

go 复制代码
func (s *EtcdSource) Watch() (config.Watcher, error) {
    return NewEtcdWatcher(s.client, s.key), nil
}

具体的监听key的变化代码:

go 复制代码
type EtcdWatcher struct {
    client *clientv3.Client
    key    string
    ch     clientv3.WatchChan
    once   sync.Once
}

func NewEtcdWatcher(client *clientv3.Client, key string) config.Watcher {
    w := &EtcdWatcher{
       client: client,
       key:    key,
       ch:     client.Watch(context.Background(), key),
    }
    log.Infof("start watching key: %s", key)
    return w
}

func (w *EtcdWatcher) Next() ([]*config.KeyValue, error) {
    log.Infof("waiting for events on key: %s", w.key)
    var kvs []*config.KeyValue

    // 第一次调用时返回当前值
    w.once.Do(func() {
       resp, err := w.client.Get(context.Background(), w.key)
       if err != nil {
          log.Infof("failed to get initial value: %v", err)
          return
       }
       if len(resp.Kvs) > 0 {
          kvs = append(kvs, &config.KeyValue{
             Key:    w.key,
             Value:  resp.Kvs[0].Value,
             Format: "yaml",
          })
       }
    })

    if len(kvs) > 0 {
       log.Infof("returning initial value for key: %s", w.key)
       return kvs, nil
    }

    // 监听后续变化
    wr := <-w.ch
    if wr.Canceled {
       log.Infof("watch canceled: %v", wr.Err())
       return nil, wr.Err()
    }
    log.Infof("received watch events: %d", len(wr.Events))
    for _, ev := range wr.Events {
       log.Infof("event type: %v, key: %s, value: %s", ev.Type, ev.Kv.Key, ev.Kv.Value)
       if ev.Type == clientv3.EventTypePut {
          kvs = append(kvs, &config.KeyValue{
             Key:    w.key,
             Value:  ev.Kv.Value,
             Format: "yaml",
          })
       }
    }
    return kvs, nil
}
func (w *EtcdWatcher) Stop() error {
    return w.client.Close()
}

具体的使用是

go 复制代码
func InitConfig() *conf.Bootstrap {

    key := "/config/rwService"
    source := r1.NewEtcdSource([]string{"localhost:4000"}, key)
    c := config.New(config.WithSource(source))
    defer c.Close()
    if err := c.Load(); err != nil {
       log.Fatalf("failed to load config: %v", err)
    }

    var cfg conf.Bootstrap
    if err := c.Scan(&cfg); err != nil {
       log.Fatalf("failed to scan config: %v", err)
    }

    w, err := source.Watch()
    if err != nil {
       log.Fatalf("failed to watch: %v", err)
    }
    defer func() {
       if err := w.Stop(); err != nil {
          log.Error("failed to stop watcher: %v", err)
       }
    }()

    for {
       select {
       default:
          kvs, err := w.Next()
          if err != nil {
             log.Fatalf("next error: %v", err)
          }
          if len(kvs) == 0 {
             log.Infof("no events received, continuing")
             continue
          }
          for _, kv := range kvs {
             log.Infof(">>> key: %s, value: %s", kv.Key, string(kv.Value))
          }
       }
    }
    return &cfg

}

以上就实现了etcd监听配置中心的key变化实时获取数据。 也可以从官方使用数据来监听数据

arduino 复制代码
go get github.com/go-kratos/kratos/contrib/config/etcd/v2
相关推荐
Joker-011112 小时前
牛客周赛Round 99(Go语言)
go·牛客周赛
Code季风18 小时前
Gin Web 层集成 Viper 配置文件和 Zap 日志文件指南(下)
前端·微服务·架构·go·gin
Code季风19 小时前
Gin Web 服务集成 Consul:从服务注册到服务发现实践指南(下)
java·前端·微服务·架构·go·gin·consul
struggleupwards19 小时前
golang中defer的小坑
后端·go
ん贤20 小时前
RESTful风格
后端·go·restful
风飘百里2 天前
分组加密核心原理与实践解析(AES/SM4)
go
岁忧2 天前
(LeetCode 每日一题) 1865. 找出和为指定值的下标对 (哈希表)
java·c++·算法·leetcode·go·散列表
Wo3Shi4七2 天前
哈希冲突
数据结构·算法·go
Code季风2 天前
GORM 部分关键字详解与关联查询实战:Preload 与 Association 的使用对比
go·orm