Go 配置文件


类似  PHP的php.ini文件   Nginx的server.conf 文件

Go 项目配置文件 很多选择 如 JSON文件/INI文件/YAML文件/TOML文件等
对应的Golang处理库
encoding/json 标准库中的包  处理JSON配置文件  缺点是不能加注释
gcfg   处理 INI配置文件
toml   处理 TOML配置文件
viper  处理 JSON / TOML / YAML / HCL / Java properties配置文件

toml 使用

# This is a TOML document.
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# Indentation (tabs and/or spaces) is allowed but not required
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ]
# Line breaks are OK when inside arrays
hosts = [ "alpha", "omega"]
格式灵活  数字 字符串 布尔等简单类型  数组 map等 复杂的类型  TOML语言 文档  //github.com/toml-lang/toml

使用配置文件来定义Go 配置 struct

type tomlConfig struct {
    Title string
    Owner ownerInfo
    DB database `toml:"database"`
    Servers map[string]server
    Clients clients
}
type ownerInfo struct {
    Name string
    Org string `toml:"organization"`
    Bio string
    DOB time.Time
}
type database struct {
    Server string
    Ports []int
    ConnMax int `toml:"connection_max"`
    Enabled bool
}
type server struct {
    IP string
    DC string
}
type clients struct {
    Data [][]interface{}
    Hosts []string
}
只需要将文件配置 内容转成Go  可用的struct实例 即可
var config  tomlConfig
filePath := "/your/path/config.toml"
if _, err := toml.DecodeFile(filePath, &config); err != nil {
    panic(err)
}
这样config就是拥有TOML文件内容的tomlConfig 实例 直接使用

配置的单例模式

项目  配置文件 只需要解析一次 可以使用单例模式 config 解析
package config
var (  cfg * tomlConfig
    once sync.Once
)
func Config() *tomlConfig {
    once.Do(func() {
        filePath, err := filepath.Abs("./ch3/config.toml")
        if err != nil {
            panic(err)
        }
        fmt.Printf("parse toml file once. filePath: %s\n", filePath)
        if _ , err := toml.DecodeFile(filePath, &cfg); err != nil {
            panic(err)
        }
    })
    return cfg
}
使用 sync.Once 的 Do 方法  Do 方法当且仅当 第一次被调用时 才执行函数
如果 once.Do(f) 被多次调用 只有第一次调用会执行f  即使f每次调用Do  提供的f值不同
需要给每个要执行仅一次的函数 建立Once类型的实例  保证 tomlConfig对象 是单例模式  只需解析一次  在任何地方调用
fmt.Println(config.Config().DB.Server)// 配置中DB的IP
fmt.Println(config.Config().Owner.Name)// 配置中Owner的名字

配置的更新

常驻的项目(如http server) 希望能够提供 更新配置的功能 平滑的替换掉配置 不需要重启项目 只需要起一个协程 监视 定义好的信号
如果接收到信号就重新加载配置
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGUSR1)
go func() {
    for {
        <-s
        config.ReloadConfig()
        log.Println("Reloaded config")
    }
}()
监视了syscall.SIGUSR1信号 其值是30 接收到信号就执行config.ReloadConfig()方法  config中方法变动
func Config() *tomlConfig {
    once.Do(ReloadConfig)
    cfgLock.RLock()
    defer cfgLock.RUnlock()
    return cfg
}
func ReloadConfig() {
    filePath, err := filepath.Abs("./ch3/config.toml")
    if err != nil {
        panic(err)
    }
    fmt.Printf("parse toml file once. filePath: %s\n", filePath)
    config := new(tomlConfig)
    if _ , err := toml.DecodeFile(filePath, config); err != nil {
        panic(err)
    }
    cfgLock.Lock()
    defer cfgLock.Unlock()
    cfg = config
}
原来加载配置的代码放到ReloadConfig方法中 在给变量cfg赋值时 加了读写锁  以保证安全
在Config方法中获取cfg的时候加了读锁 防止在读的时候 也在写入 导致配置错乱
启动server之后 可以通过如下shell命令更新配置 kill -30 6666
其中的6666是go server的进程号 执行这条命令之后 会向go server发送syscall.SIGUSR1的信号 从而触发更新配置的动作

POSIX信号

Linux 使用34-64信号用作实时系统中 命令 man 7 signal 官方的信号介绍
在POSIX.1-1990标准中定义的信号列表:
信号     值     动作     说明
SIGHUP     1     Term     终端控制进程结束(终端连接断开)
SIGINT     2     Term     用户发送INTR字符(Ctrl+C)触发
SIGQUIT     3     Core     用户发送QUIT字符(Ctrl+/)触发
SIGILL     4     Core     非法指令(程序错误、试图执行数据段、栈溢出等)
SIGABRT     6     Core     调用abort函数触发
SIGFPE     8     Core     算术运行错误(浮点运算错误、除数为零等)
SIGKILL     9     Term     无条件结束程序(不能被捕获、阻塞或忽略)
SIGSEGV     11     Core     无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作)
SIGPIPE     13     Term     消息管道损坏(FIFO/Socket通信时 管道未打开而进行写操作)
SIGALRM     14     Term     时钟定时信号
SIGTERM     15     Term     结束程序(可以被捕获、阻塞或忽略)
SIGUSR1     30,10,16     Term     用户保留
SIGUSR2     31,12,17     Term     用户保留
SIGCHLD     20,17,18     Ign     子进程结束(由父进程接收)
SIGCONT     19,18,25     Cont     继续执行已经停止的进程(不能被阻塞)
SIGSTOP     17,19,23     Stop     停止进程(不能被捕获、阻塞或忽略)
SIGTSTP     18,20,24     Stop     停止进程(可以被捕获、阻塞或忽略)
SIGTTIN     21,21,26     Stop     后台程序从终端中读取数据时触发
SIGTTOU     22,22,27     Stop     后台程序向终端中写数据时触发
在SUSv2和POSIX.1-2001标准中的信号列表:
信号     值     动作     说明
SIGTRAP     5     Core     Trap指令触发(如断点 在调试器中使用)
SIGBUS     0,7,10     Core     非法地址(内存地址对齐错误)
SIGPOLL         Term     Pollable event (Sys V). Synonym for SIGIO
SIGPROF     27,27,29     Term     性能时钟信号(包含系统调用时间和进程占用CPU的时间)
SIGSYS     12,31,12     Core     无效的系统调用(SVr4)
SIGURG     16,23,21     Ign     有紧急数据到达Socket(4.2BSD)
SIGVTALRM     26,26,28     Term     虚拟时钟信号(进程占用CPU的时间)(4.2BSD)
SIGXCPU     24,24,30     Core     超过CPU时间资源限制(4.2BSD)
SIGXFSZ     25,25,31     Core     超过文件大小资源限制(4.2BSD)