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
相关推荐
楽码21 分钟前
一文看懂!编程语言访问变量指针和复制值
后端·go·编程语言
forever231 小时前
单个服务添加 OpenTelemetry (otel)
go
来杯咖啡1 小时前
Golang 事务消息队列:基于 SQLite 的轻量级消息队列解决方案
后端·go
十分钟空间1 小时前
Go语言实现权重抽奖系统
后端·go
DemonAvenger1 小时前
Go并发编程进阶:基于Channel的并发控制模式实战指南
分布式·架构·go
郝同学的测开笔记18 小时前
云原生探索系列(十五):Go 语言通道
后端·云原生·go
夜寒花碎20 小时前
GO入门——Hello, World
后端·go
forever2321 小时前
jaeger组件部署
go
王中阳Go21 小时前
15~30K,3年以上golang开发经验
后端·面试·go
梦兮林夕1 天前
06 文件上传从入门到实战:基于Gin的服务端实现(一)
后端·go·gin