最近優化了一版程式:用到了golang的優雅退出機制。
程式使用etcd的election sdk
做高可用選主,需要在節點意外下線的時候,主動去etcd卸任(刪除10s租約), 否則已經下線的節點還會被etcd認為是leader。
所以在這裡,優雅退出是技術剛需。
另外根據[雲原生十二要素方法論] 第9條: 快速啟動和優雅終止可最大化健壯性 , 也推薦各位遵守實踐。
Fast startup and shutdown are advocated for a more robust and resilient system.
粗淺的認知方案: 捕獲程式的終止訊號, 主動去卸任。
標準訊號
Linux支援如下標準訊號,第二列指示該訊號遵守的標準。
Signal Standard Action Comment
────────────────────────────────────────────────────────────────────────
SIGABRT P1990 Core Abort signal from abort(3)
SIGALRM P1990 Term Timer signal from alarm(2)
SIGBUS P2001 Core Bus error (bad memory access)
SIGCHLD P1990 Ign Child stopped or terminated
SIGCLD - Ign A synonym for SIGCHLD
SIGCONT P1990 Cont Continue if stopped
SIGEMT - Term Emulator trap
SIGFPE P1990 Core Floating-point exception
SIGHUP P1990 Term Hangup detected on controlling terminal
or death of controlling process
SIGILL P1990 Core Illegal Instruction
SIGINFO - A synonym for SIGPWR
SIGINT P1990 Term Interrupt from keyboard
SIGIO - Term I/O now possible (4.2BSD)
SIGIOT - Core IOT trap. A synonym for SIGABRT
SIGKILL P1990 Term Kill signal
SIGLOST - Term File lock lost (unused)
SIGPIPE P1990 Term Broken pipe: write to pipe with no
readers; see pipe(7)
SIGPOLL P2001 Term Pollable event (Sys V);
synonym for SIGIO
SIGPROF P2001 Term Profiling timer expired
SIGPWR - Term Power failure (System V)
SIGQUIT P1990 Core Quit from keyboard
SIGSEGV P1990 Core Invalid memory reference
SIGSTKFLT - Term Stack fault on coprocessor (unused)
SIGSTOP P1990 Stop Stop process
SIGTSTP P1990 Stop Stop typed at terminal
SIGSYS P2001 Core Bad system call (SVr4);
see also seccomp(2)
SIGTERM P1990 Term Termination signal
SIGTRAP P2001 Core Trace/breakpoint trap
SIGTTIN P1990 Stop Terminal input for background process
SIGTTOU P1990 Stop Terminal output for background process
SIGUNUSED - Core Synonymous with SIGSYS
SIGURG P2001 Ign Urgent condition on socket (4.2BSD)
SIGUSR1 P1990 Term User-defined signal 1
SIGUSR2 P1990 Term User-defined signal 2
SIGVTALRM P2001 Term Virtual alarm clock (4.2BSD)
SIGXCPU P2001 Core CPU time limit exceeded (4.2BSD);
see setrlimit(2)
SIGXFSZ P2001 Core File size limit exceeded (4.2BSD);
see setrlimit(2)
SIGWINCH - Ign Window resize signal (4.3BSD, Sun)
其中SIGKILL
,SIGSTOP
訊號不能被捕獲,阻塞,忽略。
我們常見的三種終止程式的操作:
-
CTRL+C
實際是傳送SIGINT
訊號, -
kill pid
的作用是向指定程式傳送SIGTERM
訊號(這是kill預設傳送的資訊), 若應用程式沒有捕獲並響應該訊號的邏輯,則該訊號預設動作是kill掉程式,這是終止程式的推薦做法。 -
kill -9 pid
則是向指定程式傳送SIGKILL
訊號,SIGKILL訊號既不能被應用程式捕獲,也不能被阻塞或忽略,
故要達成我們的目的,這裡捕獲 SIGINT
SIGTREM
訊號就可滿足需求。
golang提供signal
包來監聽並反饋收到的訊號。
可針對長時間執行的程式,新開協程,持續監聽訊號,並插入優雅關閉的程式碼。
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
go func() {
select {
case sig:= <-c: {
log.Infof("Got %s signal. Aborting...\n", sig)
eCli.Close() // 利用 etcd election sdk主動卸任
os.Exit(1)
}
}
}()
是不是依舊適配容器?
我們得看DOCKER官方docker stop
,docker kill
命令的定義。
docker stop: The main process inside the container will receiver SIGTREM, and after a grace period,SIGKILL .(default grace period =10s)
docker kill:The main process inside the container is sent SIGKILL signal (default), or the signal that is specified with the --signal option
我們常用的docker stop命令: 向容器內程式傳送SIGTREM
訊號,10s後傳送SIGKILL
訊號,這10s時間給了程式做優雅關閉的時機,所以上面程式碼的邏輯是能適配容器的。