Supervisor 是一个弱小的 过程管理工具。

在非容器化治理的服务器上, Supervisor 是有十分宽泛的应用场景的。

例如:

服务批量重启,多服务按程序启动,服务oom后主动拉起,服务std日志收集等,甚至服务健康检查它都能做。

原 Supervisor (Python)

git: https://github.com/Supervisor...

doc: http://supervisord.org/

新轮子 Supervisor (Golang)

git: https://github.com/ochinchina...

比照

两个 Supervisor 比照

指标\语言PythonGolang
起源20042017
以后版本4.2.40.7.3
语言版本要求2.7+ 或 3.4+1.11+
*unix反对反对
MacOS反对反对
Widnows不反对能跑
安装包大小Pyton环境(40MB) + 脚本(490KB)4.2MB
Web GUI反对反对

性能反对状况

共呢个\语言PythonGolang
分组反对反对
挂了主动拉起反对反对
定时重启反对反对
web端治理反对反对
监控文件主动重启反对反对
依赖程序启动反对反对
...

这里只是列举了罕用的性能,根本都实现了的,依附golang按需runtime+可执行代码打包后,二进制部署相较 python 是更为不便和玲珑的。

装置

gihub 上没有二进制包,须要clone代码,手动编译。

$ git clone https://github.com/ochinchina/supervisord$ cd supervisord$ go generate# 以下代码会编译出 linux 平台二进制可执行文件$ GOOS=linux go build -tags release -a -ldflags "-linkmode external -extldflags -static" -o supervisord# mac 下$ go build -tags release -o supervisord

试试

$ ./supervisord --helpUsage:  supervisord [OPTIONS] <command>Application Options:  -c, --configuration= the configuration file  -d, --daemon         run as daemon      --env-file=      the environment fileHelp Options:  -h, --help           Show this help messageAvailable commands:  ctl      Control a running daemon  init     initialize a template  service  install/uninstall/start/stop service  version  show the version of supervisor

应用

  • 先创立一个配置文件
$ vi supervisor.conf
[program:test]command = watch -n 5 "echo Hello!"
  • 启动
$ supervisord -c supervisor.confINFO[2022-10-15T17:31:24+08:00] load configuration from file                  file=./supervisor.confINFO[2022-10-15T17:31:24+08:00] create process:testINFO[2022-10-15T17:31:24+08:00] stop listeningINFO[2022-10-15T17:31:24+08:00] try to start program                          program=testDEBU[2022-10-15T17:31:24+08:00] wait program exit                             program=testINFO[2022-10-15T17:31:25+08:00] success to start program                      program=test## 此时该 supervisord 会前台运行,退出终端,或者 Ctrl+C 都会推出,会完结所有的程序。^CINFO[2022-10-15T17:32:39+08:00] receive a signal to stop all process & exit   signal=interruptINFO[2022-10-15T17:32:39+08:00] stop the program                              program=testINFO[2022-10-15T17:32:39+08:00] force to kill the program                     program=testINFO[2022-10-15T17:32:39+08:00] Send signal to program                        program=test signal=killedINFO[2022-10-15T17:32:39+08:00] program stopped with status:signal: killed    program=testINFO[2022-10-15T17:32:39+08:00] program exited                                program=testINFO[2022-10-15T17:32:39+08:00] Stopped by user, don't start it again         program=test
  • 启动并运行到后盾
$ supervisord -c supervisor.conf -d

这样就启动了

http 治理

supervior 同样提供了 Web GUI 治理入口,咱们来启用配置试试

[program:test]command = watch -n 5 "echo Hello"[inet_http_server]port=127.0.0.1:9001

拜访: http://127.0.0.1:9001 即

同样反对 http Auth, 依照如下配置

[inet_http_server]port=127.0.0.1:9001username=test1password=thepassword
留神: Shutdown 是停掉 supervisor 服务自身,包含 Web 入口,须要登陆到服务器,手动启动后,能力持续应用。要停掉所有自程序,抉择全副而后点击 Stop Select

文件监控

当咱们部署,或更新程序时,心愿 supervisor 能主动敞开,并运行新的可执行文件,那么 文件监控 性能就派上用场了。

go-supervisor 反对多种文件监控模式:

  1. 执行的程序自身监控
  2. 某个文件夹内监控
  3. 文件监控
  • 配置形式

    [program:golang]command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.tomlrestart_when_binary_changed=true

这里的测试代码我放到文章最初了

INFO[2022-10-15T20:33:20+08:00] program is changed, restart it                program=golangINFO[2022-10-15T20:33:20+08:00] stop the program                              program=golangINFO[2022-10-15T20:33:20+08:00] force to kill the program                     program=golangINFO[2022-10-15T20:33:20+08:00] Send signal to program                        program=golang signal=killedINFO[2022-10-15T20:33:20+08:00] program stopped with status:signal: killed    program=golangINFO[2022-10-15T20:33:20+08:00] program exited                                program=golangINFO[2022-10-15T20:33:20+08:00] Stopped by user, don't start it again         program=golangINFO[2022-10-15T20:33:21+08:00] try to start program                          program=golangDEBU[2022-10-15T20:33:21+08:00] wait program exit                             program=golangINFO[2022-10-15T20:33:22+08:00] success to start program                      program=golang

监控到变动后,重启形式也有两种,一种是:间接kill。另一种是发送信号量给程序,让程序自行处理。

留神: 如果 supervisor 自身发了 kill 信号给程序,程序本人完结了,superviosr 默认也不会帮你在重启程序,它的设计逻辑时,我只负责发信号,其余程序自理。这里你能够手动新增一条配置:
[program:golang]command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.tomlrestart_when_binary_changed=trueautostart=true #  这行配置
如果治理了在线的大流量服务,举荐应用第二种,平滑重启,因为间接kill程序,会导致申请解决一半,或事务进行到一半停止,进而数据不统一。

好的,咱们再次调整配置

[program:golang]command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.tomlrestart_when_binary_changed=truerestart_signal_when_binary_changed=9 # SIGKILL

来看下日志:

INFO[2022-10-15T20:37:58+08:00] program is changed, restart it                program=golangINFO[2022-10-15T20:37:58+08:00] Send signal to program                        program=golang signal=terminatedINFO[2022-10-15T20:37:58+08:00] program stopped with status:exit status 0     program=golangINFO[2022-10-15T20:37:58+08:00] program exited                                program=golangINFO[2022-10-15T20:37:58+08:00] Don't start the stopped program because its autorestart flag is false  program=golang

留神这里的日志,说的是,supersivor 给程序发了 信号,然而程序退出了,因为,你启用主动重启配置,所有,没有启动该程序。

这里是信号发错了,调整一下:

[program:golang]command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.tomlrestart_when_binary_changed=truerestart_signal_when_binary_changed=SIGHUP # 1 这里填数字字符都行

这下重新启动supervisor,看下成果。

程序运行日志:

2022-10-16 11:00:27.754 [INFO] main.go:13: start2022-10-16 11:00:27.754 [INFO] main.go:21: waiting signal~2022-10-16 11:00:28.755 [INFO] main.go:17: golang program is running~2022-10-16 11:00:29.757 [INFO] main.go:17: golang program is running~2022-10-16 11:00:30.761 [INFO] main.go:17: golang program is running~2022-10-16 11:00:31.765 [INFO] main.go:17: golang program is running~2022-10-16 11:00:32.768 [INFO] main.go:17: golang program is running~2022-10-16 11:00:33.771 [INFO] main.go:17: golang program is running~2022-10-16 11:00:34.774 [INFO] main.go:17: golang program is running~2022-10-16 11:00:35.779 [INFO] main.go:17: golang program is running~2022-10-16 11:00:36.783 [INFO] main.go:17: golang program is running~2022-10-16 11:00:37.659 [INFO] main.go:32: golang get signal hangup [sighup]2022-10-16 11:00:37.788 [INFO] main.go:17: golang program is running~2022-10-16 11:00:38.790 [INFO] main.go:17: golang program is running~

这样之后,咱们就能实现部署新的程序后,主动平滑重启程序了。

留神:在 Web 端,手动 stop/start 程序,不会发信号量到程序!

监控文件夹

刚刚展现目标程序变更,主动重启。那么配置文件更新了,主动重启如何配置呢?

留神:如果程序内主动监控了文件变动并更新配置(举荐这样做),则不须要 supervisor 来发信号给程序自身了。

这里新增了两行配置,1.配置监控寄存配置文件的文件夹,2. 配置文件夹内文件变动时,发什么信号告诉程序。

[program:golang]command = /Users/paulxu/golang/go-learn/main -conf /Users/paulxu/golang/go-learn/config/config.tomlrestart_when_binary_changed=truerestart_signal_when_binary_changed=SIGHUPrestart_directory_monitor=/Users/paulxu/golang/go-learn/config/restart_signal_when_file_changed=SIGHUP

测试代码

package mainimport (    "os"    "os/signal"    "syscall"    "time"    "github.com/gogf/gf/frame/g")func main() {    g.Log().Line().Info("start!!")    go func() {        for {            time.Sleep(time.Second)            g.Log().Line().Info("golang program is running~")        }    }()    g.Log().Line().Info("waiting signal~")    c := make(chan os.Signal, 1)    signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)    for {        select {        case s := <-c:            switch s {            case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:                g.Log().Line().Infof("golang get signal %+v", s)                return            case syscall.SIGHUP:                g.Log().Line().Infof("golang get signal %+v [sighup]", s)            default:                g.Log().Line().Infof("golang get other signal %+v", s)                return            }        }    }}

最初

好的,明天给大家介绍了一款 superviorgolang轮子,以及根本应用办法。能够看到一些罕用的根底和golang碰撞后,擦出了不一样的火花。因为 Go 语言的编译工具链会全动态链接构建二进制文件,All in One 的设计理念,对运维部署时十分敌对的。期待更多这样的轮子。

尽管,在以后容器化时代,它的应用场景被进一步挤压,然而在小型站点,实体机上应用还是很不便的。

关注我,理解更多golang常识~