Go-Micro json/yaml/etcd配置读取

·  阅读 3385

前言

不管是微服务,还是单体服务,配置的读取都是一个必不可少的部分。

在大部分应用程序中,大多数配置都是静态加载的,有时候可能还需要从多个源读取配置,从而使配置的读取变得更复杂。而在Go-Micro中,不管是动态读取配置、还是从多个源读取配置,都非常简单,唯一的难点就是没有文档支持

Go-Micro支持多种源的读取,包括命令行参数、文件(json、yaml)、etcd、consul、k8s等。

核心概念

Go-Micro 配置模块的核心概念有四个,分别是 Source、Encoder、Reader、Config。

对于Source,它表示读取的配置源,比如文件、命令行、consul、etcd等。Go-Micro官方支持的源有:

  • cli:即命令行参数
  • env:从环境变量中读取
  • consul:从consul中读取
  • etcd:从etcd中读取
  • file:从文件中读取
  • flag:从flags中读取
  • memory:从内存中读取

除了官方支持的源,还有一些是Go-Micro社区支持的:

  • configmap:从 k8s 的configmap中读取
  • grpc:从grpc服务器读取
  • url:从URL读取
  • runtimevar:read from Go Cloud Development Kit runtime variable
  • vault:read from Vault server

对于Encoder,它表示的是如何解析配置,比如json文件和yaml文件同属文件源,但是使用的解析器是不同的。Go-Micro默认的解析器是json,除了json解析器外,官方支持的解析器还有 yaml、toml、xml、hcl。

对于Reader,它的作用是将多个源的配置合并为一个。因为对于json、yaml、或者是consul,其配置结构都是类似的,最终Go-Micro都会将其转换成map[string]interface{}形式,并进行合并。

对于Config,它扮演的是一种管理者的角色,它负责配置的新建、配置的读取、配置的同步、配置的监听等功能。

配置读取实战

文件准备

# ./file/config.json
{
  "hosts": {
    "database": {
      "address": "10.0.0.1",
      "port": 3306
    },
    "cache": {
      "address": "10.0.0.2",
      "port": 6379
    }
  }
}


# ./file/config.yaml
hosts:
  database:
    address: 10.0.0.3
    port: 3307
  cache:
    address: 10.0.0.4
    port: 6378

复制代码

注:两份文件的结构是一样的,只不过用不同形式展示,且配置内容有所区别,主要是方便后面演示。

json读取

1.方式一:使用LoadFile读取(本质是对Load函数的封装)

import (
	"encoding/json"
	"fmt"
	"github.com/micro/go-micro/v2/config"
	"github.com/micro/go-micro/v2/config/source/file"
)

func readJson() {
	// 加载配置文件
	err := config.LoadFile("./file/config.json")
	if err != nil {
		panic(err)
  }
  // data的格式是 map[string]interface{}
  // data map[hosts:map[cache:map[address:10.0.0.2 port:6379] database:map[address:10.0.0.1 port:3306]]]
	data := config.Map()
	fmt.Println("data", data)
}

复制代码

2.方式二:新建文件源,并使用Load读取

func readJsonBySource() {
  // 使用的是默认的配置实例:DefaultConfig
	fileSource := file.NewSource(file.WithPath("./file/config.json"))
	err := config.Load(fileSource)
	if err != nil {
		panic(err)
	}
	data := config.Map()
	fmt.Println("data", data)
}

复制代码

3.方式三:新建配置实例,使用Load读取

func readJsonByCustom() {
	// 自定义的配置实例
	myConf, err := config.NewConfig()
	if err != nil {
		panic(err)
	}
	err = myConf.Load(file.NewSource(file.WithPath("./file/config.json")))
	if err != nil {
		panic(err)
	}
	data := myConf.Map()
	fmt.Println("data", data)
}

复制代码

4.方式四:读取配置,将数据解析为结构体

type Host struct {
	Address string `json:"address"`
	Port    int    `json:"port"`
}

type Config struct {
	Hosts map[string]Host `json:"hosts"`
}

func readJsonByStruct() {
	err := config.LoadFile("./file/config.json")
	if err != nil {
		panic(err)
	}
	conf := Config{}
	// 注意传的是指针
	err = config.Scan(&conf)
	if err != nil {
		panic(err)
	}
	fmt.Println("data", conf)
}

复制代码

5.方式五,读取配置,得到二进制数据,自己解析 (这种方式需要新建一个源)

func readJsonByStruct2() {
	// 新建一个源
	fileSource := file.NewSource(file.WithPath("./file/config.json"))
	err := config.Load(fileSource)
	if err != nil {
		panic(err)
	}
	// 官方文档中提到,从source读取配置后会以 changeSet 的格式返回
	changeSet, err := fileSource.Read()
	if err != nil {
		panic(err)
	}

	conf := Config{}
	// 自己解析二进制数据
	err = json.Unmarshal(changeSet.Data, &conf)
	if err != nil {
		panic(err)
	}
	fmt.Println("data", conf)
}

复制代码

上面一共使用了五种方法去解析json,对于其他数据源,其实过程都是差不多的,大体流程就是:

  • 1.新建一个源,比如 file.NewSource,并传入对应的配置,比如文件路径等
  • 2.读取源里面的数据,使用 config.Load 方法,这时数据会存到默认的配置实例中
  • 3.从配置实例里读取数据,有 Map()、Read()、Scan() 等方法可以选择

yaml读取

yaml读取其实和json差不多,唯一区别的是需要定义一个yaml解析器,不然用json解析器解析肯定报错。

import (
	"fmt"
	"github.com/micro/go-micro/v2/config"
	"github.com/micro/go-micro/v2/config/encoder/yaml"
	"github.com/micro/go-micro/v2/config/source"
	"github.com/micro/go-micro/v2/config/source/file"
)

func readFromYaml() {
	// 定义yaml解析器
	enc := yaml.NewEncoder()
	fileSource := file.NewSource(file.WithPath("./file/config.yaml"), source.WithEncoder(enc))
	err := config.Load(fileSource)
	if err != nil {
		panic(err)
	}
	fmt.Println("data", config.Map())
}

复制代码

多数据源读取

前面提到过,json配置和yaml配置其实是存在一点区别,如端口号等,目的是为了演示Go-Micro多数据源读取的场景。

既然是多数据源读取,就有优先级之分,而且优先级高的会覆盖优先级低的配置,这也是大部分应用程序的常见手段,先有一份基底配置,然后不断往上更新配置。

import (
	"fmt"
	"github.com/micro/go-micro/v2/config"
	"github.com/micro/go-micro/v2/config/encoder/yaml"
	"github.com/micro/go-micro/v2/config/source"
	"github.com/micro/go-micro/v2/config/source/file"
)

func main()  {
	jsonSource := file.NewSource(file.WithPath("./file/config.json"))

	yamlEncoder := yaml.NewEncoder()
	yamlSource := file.NewSource(file.WithPath("./file/config.yaml"), source.WithEncoder(yamlEncoder))

	// 后面读取的优先级越高,所以yaml的配置会覆盖json的配置
	err := config.Load(jsonSource, yamlSource)
	if err != nil {
		panic(err)
  }
  // data map[hosts:map[cache:map[address:10.0.0.4 port:6378] database:map[address:10.0.0.3 port:3307]]]
	fmt.Println("data", config.Map())
}

复制代码

etcd 读取

关于 etcd 的安装配置这里就不赘述了,为了能够读取到数据,我们先要往etcd写点数据

# /micro/etcd 是我们的key
$ etcdctl put /micro/etcd '{"hosts":{"database":{"address":"10.0.0.1","port":3306},"cache":{"address":"10.0.0.2","port":6379}}}'

复制代码

使用Go-Micro读取:

package main

import (
	"fmt"
	"github.com/micro/go-micro/v2/config"
	"github.com/micro/go-micro/v2/config/source/etcd"
)

func main() {
	etcdSource := etcd.NewSource(
		etcd.WithAddress("127.0.0.1:2379"),
		etcd.WithPrefix("/micro/etcd"),
		etcd.StripPrefix(true),
	)

	err := config.Load(etcdSource)
	if err != nil {
		panic(err)
	}
	conf := Config{}
	err = config.Scan(&conf)
	fmt.Println("data", conf)
}

复制代码

大家可以发现,其实etcd配置的读取和文件的读取方式差不多,这也是Go-Micro的巧妙之处,通过高度抽象的方式,简化了不同数据源的读取方式。

另外,可能有小伙伴对 StripPrefix 这个配置存在疑惑,不过通过下面这个例子大家应该就看得懂了

func main()  {
	etcdSource := etcd.NewSource(
		etcd.WithAddress("127.0.0.1:2379"),
		etcd.WithPrefix("/micro/etcd"),
		etcd.StripPrefix(false),
	)

	err := config.Load(etcdSource)
	if err != nil {
		panic(err)
	}

	changeSet, err := etcdSource.Read()
	if err != nil {
		panic(err)
	}
	// StripPrefix 从语义上看是去掉前缀的意思,如果没有去掉前缀,则会保留micro、etcd这两个key
	// {"micro":{"etcd":{"hosts":{"cache":{"address":"10.0.0.2","port":6379},"database":{"address":"10.0.0.1","port":3306}}}}}
	fmt.Println(string(changeSet.Data))

	conf := Config{}
	// Get的作用相当于 conf["micro"]["etcd"]
	// 所以 Get("micro", "etcd") 之后的数据为 {"hosts":{"cache":{"address":"10.0.0.2","port":6379},"database":{"address":"10.0.0.1","port":3306}}}
	err = config.Get("micro", "etcd").Scan(&conf)
	if err != nil {
		panic(err)
	}
	fmt.Println("data", conf)
}


复制代码

总结

关于Go-Micro配置模块的介绍就到这里了,希望能对你们有所帮助,另外,这里只是讲解了一些个人认为比较重要的点,如果需要更复杂的,可以参考下官方文档

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改