Go 应用配置文件热更新
配置文件热更新是服务端应用程序一项基本功能,特别是在生产环境中,我们不需要停服就可以调整应用配置。通过热更新,可以动态地调整日志级别、业务逻辑参数、功能模块等等。
每种语言都有自己的热更新方式,下面以 Go 语言程序为例进行演示。
错误的示例
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/signal"
"syscall"
)
type Config struct {
Test1 string `json:"Test1"`
Test2 string `json:"Test2"`
}
var (
config *Config
)
func loadConfig() {
f, err := ioutil.ReadFile("config1.json")
if nil != err {
fmt.Println("load config error:", err)
}
err = json.Unmarshal(f, &config)
if nil != err {
fmt.Println("Para config failed:", err)
}
}
func init() {
loadConfig()
fmt.Println("Load config:", config)
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGUSR2)
go func() {
for {
<-s
loadConfig()
fmt.Println("Reload config:", *config)
}
}()
}
func main() {
select {}
}
这里存在的问题是,不同 routine 读取到的配置文件可能是不同的。
正确的示例
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/signal"
"sync"
"syscall"
)
type Config struct {
Test1 string `json:"Test1"`
Test2 string `json:"Test2"`
}
var (
config *Config
configLock = new(sync.RWMutex)
)
func loadConfig() bool {
f, err := ioutil.ReadFile("config.json")
if nil != err {
fmt.Println("load config error:", err)
return false
}
temp := &Config{}
err = json.Unmarshal(f, &temp)
if nil != err {
fmt.Println("Para config failed:", err)
return false
}
configLock.Lock()
config = temp
configLock.Unlock()
return true
}
func GetConfig() *Config {
configLock.RLock()
defer configLock.RUnlock()
return config
}
func init() {
if !loadConfig() {
os.Exit(1)
}
fmt.Println("Load config:", config)
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGUSR2)
go func() {
for {
<-s
fmt.Println("Reload config:", *config)
}
}()
}
func main() {
select {}
}
当配置文件重新加载时,可能会有很多 routine 正在读取旧的配置,通过加一个全局锁,就可以保证多个 routine 读取到的是相同的配置,要注意加 read lock。
References
- Golang configuration file hot update.
- Golang hot configuration reload.
- golang信号signal的处理 - 快乐编程.
- Golang信号处理和优雅退出守护进程 - 简书.
- Signal (IPC) - Wikipedia.
- Mac OS X Manual Page For signal(3).
See also
- Go配置文件热加载 - 发送系统信号 - 360 技术 - SegmentFault 思否.
- 基于inotify实现配置文件热更新 - 360 技术 - SegmentFault 思否.
- How to Detect File Changes in Golang | by Steve Domino | Medium.