day 18 - graceful shutdown 优雅地退场

服务上线之後, 另一个考验才刚开始。

当流量开始进出服务之後, 如果要进行更版, 服务就需要重启或中断, 其中就有机率存在流程跑到一半的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 26 「一个巨星的诞生」Entity、Repository 与单元测试

>>:  Spring Framework X Kotlin Day 21 WebSocket

[第二十一天]从0开始的UnityAR手机游戏开发-切换Animation动画

范例小龙的动画是挂在Animation而不是Animator上,所以本次章节会教大家如何切换Anim...

惨 ...

Day18-13. Roman to Integer

今日题目:13. Roman to Integer(Easy) Roman numerals are...

Day 12 - Length of Last Word

大家好,我是毛毛。ヾ(´∀ ˋ)ノ 废话不多说开始今天的解题Day~ 58. Length of L...

Day43. 蝇量模式

本文同步更新於blog Flyweight Pattern 又称为享元模式,於相似物件中共享尽可能...