亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

go實(shí)現(xiàn)服務(wù)優(yōu)雅關(guān)閉的示例

 更新時(shí)間:2023年02月09日 09:44:28   作者:亞洲第一中鋒_哈達(dá)迪  
本文主要介紹了go實(shí)現(xiàn)服務(wù)優(yōu)雅關(guān)閉的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

為什么需要優(yōu)雅關(guān)閉

什么叫優(yōu)雅關(guān)閉?先說不優(yōu)雅關(guān)閉,就是什么都不管,強(qiáng)制關(guān)閉進(jìn)程,這會(huì)導(dǎo)致有些正在處理中的請(qǐng)求被強(qiáng)行中斷

這樣做有什么問題?

  • 用戶本次請(qǐng)求會(huì)失敗,降低用戶體驗(yàn)
  • 沒有事務(wù)的數(shù)據(jù)庫(kù)操作,會(huì)產(chǎn)生部分成功的問題,破壞原子性
  • 某些緩服務(wù)需要定期將本地緩存刷到遠(yuǎn)程db,強(qiáng)制關(guān)閉會(huì)導(dǎo)致數(shù)據(jù)丟失

優(yōu)雅關(guān)閉的核心是以下功能:

  • 如何監(jiān)聽退出信號(hào)
  • 如何拒絕新請(qǐng)求
  • 如何等待進(jìn)行中的請(qǐng)求處理完畢

監(jiān)控服務(wù)退出信號(hào)

在go中使用下面的代碼監(jiān)聽退出信號(hào),如果c返回,說明監(jiān)聽到信號(hào)

不同的操作系統(tǒng)監(jiān)聽不同的退出信號(hào)

c := make(chan os.Signal, 1)
signals := []os.Signal{
   syscall.SIGINT,
   syscall.SIGTERM,
   syscall.SIGQUIT,
}

signal.Notify(c, signals...)
<-c

拒絕新請(qǐng)求

go在1.8后增加了shutdown方法來,我們看看它怎么實(shí)現(xiàn)優(yōu)雅關(guān)閉:

srv.inShutdown.setTrue()
lnerr := srv.closeListenersLocked()
srv.closeDoneChanLocked()
  • 設(shè)置inShutdown標(biāo)志位
  • 關(guān)閉所有的listener
  • 關(guān)閉doneChan

這一段對(duì)應(yīng)到http服務(wù)接收請(qǐng)求的流程:

for {
   rw, err := l.Accept()
   if err != nil {
      select {
      case <-srv.getDoneChan():
         return ErrServerClosed
   // ...       
}

一旦關(guān)閉listener,關(guān)閉doneChan后,http服務(wù)就不會(huì)再接收新的請(qǐng)求,直接返回

執(zhí)行關(guān)閉之前的回調(diào)

for _, f := range srv.onShutdown {
   go f()
}

這里的回調(diào)實(shí)現(xiàn)得比較粗糙:

  • 沒有優(yōu)先級(jí)的概念,所有回調(diào)并發(fā)執(zhí)行,因此需要保證回調(diào)之間沒有依賴
  • 雖然回調(diào)不適合長(zhǎng)時(shí)間運(yùn)行,但Go http沒有提供機(jī)制來保證這些回調(diào)一定能執(zhí)行完畢,若想做到這點(diǎn)需要自己處理

等待處理中的請(qǐng)求執(zhí)行完畢

設(shè)置標(biāo)識(shí)位可以拒絕新的請(qǐng)求,但依舊在執(zhí)行的請(qǐng)求還在處理中,需要等這些請(qǐng)求執(zhí)行完畢

等待處理中的請(qǐng)求執(zhí)行完畢有兩種思路:

  • 等待一段固定的時(shí)間
  • 實(shí)時(shí)維護(hù)請(qǐng)求的計(jì)數(shù)

go選擇了兩種方式結(jié)合的模式,通過ctx設(shè)置一個(gè)最大的等待時(shí)間,同時(shí)不斷輪詢正在請(qǐng)求中的計(jì)數(shù)

ctx超時(shí)或者計(jì)數(shù)變?yōu)?,都會(huì)返回

timer := time.NewTimer(nextPollInterval())
defer timer.Stop()
for {
   if srv.closeIdleConns() && srv.numListeners() == 0 {
      return lnerr
   }
   select {
   case <-ctx.Done():
      return ctx.Err()
   case <-timer.C:
      timer.Reset(nextPollInterval())
   }
}

這里每隔一定時(shí)間檢查已有請(qǐng)求是否執(zhí)行完畢,如果執(zhí)行完畢,或者外部通過ctx設(shè)置的超時(shí)到期就會(huì)返回

檢查間隔是多少?

  • 從1ms開始,每輪檢查后倍增,最大500ms

怎么判斷是否執(zhí)行完畢?

  • 所有的連接都關(guān)閉
  • 所有的listener都關(guān)閉

服務(wù)收到監(jiān)聽信號(hào)返回之前,關(guān)閉連接和listener,會(huì)被這里檢查到

在這里插入圖片描述

實(shí)戰(zhàn)

func main() {
   // 注冊(cè)路由
   http.Handle("/aaa", http.HandlerFunc(func(writer http.ResponseWriter, req *http.Request) {
      time.Sleep(time.Second * 10)
      fmt.Println(111)
   }))
   server := http.Server{
      Addr:    "localhost:8080",
      Handler: http.DefaultServeMux,
   }

   close := make(chan int)
   go func() {
      quit := make(chan os.Signal)
      signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
      <-quit

      ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
      defer cancel()
      err := server.Shutdown(ctx)
      log.Print(err)
      
      // 控制外層退出
      close <- 1
   }()

   err := server.ListenAndServe()
   fmt.Println(err)

   <-close
}

該代碼做了下面的事:

  • 注冊(cè)一個(gè)10s才返回的路由處理函數(shù)
  • 開子協(xié)程監(jiān)聽OS的退出信號(hào),如果監(jiān)聽到了開始進(jìn)行優(yōu)雅關(guān)閉,雖多等待30s
  • 主協(xié)程調(diào)用 server.ListenAndServe(),開始監(jiān)聽請(qǐng)求

需要注意的是,一定要在子協(xié)程中優(yōu)雅關(guān)閉結(jié)束后,主協(xié)程才能退出,這里用channel控制

因?yàn)橹鲄f(xié)程發(fā)現(xiàn)doneChan被關(guān)閉時(shí)會(huì)馬上返回,但此時(shí)主協(xié)程開的業(yè)務(wù)處理協(xié)程還在進(jìn)行中,如果主協(xié)程此時(shí)退出,無法達(dá)到優(yōu)雅關(guān)閉的效果

按照以下流程測(cè)試:

  • 啟動(dòng) Web 服務(wù)
  • 在瀏覽器請(qǐng)求http://localhost:8080/aaa
  • 過5秒后在控制臺(tái)按下ctrl+c
  • 觀察控制臺(tái)程序是否不會(huì)立刻結(jié)束,而是在 10s 后結(jié)束

支持強(qiáng)制退出

既然有優(yōu)雅退出,那就有強(qiáng)制退出,我們假設(shè)如果按下兩次ctrl+c,代表用戶希望服務(wù)強(qiáng)制退出:

close := make(chan int, 2)
go func() {
   quit := make(chan os.Signal)
   signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
   <-quit
   go func() {
      <-quit
      os.Exit(1)
   }()

   // ...
}()

做法很簡(jiǎn)單,收到第一個(gè)退出信號(hào)后,再開一個(gè)子協(xié)程,如果再收到退出信號(hào),就調(diào)用os.Exit退出進(jìn)程

并且close channel的容量需要為2,避免當(dāng)兩次退出信號(hào)過短時(shí)丟失信號(hào)

到此這篇關(guān)于go實(shí)現(xiàn)服務(wù)優(yōu)雅關(guān)閉的示例的文章就介紹到這了,更多相關(guān)go 服務(wù)關(guān)閉內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺析GO語(yǔ)言的垃圾回收機(jī)制

    淺析GO語(yǔ)言的垃圾回收機(jī)制

    今天我們來聊聊golang是如何進(jìn)行垃圾回收的,我們知道,目前各語(yǔ)言進(jìn)行垃圾回收的方法有很多,如引用計(jì)數(shù)、標(biāo)記清除、分代回收、三色標(biāo)記等,各種方式都有其特點(diǎn),文中介紹的非常詳細(xì),感興趣的小伙伴跟著小編一起學(xué)習(xí)吧
    2023-07-07
  • golang?gorm的預(yù)加載及軟刪硬刪的數(shù)據(jù)操作示例

    golang?gorm的預(yù)加載及軟刪硬刪的數(shù)據(jù)操作示例

    這篇文章主要介紹了golang?gorm的預(yù)加載及軟刪硬刪的數(shù)據(jù)操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go錯(cuò)誤和異常CGO?fallthrough處理教程詳解

    Go錯(cuò)誤和異常CGO?fallthrough處理教程詳解

    這篇文章主要為大家介紹了Go錯(cuò)誤和異常CGO?fallthrough使用教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Golang實(shí)現(xiàn)單元測(cè)試中的接口層

    Golang實(shí)現(xiàn)單元測(cè)試中的接口層

    接口層主要負(fù)責(zé)的就是請(qǐng)求的處理,最常見的就是?HTTP?請(qǐng)求的處理。這篇文章主要為大家介紹了Golang如何實(shí)現(xiàn)單元測(cè)試中的接口層,需要的可以參考一下
    2023-03-03
  • Golang使用Swagger文檔教程詳解

    Golang使用Swagger文檔教程詳解

    這篇文章主要為大家詳細(xì)介紹Golang使用Swagger文檔教程的相關(guān)知識(shí),文中通過示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以學(xué)習(xí)一下
    2023-12-12
  • 攔截信號(hào)Golang應(yīng)用優(yōu)雅關(guān)閉的操作方法

    攔截信號(hào)Golang應(yīng)用優(yōu)雅關(guān)閉的操作方法

    這篇文章主要介紹了攔截信號(hào)優(yōu)雅關(guān)閉Golang應(yīng)用,本文介紹了信號(hào)的概念及常用信號(hào),并給出了應(yīng)用廣泛的幾個(gè)示例,例如優(yōu)雅地關(guān)閉應(yīng)用服務(wù)、在命令行應(yīng)用中接收終止命令,需要的朋友可以參考下
    2023-02-02
  • 盤點(diǎn)幾種Go語(yǔ)言開發(fā)的IDE

    盤點(diǎn)幾種Go語(yǔ)言開發(fā)的IDE

    Go語(yǔ)言作為一種新興的編程語(yǔ)言,近年來受到了越來越多的關(guān)注,它以其簡(jiǎn)潔、高效和并發(fā)性能而聞名,被廣泛應(yīng)用于各種軟件開發(fā)項(xiàng)目中,本文將介紹幾種常用的Go語(yǔ)言IDE,并對(duì)它們進(jìn)行比較,幫助開發(fā)者根據(jù)自己的需求選擇合適的工具,需要的朋友可以參考下
    2023-11-11
  • Golang使用channel實(shí)現(xiàn)一個(gè)優(yōu)雅退出功能

    Golang使用channel實(shí)現(xiàn)一個(gè)優(yōu)雅退出功能

    最近補(bǔ)?Golang?channel?方面八股的時(shí)候發(fā)現(xiàn)用?channel?實(shí)現(xiàn)一個(gè)優(yōu)雅退出功能好像不是很難,之前寫的?HTTP?框架剛好也不支持優(yōu)雅退出功能,于是就參考了?Hertz?優(yōu)雅退出方面的代碼,為我的?PIANO?補(bǔ)足了這個(gè)?feature
    2023-03-03
  • Go庫(kù)text與template包使用示例詳解

    Go庫(kù)text與template包使用示例詳解

    這篇文章主要為大家介紹了Go庫(kù)text與template包使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Golang 實(shí)現(xiàn)獲取當(dāng)前函數(shù)名稱和文件行號(hào)等操作

    Golang 實(shí)現(xiàn)獲取當(dāng)前函數(shù)名稱和文件行號(hào)等操作

    這篇文章主要介紹了Golang 實(shí)現(xiàn)獲取當(dāng)前函數(shù)名稱和文件行號(hào)等操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05

最新評(píng)論