iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 11
1
自我挑戰組

Let's Eat GO ! 實務開發雜談by Golang系列 第 11

Day11 .[正確資料篇] graceful shutdown & restart

  • 分享至 

  • xImage
  •  

說明

在php專案,如果遇到程式要修正,要重新發佈,那麼就直接把程式丟上去就好啦,因為是直譯式的語言,程式是執行到哪裡,才看哪裡。於是有更新的話,程式下次執行到有做更新的部分,看到的是新的內容,而不是舊的。

Golang就不一樣,編譯好的內容一但執行下去,它就把這些內容放到記憶體了,再怎麼改原始碼或重新編譯,都不會影響到目前正在執行的process。

有別於此,正在上線的Golang程式服務,若遇到緊急需要更新或者改版?要怎麼操作呢?總不能每次都掛維護,再來砍掉process,執行重新編譯好的檔案吧!如果process還有工作或服務正做到一半,你砍掉process等於強制中斷這些工作,可能影響使用者體驗,甚至資料正確性。

若等工作做完再砍掉目前執行的process呢?你的新問題會是:我要怎麼才能知道目前工作已做完,並且阻止新工作進來?

除了在load balance機器調整或設定,你有更好的做法。

graceful shutdown

對岸翻作『優雅關閉』,我個人是傾向專有名詞還是用原文來表示的好,但意思都一樣。

graceful shutdown 簡單來說,就是process收到關閉訊息時候,先把訊息擺在一邊,把目前手邊工作做完,再做關閉。

這是一種人為實作的機制,並不是程式就天生有附帶這種效果,你要說這是一種design pattern也可以。

粗暴一點的講法是:你寫一段code去攔截送到os的關閉signal,先立某個即將關閉的flag,程式每次執行到某個階段(結束),檢查到這個flag有立起,則進行os.exit等類似的關閉method。

如下面程式碼是我們的應用

{
	// 開始排程
	log.Println("INFO", `start`)
	bg.Start()
	// 等待結束訊號
	<-gracefulShutdown()
    
	log.Println("WARNIGN", `received singal`)
	// 停止排程
	bg.Stop()
	// 等待背景結束
	for _, job := range jobs {
		job.Wait()
	}
	log.Println("INFO", `end`)
}

func gracefulShutdown() (sig chan os.Signal) {
	sig = make(chan os.Signal)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
	return
}


在gracefulShutdown() 未攔截到關閉的訊號茲前,排程job一直處理正常運作的狀況,一但gracefulShutdown()攔截到訊號後,channel就無法繼續卡住,而執行了bg.Stop(),這時排成job就會依序關閉,並不再啟動新工作。

graceful restart

對岸翻作『優雅重啟』,是更一步的進化版,通常你想要關閉運行中的程式,可能是為了換成新的程式編譯檔。graceful restart就是以graceful shutdown的方式殺掉process,再重新掛上的process的機制。

概念和做法可以參考下面這個facebook提供的開源套件,若仔細研究一下,你會發現好像不是什麼特別的東西。

概念是它找到目前process的環境參數,在啟動新的process的時候,把他帶過去,內容的關鍵流程大致如下。

facebook開源專案

  1. kill 的時候帶入-USR2 讓程式知道你要優雅關閉
    kill -USR2

  2. 尋找執行檔路徑(你要重新掛程式,可以在這之前先重新編譯過)
    exec.LookPath()

  3. 取得環境變數
    os.Getwd()

  4. 帶入就環境變數,啟動新的process
    os.StartProcess

這篇短介是實務上我們遇到非常需要的知識重點,希望有幫助到類似需求的開發人員。


上一篇
Day10 .[正確資料篇] 浮點數運算請decimal package協助
下一篇
Day12 .[正確資料篇] 不要用time.time型態的資料insert到MySql Datetime欄位
系列文
Let's Eat GO ! 實務開發雜談by Golang30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言