达同样首文章被我们学会了使包管理工具,这样我们便可以死有益于之施用包管理工具来保管我们负之管教。

安排工具的抉择

可咱而遇见了一个题材,一个型一般是出不少布置的,比如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中的信号处理

相关文章

网站地图xml地图