Go语言进阶(八)配置管理

Configuration

  • 环境变量(配置): Region、Zone、Cluster、Environment、Color、Discovery、AppID、Host,等之类的环境信息,都是通过在线运行时平台打入到容器或者物理机,供 kit 库读取使用
  • 静态配置:资源需要初始化的配置信息,比如 http/gRPC server、redis、mysql 等,这类资源在线变更配置的风险非常大,我通常不鼓励 on-the-fly 变更,很可能会导致业务出现不可预期的事故,变更静态配置和发布 bianry app 没有区别,应该走一次迭代发布的流程
  • 动态配置:应用程序可能需要一些在线的开关,来控制业务的一些简单策略,会频繁的调整和使用,我们把这类是基础类型(int, bool)等配置,用于可以动态变更业务流的收归一起,同时可以考虑结合类似 https://pkg.go.dev/expvar 来结合使用。
  • 全局配置:通常,我们依赖的各类组件、中间件都有大量的默认配置或者指定配置,在各个项目里大量拷贝复制,容易出现意外,所以我们使用全局配置模板来定制化常用的组件,然后再特化的应用里进行局部替换。

例如:redis客户端,开始我们通过网络和地址创建一个连接

然后就会有一对需求:

  • 我要自定义超时时间!
  • 我要设定 Database!
  • 我要控制连接池的策略!
  • 我要安全使用 Redis,让我填一下 Password!
  • 可以提供一下慢查询请求记录,并且可以设置 slowlog 时间?

然后我们就有了各种创建函数,非常繁杂。

看看标准库和开源库怎么做的!?

方案A:net/http

看上去也不怎么好,可以动态修改ReadTimeoutWriteTimeout等字段,有什么副作用,未知。

方案B:配置文件定义填入Config对象,创建客户端

同样可以动态修改ReadTimeoutWriteTimeout等字段,有什么副作用,未知。

方案C:只读参数,无法确定那些参数必填,那些参数选填。

Functional Options

还有个问题,JSON/YAML 配置怎么加载,无法映射 DialOption

“For example, both your infrastructure and interface might use plain JSON. However, avoid tight coupling between the data format you use as the interface and the data format you use internally. For example, you may use a data structure internally that contains the data structure consumed from configuration. The internal data structure might also contain completely implementation-specific data that never needs to be surfaced outside of the system.”

— the-site-reliability-workbook 2

将配置读取到Config对象,然后Config对象,输出Options.

yaml config to Config

Configuration Best Pratice(配置最佳实践)

代码更改系统功能是一个冗长且复杂的过程,往往还涉及Review、测试等流程,但更改单个配置选项可能会对功能产生重大影响,通常配置还未经测试。配置的目标:

  • 避免复杂
  • 多样的配置
  • 简单化努力
  • 以基础设施 -> 面向用户进行转变
  • 配置的必选项和可选项
  • 配置的防御编程
  • 权限和变更跟踪
  • 配置的版本和应用对齐
  • 安全的配置变更:逐步部署、回滚更改、自动回滚