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
相关推荐
我不会起名字32211 小时前
微服务链路超时怎么设:逐层收敛的 4 条规则与 1 个反例
微服务·go·超时·熔断
我的div丢了肿么办17 小时前
go语言安装包详细讲解
后端·go
我不会起名字32218 小时前
Go 写 Kafka 消费者:sarama 的 3 个坑与优雅退出写法
kafka·消息队列·go·sarama
我不会起名字32219 小时前
Redis 从 0 到 1(十一):缓存穿透/击穿/雪崩三连击,Go 3 套防御代码
redis·缓存·go·布隆过滤器·雪崩
bug菌1 天前
一个周末就想把短链服务推到 10 万 QPS,真能靠加 Redis 做到吗?
java·redis·go
tachibana21 天前
Go 语言里的 Context 是什么?
开发语言·后端·golang·go·语言
Linux实战笔记1 天前
sync.Mutex还是Channel?Go并发场景选型对比与goroutine泄漏实战
go·channel·sync.mutex·goroutine泄漏·race detector
wflynn2 天前
GitHub 今日推荐|open_scion:为AI代理设计的并发版本控制
git·开源·go·github·agent·coding-agents
Thinker QAQ2 天前
并发编程(九):BlockingQueue 与 Channel——语言层的原子性、可见性与有序性
java·python·go·并发编程·channel·blockingqueue·message passing
茉莉玫瑰花茶2 天前
GO [ 标准库 · unsafe ]
后端·go