iT邦幫忙

2021 iThome 鐵人賽

DAY 18
0

服務上線之後, 另一個考驗才剛開始。

當流量開始進出服務之後, 如果要進行更版, 服務就需要重啟或中斷, 其中就有機率存在流程跑到一半的request。
如果是一個查詢的request, 那就等服務恢復再查一次就好;
如果是幾筆異動資料的request, 或許log有寫好, 要人工重做或補資料也還可以;
那如果是一批大量異動重要資料的request呢? 像是要發整批獎金給一萬名員工, 然後request跑到一半中斷了, 要怎麼判斷誰發了?誰沒發?
如果真的發生重要資料異動被中斷的狀況, 工程師大概會補資料補到焦頭爛額吧......

為了避免request被中斷的悲劇, 我們可以在服務裡面增加處理gracefult shutdown, 讓服務優雅地退出。
gracefult shutdown主要會做兩個行為:

  1. 關閉服務Port, 不再收新的request
  2. 等待, 直到所有連線關閉

gRPC套件有提供GracefulStop()可以使用, 在程式裡面加上一行grpcServer.GracefulStop()即可,
保險起見還可以加上幾秒的 Sleep 卡住程式, 讓他多等一下再退出。

  • cmd.go 直接加上 grpcServer.GracefulStop() 以及 time.Sleep 讓服務做到gracefult shutdown
	//阻塞直到有信號傳入
	s := <-shutdownObserver
	Logger.Debugf(`Receive signal: %s`, s)

	// 優雅停止GRPC服務
	grpcServer.GracefulStop()

	// 避免有執行完的動作,休息一下再退出
	for t := 10; t > 0; t-- {
		log.Printf("休息%d秒後準備退出", t)
		time.Sleep(time.Second * 1)
	}
  • 執行 ctrl+C 退出服務可以看到退出前log, 服務會再等幾秒才退出
{"level":"info","msg":"Receive signal: interrupt","time":"2021-09-24T09:15:23+08:00"}
2021/09/24 09:15:23 休息10秒後準備退出
2021/09/24 09:15:24 休息9秒後準備退出
2021/09/24 09:15:25 休息8秒後準備退出
2021/09/24 09:15:26 休息7秒後準備退出
2021/09/24 09:15:27 休息6秒後準備退出
2021/09/24 09:15:28 休息5秒後準備退出
2021/09/24 09:15:29 休息4秒後準備退出
2021/09/24 09:15:30 休息3秒後準備退出
2021/09/24 09:15:31 休息2秒後準備退出
2021/09/24 09:15:32 休息1秒後準備退出

在K8s的環境底下, Pod如果發生非預期的中斷時, pod會自動重啟, 可是一樣會有request執行到一半的風險, 尤其是在微服務的分工拆分底下, 一個request的中斷可能連帶很多服務都會因為資料回應不完整而卡在某個未完成的狀態, 所以做好 graceful shutdown 可以幫工程師省去很多補資料、對資料的時間, 如果用的不是gRPC, Go針對http也有提供Shutdown可以使用。
或者也可以使用channel & sync.WaitGroup 自己實作gracefule shutdown的效果!

參考資料

  1. [Go 教學] graceful shutdown with multiple workers

上一篇
day 17 - 利用 interface 來mock外部回應
下一篇
day 19 - health check 讓k8s幫忙關懷服務
系列文
Let's Go! 解剖Go server開發到部署的過程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言