Supervisor 是一個強大的 進程管理工具。
在非容器化管理的服務器上, Supervisor 是有非常廣泛的使用場景的。
例如:
服務批量重啓,多服務按順序啓動,服務oom後自動拉起,服務std日誌收集等,甚至服務健康檢查它都能做。
原 Supervisor (Python)
git: https://github.com/Supervisor...
doc: http://supervisord.org/
新輪子 Supervisor (Golang)
git: https://github.com/ochinchina...
對比
兩個 Supervisor 對比
| 指標\語言 | Python | Golang |
|---|---|---|
| 起源 | 2004 | 2017 |
| 當前版本 | 4.2.4 | 0.7.3 |
| 語言版本要求 | 2.7+ 或 3.4+ | 1.11+ |
| *unix | 支持 | 支持 |
| MacOS | 支持 | 支持 |
| Widnows | 不支持 | 能跑 |
| 安裝包大小 | Pyton環境(40MB) + 腳本(490KB) | 4.2MB |
| Web GUI | 支持 | 支持 |
功能支持情況
| 共呢個\語言 | Python | Golang |
|---|---|---|
| 分組 | 支持 | 支持 |
| 掛了自動拉起 | 支持 | 支持 |
| 定時重啓 | 支持 | 支持 |
| 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 --help
Usage:
supervisord [OPTIONS] <command>
Application Options:
-c, --configuration= the configuration file
-d, --daemon run as daemon
--env-file= the environment file
Help Options:
-h, --help Show this help message
Available 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.conf
INFO[2022-10-15T17:31:24+08:00] load configuration from file file=./supervisor.conf
INFO[2022-10-15T17:31:24+08:00] create process:test
INFO[2022-10-15T17:31:24+08:00] stop listening
INFO[2022-10-15T17:31:24+08:00] try to start program program=test
DEBU[2022-10-15T17:31:24+08:00] wait program exit program=test
INFO[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=interrupt
INFO[2022-10-15T17:32:39+08:00] stop the program program=test
INFO[2022-10-15T17:32:39+08:00] force to kill the program program=test
INFO[2022-10-15T17:32:39+08:00] Send signal to program program=test signal=killed
INFO[2022-10-15T17:32:39+08:00] program stopped with status:signal: killed program=test
INFO[2022-10-15T17:32:39+08:00] program exited program=test
INFO[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:9001
username=test1
password=thepassword
注意: Shutdown 是停掉 supervisor 服務本身,包括 Web 入口,需要登陸到服務器,手動啓動後,才能繼續使用。要停掉所有自程序,選擇全部然後點擊 Stop Select。
文件監控
當我們部署,或更新程序時,希望 supervisor 能自動關閉,並運行新的可執行文件,那麼 文件監控 功能就派上用場了。
go-supervisor 支持多種文件監控模式:
- 執行的程序本身監控
- 某個文件夾內監控
- 文件監控
-
配置方式
[program:golang] command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.toml restart_when_binary_changed=true
這裏的測試代碼我放到文章最後了
INFO[2022-10-15T20:33:20+08:00] program is changed, restart it program=golang
INFO[2022-10-15T20:33:20+08:00] stop the program program=golang
INFO[2022-10-15T20:33:20+08:00] force to kill the program program=golang
INFO[2022-10-15T20:33:20+08:00] Send signal to program program=golang signal=killed
INFO[2022-10-15T20:33:20+08:00] program stopped with status:signal: killed program=golang
INFO[2022-10-15T20:33:20+08:00] program exited program=golang
INFO[2022-10-15T20:33:20+08:00] Stopped by user, don't start it again program=golang
INFO[2022-10-15T20:33:21+08:00] try to start program program=golang
DEBU[2022-10-15T20:33:21+08:00] wait program exit program=golang
INFO[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.toml
restart_when_binary_changed=true
autostart=true # 這行配置
如果管理了在線的大流量服務,推薦使用第二種,平滑重啓,因為直接kill程序,會導致請求處理一半,或事務進行到一半中止,進而數據不一致。
好的,我們再次調整配置
[program:golang]
command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.toml
restart_when_binary_changed=true
restart_signal_when_binary_changed=9 # SIGKILL
來看下日誌:
INFO[2022-10-15T20:37:58+08:00] program is changed, restart it program=golang
INFO[2022-10-15T20:37:58+08:00] Send signal to program program=golang signal=terminated
INFO[2022-10-15T20:37:58+08:00] program stopped with status:exit status 0 program=golang
INFO[2022-10-15T20:37:58+08:00] program exited program=golang
INFO[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.toml
restart_when_binary_changed=true
restart_signal_when_binary_changed=SIGHUP # 1 這裏填數字字符都行
這下重新啓動supervisor,看下效果。
程序運行日誌:
2022-10-16 11:00:27.754 [INFO] main.go:13: start
2022-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.toml
restart_when_binary_changed=true
restart_signal_when_binary_changed=SIGHUP
restart_directory_monitor=/Users/paulxu/golang/go-learn/config/
restart_signal_when_file_changed=SIGHUP
測試代碼
package main
import (
"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
}
}
}
}
最後
好的,今天給大家介紹了一款 supervior 的golang輪子,以及基本使用方法。可以看到一些常用的基礎和golang碰撞後,擦出了不一樣的火花。由於 Go 語言的編譯工具鏈會全靜態鏈接構建二進制文件,All in One 的設計理念,對運維部署時非常友好的。期待更多這樣的輪子。
雖然,在當前容器化時代,它的使用場景被進一步擠壓,但是在小型站點,實體機上使用還是很方便的。
關注我,瞭解更多golang知識~