PHPGolang学习–TOML配置处理

达到同一首文章被我们学会了以包管理工具,这样我们就好很方便的使包管理工具来治本我们依靠之保。

布工具的挑

但咱还要碰到了一个题目,一个路一般是生无数部署的,比如PHP的php.ini文件、Nginx的server.conf文件,那么Golang的花色同时符合用什么的布局文件为?

实际上现在我们出不少精选,比如 JSON文件、INI文件、YAML文件及TOML文件等等。

其间这些文件,对应之Golang处理库如下:

  • encoding/json —
    标准库中之管,可以拍卖JSON配置文件,缺点是休能够加注
  • gcfg — 处理INI配置文件
  • toml — 处理TOML配置文件
  • viper — 处理JSON, TOML, YAML,
    HCL以及Java properties配置文件

实际关于怎么选择得看stackoverflow上之问题How to handle
configuration in
Go。

toml的使用

我根据自己之欢喜好选了toml,下面就是来说下toml。

先行来拘禁一个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语言的解释大家查看文档
toml-lang/toml

下面我们再次来说一下,具体的Golang代码中怎样使用

我们根据上面的安排文件来定义Golang中配置的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
}

即时部分还定义好下,我们只有待以文件配置中之情节改动成Golang中可用的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对象是一个单例模式,只待分析一破,可以当旁地方调用。调用例子如下:

// 配置中DB的IP
fmt.Println(config.Config().DB.Server)
// 配置中Owner的名字
fmt.Println(config.Config().Owner.Name)

配置的更新

假设我们的档次是一个常驻的种类(比如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信号

当即边顺便列一下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)

代码可参考:https://github.com/CraryPrimitiveMan/go-in-action/tree/master/ch3

参考资料

Design Patterns in Golang:
Singleton
Golang hot configuration
reload
Golang中的信号处理

相关文章