Go的優雅終止姿勢

部落格猿馬甲哥發表於2022-02-25

最近優化了一版程式:用到了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訊號不能被捕獲,阻塞,忽略。

我們常見的三種終止程式的操作:

  1. CTRL+C 實際是傳送SIGINT訊號,

  2. kill pid的作用是向指定程式傳送SIGTERM訊號(這是kill預設傳送的資訊), 若應用程式沒有捕獲並響應該訊號的邏輯,則該訊號預設動作是kill掉程式,這是終止程式的推薦做法。

  3. 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時間給了程式做優雅關閉的時機,所以上面程式碼的邏輯是能適配容器的。

相關文章