Go微服务项目配置文件的定义和读取示例详解


Posted in Golang onJune 21, 2022

前言

我们在写应用时,基本都会用到配置文件,从各种 shellnginx 等,都有自己的配置文件。虽然这没有太多难度,但是配置项一般相对比较繁杂,解析、校验也会比较麻烦。本文就给大家讲讲我们是怎么简化配置文件的定义和解析的。

场景

如果我们要写一个 Restful API 的服务,配置项大概有如下内容:

  • Host,侦听的 IP,如果不填,默认用 0.0.0.0
  • Port,侦听的端口,必填,只能是数字,大于等于80,小于65535
  • LogMode,日志模式,只能选 file 或者 console
  • Verbose,看是否输出详细日志,可选,默认为 false
  • MaxConns,允许的最大并发连接数,默认 10000
  • Timeout,超时设置,默认 3s
  • CpuThreshold,设置 CPU 使用率触发系统降载的阈值,默认 9001000m 表示 100%

之前我们用 json 做配置文件,但是 json 有个问题,无法加注释,所以我们后来切换到了 yaml 格式。

接下来让我们看看借助 go-zero 怎么来方便的的定义和解析这样的配置文件~

定义配置

首先,我们需要将上述配置需求定义到 Go 结构体里,如下:

RestfulConf struct {
    Host         string        `json:",default=0.0.0.0"`
    Port         int           `json:",range=[80,65535)"`
    LogMode      string        `json:",options=[file,console]"`
    Verbose      bool          `json:",optional"`
    MaxConns     int           `json:",default=10000"`
    Timeout      time.Duration `json:",default=3s"`
    CpuThreshold int64         `json:",default=900,range=[0:1000]"`
}
复制代码

可以看到,我们对每个配置项都有一定的定义和限制,其中一些定义如下:

  • default,配置没填的话,使用该默认值,可以看到其中的 3s 会自动解析成 time.Duration 类型
  • optional,此项可以不配置,没有的话,用类型零值
  • range,限定数字类型,需要在给定的范围内
  • options,限制配置的值只能是给出的这几个之一

并且,一些属性可以叠加使用,比如:

  • defaultrange 一起使用,就可以既增加了范围限制,又提供了默认值
  • defaultoptions 一起使用,就可以既增加了可选项限制,又提供了默认值

配置文件

因为我们在定义配置的时候,给了很多的默认值,还有使用 optional 指定为可选,所以我们的配置文件里的配置项就相对比较少了,能用默认值的就不用写了,如下:

# 因为很多都有默认值,所以只需要写需要指定值和没有默认值的
Port: 8080
LogMode: console
# 可以读取环境变量的值
MaxBytes: ${MAX_BYTES}
复制代码

这里有个注意点,如果配置项的 value 全部是数字,而你定义的配置类型是 string,比如有人测试密码经常用 123456,但是密码一般会定义为 string,配置就要写成如下(只是举个例子哈,密码一般不建议裸写到配置文件里):

Password: "123456"
复制代码

这里的双引号不能少,少了会报 type mismatch 之类的错误,因为 yaml 解析器会把不带双引号的 123456 解析成 int

加载配置文件

我们有了配置定义(config.go)和配置文件(config.yaml),接下来就是加载配置文件了,加载配置文件有三种方式:

  • 必须加载成功,否则程序退出,我们一般这么用,如果配置不对,程序就无法继续了
// 有错误直接退出程序
var config RestfulConf
conf.MustLoad("config.yaml", &config)
复制代码

go-zero 自带的 goctl 生成的默认代码也是使用 MustLoad 来加载配置文件的

  • 加载配置,并自行判断是否有 error
// 自己判断并处理 error
var config RestfulConf
// 为了更简洁,这里的 LoadConfig 后续会改为 Load,LoadConfig 已被标记为 Deprecated
if err := conf.LoadConfig("config.yaml", &config); err != nil {
    log.Fatal(err)
}
复制代码
  • 加载配置并读取环境变量
// 自动读取环境变量
var config RestfulConf
conf.MustLoad(configFile, &config, conf.UseEnv())
复制代码

这里为啥我们需要显式指定 conf.UseEnv(),因为如果默认读取的话,可能在配置里大家写特定字符的时候就需要 escape 了,所以默认不读取环境变量,这个设计也欢迎大家多提提建议哈

实现原理

我们在实现类似 yaml/json 解析的时候一般会直接使用 encoding/json 或者对应的 yaml 库,但是对于 go-zero 来说,我们需要在 unmarshal 的时候有更精确的控制,这就需要我们自己定制 yaml/json 的解析了,完整的代码实现在:

配置文件代码:github.com/zeromicro/g…

yaml/json 解析代码:github.com/zeromicro/g…

这里也充分展示了 reflect 的用法,以及复杂场景下如何通过单元测试保证代码的正确性。

总结

我一直比较推荐 Fail Fast 的思想,我们在加载配置文件的时候也是这样,一旦有错误,立马退出,这样运维在部署服务时就会及时发现问题,因为进程压根起不来。

go-zero 的所有服务的配置项都是通过这样的方式来加载和自动验证的,包括我写的很多工具的配置也是基于此来实现的,希望能对你有所帮助!

项目地址

github.com/zeromicro/g…

以上就是Go项目配置文件的定义和读取示例详解的详细内容,更多关于Go配置文件定义读取的资料请关注三水点靠木其它相关文章!

Golang 相关文章推荐
Golang 实现超大文件读取的两种方法
Apr 27 Golang
解决golang在import自己的包报错的问题
Apr 29 Golang
使用Golang的channel交叉打印两个数组的操作
Apr 29 Golang
对Golang中的FORM相关字段理解
May 02 Golang
golang 定时任务方面time.Sleep和time.Tick的优劣对比分析
May 05 Golang
完美解决golang go get私有仓库的问题
May 05 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
Go 语言中 20 个占位符的整理
Oct 16 Golang
Go并发4种方法简明讲解
Apr 06 Golang
Golang流模式之grpc的四种数据流
Apr 13 Golang
golang操作redis的客户端包有多个比如redigo、go-redis
Apr 14 Golang
Golang 入门 之url 包
May 04 Golang
Go本地测试解耦任务拆解及沟通详解Go本地测试的思路沟通的重要性总结
Jun 21 #Golang
Go 内联优化让程序员爱不释手
Jun 21 #Golang
GoFrame框架数据校验之校验结果Error接口对象
Jun 21 #Golang
GoFrame基于性能测试得知grpool使用场景
Jun 21 #Golang
Golang gRPC HTTP协议转换示例
Go Grpc Gateway兼容HTTP协议文档自动生成网关
Jun 16 #Golang
Go gRPC进阶教程gRPC转换HTTP
Jun 16 #Golang
You might like
让PHP更快的提供文件下载的代码
2012/06/13 PHP
PHP中in_array函数使用的问题与解决办法
2016/09/11 PHP
Laravel框架处理用户的请求操作详解
2019/12/20 PHP
初窥JQuery(二)事件机制(2)
2010/12/06 Javascript
js自定义事件代码说明
2011/01/31 Javascript
lyhucSelect基于Jquery的Select数据联动插件
2011/03/29 Javascript
jquery 实现checkbox全选,反选,全不选等功能代码(奇数)
2012/10/24 Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)
2016/02/16 Javascript
javascript检测移动设备横竖屏
2016/05/21 Javascript
纯js实现手风琴效果代码
2020/04/17 Javascript
详解在AngularJS的controller外部直接获取$scope
2017/06/02 Javascript
vue中如何实现变量和字符串拼接
2017/06/19 Javascript
select自定义小三角样式代码(实用总结)
2017/08/18 Javascript
Node.js学习之地址解析模块URL的使用详解
2017/09/28 Javascript
jquery 实现拖动文件上传加载进度条功能
2018/03/18 jQuery
Webpack devServer中的 proxy 实现跨域的解决
2018/06/15 Javascript
微信小程序在地图选择地址并返回经纬度简单示例
2018/12/03 Javascript
JS校验与最终登陆界面功能完整示例
2020/01/13 Javascript
跟老齐学Python之集合的关系
2014/09/24 Python
Python类属性的延迟计算
2016/10/22 Python
Python网络爬虫神器PyQuery的基本使用教程
2018/02/03 Python
Python实现的文轩网爬虫完整示例
2019/05/16 Python
在Python中过滤Windows文件名中的非法字符方法
2019/06/10 Python
解决Django中修改js css文件但浏览器无法及时与之改变的问题
2019/08/31 Python
python sqlite的Row对象操作示例
2019/09/11 Python
Python注释、分支结构、循环结构、伪“选择结构”用法实例分析
2020/01/09 Python
python中yield的用法详解
2021/01/13 Python
新加坡领先的时尚生活方式零售品牌:CHARLES & KEITH
2018/01/16 全球购物
expedia比利时:预订航班+酒店并省钱
2018/07/13 全球购物
纽约香氛品牌:NEST Fragrance
2018/10/15 全球购物
澳大利亚波西米亚风情网上商店:Czarina
2019/03/18 全球购物
W Hamond官网:始于1979年的钻石专家
2020/07/20 全球购物
应届生的求职推荐信范文
2013/11/30 职场文书
党的群众路线教育实践活动个人自我剖析材料
2014/10/07 职场文书
浅谈@Value和@Bean的执行顺序问题
2021/06/16 Java/Android
Mysql数据库表中为什么有索引却没有提高查询速度
2022/02/24 MySQL