etcd3进行配置管理

来源:互联网 发布:淘宝怎么认证代购 编辑:程序博客网 时间:2024/05/17 04:20

最近在用golang 做一个系统,里面有一个需求是可以随时暂停某项功能,这个涉及到运行时动态改变配置。首先配置写死在代码中,是绝对不可能实现这个需求的,每次从数据获取,虽说可以解决这个问题,但是耗时,每次请求都要去查数据库。有人会说引入缓存保存从数据库查询的值,定时去同步数据中的值到缓存。这是一个可行的办法,但是用etcd3的watcher会达到更加高效,优雅。etcd是一个高可用的键值存储系统,主要用于共享配置和服务发现.。 etcd 里面有个watcher 可以监视某个key, 如果key中的value有改变,会监听到这个改变事件,然后刷新etcd种的最新版本到本地缓存。下面上代码分析:

const(

    etcdKey = "/prod/xxx/config"  // 缓存的key,也是watcher监听的key
)

var (

    ....................................

   .....................................

    confVals     map[string]interface{} // 配置的本地缓存,防止etcd宕机,也不影响业务,当watcher监听的key的value变化,会刷新缓存到这个map中。
    lock         sync.RWMutex  // 读写锁
)
 
// 启动etcd
func start() {
    .............
    cli, err := clientv3.New(clientv3.Config{
        Endpoints:   parseEndpoints(*etcdEndpoints),
        DialTimeout: time.Duration(*etcdDialTimeout) * time.Second,
    })
    ...........
    defer cli.Close()

    if err := fetchConfig(cli); err != nil {
       glog.Errorf("Fail to fetchConfig from etcd3")
    }

    watchConfigChanges(cli)
}
 
// 解析etcd 配置

func parseEndpoints(csv string) []string {
    eps := []string{}
    for _, v := range strings.Split(csv, ",") {
        if v != "" {
            eps = append(eps, v)
        }
    }
 
   return eps
}
 

func fetchConfig(cli *clientv3.Client) error {
    ctx, cancel := context.WithTimeout(context.Background(), time.Duration(*etcdOpTimeout)*time.Millisecond)
    resp, err := cli.Get(ctx, etcdKey)
    cancel()
    if err != nil {
        return err
    }

    for _, kv := range resp.Kvs {
 
        if err := updateConfigVals(kv.Value); err != nil {
            return err
        }
 
    break
    }

    return nil
}
 
// watcher 监听指定的key, key 发送变化更新confVals

func watchConfigChanges(cli *clientv3.Client) {
    rch := cli.Watch(context.Background(), etcdKey)
    for wresp := range rch {
        for _, ev := range wresp.Events {
            if string(ev.Kv.Key) != etcdKey || ev.Type != mvccpb.PUT {
                continue
            }

            if err := updateConfigVals(ev.Kv.Value); err != nil {
                glog.Errorf("Failed to update config values, %+v", err)
            }
            break
        }
    }
}
 

func updateConfigVals(b []byte) error {

    m := map[string]interface{}{}
    '''''''''''
    '''''''''''
    更新confVals
    (&lock).Lock()
    confVals = m

    return nil
}

0 0
原创粉丝点击