成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一文講懂服務的優雅重啟和更新

開發 架構
在重啟過程中,會有一段時間不能給用戶提供正常服務;同時粗魯關閉服務,也可能會對業務依賴的數據庫等狀態服務造成污染。所以我們服務重啟或者是重新發布過程中,要做到新舊服務無縫切換,同時可以保障變更服務 零宕機時間!

[[404467]]

本文轉載自微信公眾號「微服務實踐」,作者hxl。轉載本文請聯系微服務實踐公眾號。   

在服務端程序更新或重啟時,如果我們直接 kill -9 殺掉舊進程并啟動新進程,會有以下幾個問題:

  1. 舊的請求未處理完,如果服務端進程直接退出,會造成客戶端鏈接中斷(收到 RST)
  2. 新請求打過來,服務還沒重啟完畢,造成 connection refused
  3. 即使是要退出程序,直接 kill -9 仍然會讓正在處理的請求中斷

很直接的感受就是:在重啟過程中,會有一段時間不能給用戶提供正常服務;同時粗魯關閉服務,也可能會對業務依賴的數據庫等狀態服務造成污染。

所以我們服務重啟或者是重新發布過程中,要做到新舊服務無縫切換,同時可以保障變更服務 零宕機時間!

作為一個微服務框架,那 go-zero 是怎么幫開發者做到優雅退出的呢?下面我們一起看看。

優雅退出

在實現優雅重啟之前首先需要解決的一個問題是 如何優雅退出:

對 http 服務來說,一般的思路就是關閉對 fd 的 listen , 確保不會有新的請求進來的情況下處理完已經進入的請求, 然后退出。

go 原生中 http 中提供了 server.ShutDown(),先來看看它是怎么實現的:

  1. 設置 inShutdown 標志
  2. 關閉 listeners 保證不會有新請求進來
  3. 等待所有活躍鏈接變成空閑狀態
  4. 退出函數,結束

分別來解釋一下這幾個步驟的含義:

inShutdown

  1. func (srv *Server) ListenAndServe() error { 
  2.     if srv.shuttingDown() { 
  3.         return ErrServerClosed 
  4.     } 
  5.     .... 
  6.     // 實際監聽端口;生成一個 listener 
  7.     ln, err := net.Listen("tcp", addr) 
  8.     if err != nil { 
  9.         return err 
  10.     } 
  11.     // 進行實際邏輯處理,并將該 listener 注入 
  12.     return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) 
  13.  
  14. func (s *Server) shuttingDown() bool { 
  15.   return atomic.LoadInt32(&s.inShutdown) != 0 

ListenAndServe 是http啟動服務器的必經函數,里面的第一句就是判斷 Server 是否被關閉了。

inShutdown 就是一個原子變量,非0表示被關閉。

listeners

  1. func (srv *Server) Serve(l net.Listener) error { 
  2.     ... 
  3.     // 將注入的 listener 加入內部的 map 中 
  4.     // 方便后續控制從該 listener 鏈接到的請求 
  5.     if !srv.trackListener(&l, true) { 
  6.         return ErrServerClosed 
  7.     } 
  8.     defer srv.trackListener(&l, false
  9.    ... 

Serve 中注冊到內部 listeners map 中 listener,在 ShutDown 中就可以直接從 listeners 中獲取到,然后執行 listener.Close(),TCP四次揮手后,新的請求就不會進入了。

closeIdleConns

簡單來說就是:將目前 Server 中記錄的活躍鏈接變成變成空閑狀態,返回。

關閉

  1. func (srv *Server) Serve(l net.Listener) error { 
  2.   ... 
  3.   for { 
  4.     rw, err := l.Accept() 
  5.     // 此時 accept 會發生錯誤,因為前面已經將 listener close了 
  6.     if err != nil { 
  7.       select { 
  8.       // 又是一個標志:doneChan 
  9.       case <-srv.getDoneChan(): 
  10.         return ErrServerClosed 
  11.       default
  12.       } 
  13.     } 
  14.   } 

其中 getDoneChan 中已經在前面關閉 listener 時,對 doneChan 這個channel中push。

總結一下:Shutdown 可以優雅的終止服務,期間不會中斷已經活躍的鏈接。

但服務啟動后的某一時刻,程序如何知道服務被中斷了呢?服務被中斷時如何通知程序,然后調用Shutdown作處理呢?接下來看一下系統信號通知函數的作用

服務中斷

這個時候就要依賴 OS 本身提供的 signal。對應 go 原生來說,signal 的 Notify 提供系統信號通知的能力。

https://github.com/tal-tech/go-zero/blob/master/core/proc/signals.go

  1. func init() { 
  2.   go func() { 
  3.     var profiler Stopper 
  4.      
  5.     signals := make(chan os.Signal, 1) 
  6.     signal.Notify(signals, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGTERM) 
  7.  
  8.     for { 
  9.       v := <-signals 
  10.       switch v { 
  11.       case syscall.SIGUSR1: 
  12.         dumpGoroutines() 
  13.       case syscall.SIGUSR2: 
  14.         if profiler == nil { 
  15.           profiler = StartProfile() 
  16.         } else { 
  17.           profiler.Stop() 
  18.           profiler = nil 
  19.         } 
  20.       case syscall.SIGTERM: 
  21.         // 正在執行優雅關閉的地方 
  22.         gracefulStop(signals) 
  23.       default
  24.         logx.Error("Got unregistered signal:", v) 
  25.       } 
  26.     } 
  27.   }() 
  • SIGUSR1 -> 將 goroutine 狀況,dump下來,這個在做錯誤分析時還挺有用的
  • SIGUSR2 -> 開啟/關閉所有指標監控,自行控制 profiling 時長
  • SIGTERM -> 真正開啟 gracefulStop,優雅關閉

而 gracefulStop 的流程如下:

  1. 取消監聽信號,畢竟要退出了,不需要重復監聽了
  2. wrap up,關閉目前服務請求,以及資源
  3. time.Sleep() ,等待資源處理完成,以后關閉完成
  4. shutdown ,通知退出
  5. 如果主goroutine還沒有退出,則主動發送 SIGKILL 退出進程

這樣,服務不再接受新的請求,服務活躍的請求等待處理完成,同時也等待資源關閉(數據庫連接等),如有超時,強制退出。

整體流程

我們目前 go 程序都是在 docker 容器中運行,所以在服務發布過程中,k8s 會向容器發送一個 SIGTERM 信號,然后容器中程序接收到信號,開始執行 ShutDown:

到這里,整個優雅關閉的流程就梳理完畢了。

但是還有平滑重啟,這個就依賴 k8s 了,基本流程如下:

  • old pod 未退出之前,先啟動 new pod
  • old pod 繼續處理完已經接受的請求,并且不再接受新請求
  • new pod接受并處理新請求的方式
  • old pod 退出

這樣整個服務重啟就算是成功了,如果 new pod 沒有啟動成功,old pod 也可以提供服務,不會對目前線上的服務造成影響。

項目地址

https://github.com/tal-tech/go-zero

歡迎使用 go-zero 并 star 支持我們!

 

責任編輯:武曉燕 來源: 微服務實踐
相關推薦

2021-09-03 05:03:58

模塊命令項目

2020-03-26 09:18:54

高薪本質因素

2025-01-13 12:00:00

反射Java開發

2025-01-20 09:15:00

iOS 18.3蘋果iOS 18

2019-09-23 10:51:14

JavaJava虛擬機Linux

2019-10-12 08:59:36

軟件DevOps技術

2024-08-13 17:09:00

架構分庫分表開發

2020-07-16 09:02:45

aPaaS云計算aPaaS平臺

2020-08-04 10:56:09

進程線程協程

2022-02-15 08:38:04

錯誤邏輯異常編程程序

2023-11-09 08:41:25

DevOpsAIOps軟件

2020-12-03 08:23:23

函數柯里化代碼

2020-05-20 09:55:42

Git底層數據

2025-01-02 11:55:08

HashMapJava哈希沖突

2021-01-18 13:05:52

Serverless Serverfull FaaS

2020-12-01 11:34:14

Elasticsear

2020-01-02 09:06:23

微服務數據框架

2019-03-14 15:59:44

前端開發編程

2018-05-10 10:53:47

分布式架構負載均衡Web

2019-04-22 15:09:24

云計算KVMXEN
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲欧美日韩久久 | 久久国产激情视频 | a级黄色网 | 日韩在线欧美 | 婷婷综合色| 国产高清免费 | 欧美日韩视频 | 中文字幕一级毛片 | 国产精品久久久久久久久久软件 | 亚洲精品成人在线 | 在线午夜| 中文字幕一区二区三区四区五区 | 亚洲一区中文 | 成人三级视频 | 国产探花在线精品一区二区 | 精品综合久久 | 国产成人精品一区二区三区在线 | 97人人超碰 | 日本精品一区二区三区视频 | 狠狠婷婷综合久久久久久妖精 | 国产精品96久久久久久 | 久久久免费 | 精品久久久久久久久久久久 | 一级在线毛片 | 午夜免费福利片 | 国产欧美精品一区 | 国产一区二区自拍 | 91资源在线| 国产精品夜色一区二区三区 | 国产成人免费视频网站视频社区 | 狠狠躁夜夜躁人人爽天天高潮 | 99这里只有精品视频 | 亚洲成人精品视频 | 国产一区二区成人 | 日韩午夜激情 | 亚洲综合视频一区 | 亚洲精品中文字幕 | 午夜精品一区二区三区三上悠亚 | 国产精品海角社区在线观看 | 人人澡人人爱 | 亚洲国产成人精 |