婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Golang學習之平滑重啟

Golang學習之平滑重啟

熱門標簽:江西轉化率高的羿智云外呼系統 中國地圖標注省會高清 高德地圖標注口訣 廣州呼叫中心外呼系統 地圖標注的汽車標 南通如皋申請開通400電話 浙江高速公路地圖標注 學海導航地圖標注 西部云谷一期地圖標注

在上一篇博客介紹TOML配置的時候,講到了通過信號通知重載配置。我們在這一篇中介紹下如何的平滑重啟server。

與重載配置相同的是我們也需要通過信號來通知server重啟,但關鍵在于平滑重啟,如果只是簡單的重啟,只需要kill掉,然后再拉起即可。平滑重啟意味著server升級的時候可以不用停止業務。

我們先來看下Github上有沒有相應的庫解決這個問題,然后找到了如下三個庫:

  • facebookgo/grace - Graceful restart zero downtime deploy for Go servers.
  • fvbock/endless - Zero downtime restarts for go servers (Drop in replacement for http.ListenAndServe)
  • jpillora/overseer - Monitorable, gracefully restarting, self-upgrading binaries in Go (golang)

我們分別來學習一下,下面只講解http server的重啟。

使用方式

我們來分別使用這三個庫來做平滑重啟的事情,之后來對比其優缺點。

這三個庫的官方都給了相應的例子,例子如下:

但三個庫官方的例子不太一致,我們來統一一下:

  • grace例子 https://github.com/facebookgo/grace/blob/master/gracedemo/demo.go
  • endless例子 https://github.com/fvbock/endless/tree/master/examples
  • overseer例子 https://github.com/jpillora/overseer/tree/master/example

我們參考官方的例子分別來寫下用來對比的例子:

grace

package main

import (
  "time"
  "net/http"
  "github.com/facebookgo/grace/gracehttp"
)

func main() {
  gracehttp.Serve(
    http.Server{Addr: ":5001", Handler: newGraceHandler()},
    http.Server{Addr: ":5002", Handler: newGraceHandler()},
  )
}

func newGraceHandler() http.Handler {
  mux := http.NewServeMux()
  mux.HandleFunc("/sleep", func(w http.ResponseWriter, r *http.Request) {
    duration, err := time.ParseDuration(r.FormValue("duration"))
    if err != nil {
      http.Error(w, err.Error(), 400)
      return
    }
    time.Sleep(duration)
    w.Write([]byte("Hello World"))
  })
  return mux
}

endless

package main

import (
  "log"
  "net/http"
  "os"
  "sync"
  "time"

  "github.com/fvbock/endless"
  "github.com/gorilla/mux"
)

func handler(w http.ResponseWriter, r *http.Request) {
  duration, err := time.ParseDuration(r.FormValue("duration"))
  if err != nil {
    http.Error(w, err.Error(), 400)
    return
  }
  time.Sleep(duration)
  w.Write([]byte("Hello World"))
}

func main() {
  mux1 := mux.NewRouter()
  mux1.HandleFunc("/sleep", handler)

  w := sync.WaitGroup{}
  w.Add(2)
  go func() {
    err := endless.ListenAndServe(":5003", mux1)
    if err != nil {
      log.Println(err)
    }
    log.Println("Server on 5003 stopped")
    w.Done()
  }()
  go func() {
    err := endless.ListenAndServe(":5004", mux1)
    if err != nil {
      log.Println(err)
    }
    log.Println("Server on 5004 stopped")
    w.Done()
  }()
  w.Wait()
  log.Println("All servers stopped. Exiting.")

  os.Exit(0)
}

overseer

package main

import (
  "fmt"
  "net/http"
  "time"

  "github.com/jpillora/overseer"
)

//see example.sh for the use-case

// BuildID is compile-time variable
var BuildID = "0"

//convert your 'main()' into a 'prog(state)'
//'prog()' is run in a child process
func prog(state overseer.State) {
  fmt.Printf("app#%s (%s) listening...\n", BuildID, state.ID)
  http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    duration, err := time.ParseDuration(r.FormValue("duration"))
    if err != nil {
      http.Error(w, err.Error(), 400)
      return
    }
    time.Sleep(duration)
    w.Write([]byte("Hello World"))
    fmt.Fprintf(w, "app#%s (%s) says hello\n", BuildID, state.ID)
  }))
  http.Serve(state.Listener, nil)
  fmt.Printf("app#%s (%s) exiting...\n", BuildID, state.ID)
}

//then create another 'main' which runs the upgrades
//'main()' is run in the initial process
func main() {
  overseer.Run(overseer.Config{
    Program: prog,
    Addresses: []string{":5005", ":5006"},
    //Fetcher: fetcher.File{Path: "my_app_next"},
    Debug:  false, //display log of overseer actions
  })
}

對比

對比示例的操作步驟

  • 分別構建上面的示例,并記錄pid
  • 調用API,在其未返回時,修改內容(Hello World -> Hello Harry),重新構建。查看舊API是否返回舊的內容
  • 調用新API,查看返回的內容是否是新的內容
  • 查看當前運行的pid,是否與之前一致

下面給一下操作命令

# 第一次構建項目
go build grace.go
# 運行項目,這時就可以做內容修改了
./grace 
# 請求項目,60s后返回
curl "http://127.0.0.1:5001/sleep?duration=60s" 
# 再次構建項目,這里是新內容
go build grace.go
# 重啟,2096為pid
kill -USR2 2096
# 新API請求
curl "http://127.0.0.1:5001/sleep?duration=1s"


# 第一次構建項目
go build endless.go
# 運行項目,這時就可以做內容修改了
./endless 
# 請求項目,60s后返回
curl "http://127.0.0.1:5003/sleep?duration=60s" 
# 再次構建項目,這里是新內容
go build endless.go
# 重啟,22072為pid
kill -1 22072
# 新API請求
curl "http://127.0.0.1:5003/sleep?duration=1s"


# 第一次構建項目
go build -ldflags '-X main.BuildID=1' overseer.go
# 運行項目,這時就可以做內容修改了
./overseer 
# 請求項目,60s后返回
curl "http://127.0.0.1:5005/sleep?duration=60s" 
# 再次構建項目,這里是新內容,注意版本號不同了
go build -ldflags '-X main.BuildID=2' overseer.go
# 重啟,28300為主進程pid
kill -USR2 28300
# 新API請求
curl http://127.0.0.1:5005/sleep?duration=1s

對比結果

示例 舊API返回值 新API返回值 舊pid 新pid 結論
grace Hello world Hello Harry 2096 3100 舊API不會斷掉,會執行原來的邏輯,pid會變化
endless Hello world Hello Harry 22072 22365 舊API不會斷掉,會執行原來的邏輯,pid會變化
overseer Hello world Hello Harry 28300 28300 舊API不會斷掉,會執行原來的邏輯,主進程pid不會變化

原理分析

可以看出grace和endless是比較像的。

  • 監聽信號
  • 收到信號時fork子進程(使用相同的啟動命令),將服務監聽的socket文件描述符傳遞給子進程
  • 子進程監聽父進程的socket,這個時候父進程和子進程都可以接收請求
  • 子進程啟動成功之后,父進程停止接收新的連接,等待舊連接處理完成(或超時)
  • 父進程退出,升級完成

overseer是不同的,主要是overseer加了一個主進程管理平滑重啟,子進程處理鏈接,能夠保持主進程pid不變。

如下圖表示的很形象

自己實現

我們下面來嘗試自己實現下第一種處理,代碼如下,代碼來自《熱重啟golang服務器》:

package main
import (
  "context"
  "errors"
  "flag"
  "log"
  "net"
  "net/http"
  "os"
  "os/exec"
  "os/signal"
  "syscall"
  "time"
)

var (
  server  *http.Server
  listener net.Listener
  graceful = flag.Bool("graceful", false, "listen on fd open 3 (internal use only)")
)

func sleep(w http.ResponseWriter, r *http.Request) {
  duration, err := time.ParseDuration(r.FormValue("duration"))
  if err != nil {
    http.Error(w, err.Error(), 400)
    return
  }
  time.Sleep(duration)
  w.Write([]byte("Hello World"))
}

func main() {
  flag.Parse()

  http.HandleFunc("/sleep", sleep)
  server = http.Server{Addr: ":5007"}

  var err error
  if *graceful {
    log.Print("main: Listening to existing file descriptor 3.")
    // cmd.ExtraFiles: If non-nil, entry i becomes file descriptor 3+i.
    // when we put socket FD at the first entry, it will always be 3(0+3)
    f := os.NewFile(3, "")
    listener, err = net.FileListener(f)
  } else {
    log.Print("main: Listening on a new file descriptor.")
    listener, err = net.Listen("tcp", server.Addr)
  }

  if err != nil {
    log.Fatalf("listener error: %v", err)
  }

  go func() {
    // server.Shutdown() stops Serve() immediately, thus server.Serve() should not be in main goroutine
    err = server.Serve(listener)
    log.Printf("server.Serve err: %v\n", err)
  }()
  signalHandler()
  log.Printf("signal end")
}

func reload() error {
  tl, ok := listener.(*net.TCPListener)
  if !ok {
    return errors.New("listener is not tcp listener")
  }

  f, err := tl.File()
  if err != nil {
    return err
  }

  args := []string{"-graceful"}
  cmd := exec.Command(os.Args[0], args...)
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  // put socket FD at the first entry
  cmd.ExtraFiles = []*os.File{f}
  return cmd.Start()
}

func signalHandler() {
  ch := make(chan os.Signal, 1)
  signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR2)
  for {
    sig := -ch
    log.Printf("signal: %v", sig)

    // timeout context for shutdown
    ctx, _ := context.WithTimeout(context.Background(), 100*time.Second)
    switch sig {
    case syscall.SIGINT, syscall.SIGTERM:
      // stop
      log.Printf("stop")
      signal.Stop(ch)
      server.Shutdown(ctx)
      log.Printf("graceful shutdown")
      return
    case syscall.SIGUSR2:
      // reload
      log.Printf("reload")
      err := reload()
      if err != nil {
        log.Fatalf("graceful restart error: %v", err)
      }
      server.Shutdown(ctx)
      log.Printf("graceful reload")
      return
    }
  }
}

代碼可參考:https://github.com/CraryPrimitiveMan/go-in-action/tree/master/ch4

關于這一部分,個人的理解也不是特別深入,如果又不正確的地方請大家指正。

參考文章

熱重啟golang服務器

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • golang flag簡單用法
  • Golang中定時器的陷阱詳解
  • 在golang中操作mysql數據庫的實現代碼
  • golang設置http response響應頭與填坑記錄
  • 詳解Golang實現http重定向https的方式
  • Golang編譯器介紹

標簽:吐魯番 德宏 常州 貴州 曲靖 東營 保定 許昌

巨人網絡通訊聲明:本文標題《Golang學習之平滑重啟》,本文關鍵詞  Golang,學,習之,平滑,重啟,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Golang學習之平滑重啟》相關的同類信息!
  • 本頁收集關于Golang學習之平滑重啟的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    成人免费看片app下载| 激情综合网最新| 偷偷要91色婷婷| 久久国产尿小便嘘嘘尿| 亚洲午夜在线视频| 亚洲成a人v欧美综合天堂下载| 日韩国产高清在线| 成人视屏免费看| 欧美久久久久久久久| 精品国产亚洲一区二区三区在线观看| 久久久天堂av| 亚洲国产欧美日韩另类综合| 不卡在线观看av| 7777精品伊人久久久大香线蕉经典版下载| 2021国产精品久久精品| 日韩一区有码在线| av成人老司机| av不卡一区二区三区| 国产成人在线看| 亚洲精品国久久99热| 久久久www成人免费无遮挡大片| 久久影院视频免费| 国产激情91久久精品导航| 国产伦精品一区二区三区免费迷| 成人免费一区二区三区视频 | 亚洲妇女屁股眼交7| 欧美精品第一页| 国产成人免费在线观看不卡| 亚洲精品欧美在线| 亚洲韩国精品一区| 欧美日韩一级黄| 亚洲精品欧美综合四区| 国产v综合v亚洲欧| 日韩欧美国产一区二区在线播放| 秋霞国产午夜精品免费视频| 成人高清在线视频| 亚洲视频一区在线观看| 亚洲蜜臀av乱码久久精品| 亚洲影视资源网| 久久久午夜精品理论片中文字幕| 欧美在线|欧美| 国产永久精品大片wwwapp| 亚洲午夜日本在线观看| 中文字幕不卡三区| 日韩一区二区中文字幕| 93久久精品日日躁夜夜躁欧美| 青青青伊人色综合久久| 亚洲欧美偷拍卡通变态| 亚洲精品一区二区在线观看| 欧美三级一区二区| 色婷婷久久99综合精品jk白丝| 精品亚洲国产成人av制服丝袜| 天堂va蜜桃一区二区三区漫画版| 亚洲日本成人在线观看| 国产日韩欧美a| 精品剧情v国产在线观看在线| 欧美日韩视频在线一区二区| 在线观看区一区二| 色婷婷精品久久二区二区蜜臂av | 男男视频亚洲欧美| 亚洲在线视频一区| 久久蜜臀中文字幕| 精品裸体舞一区二区三区| 欧美人妇做爰xxxⅹ性高电影 | 99久久精品一区| 成人免费视频视频| 不卡av电影在线播放| 成人免费视频视频| 91碰在线视频| 在线观看区一区二| 91精品国产福利| 精品99999| 国产欧美日韩精品一区| 国产精品第五页| 一区二区三区成人| 日韩高清在线不卡| 国产999精品久久久久久绿帽| 99久久精品国产毛片| 91精品91久久久中77777| 7878成人国产在线观看| 欧美一二三区精品| 精品国产第一区二区三区观看体验| 久久伊人蜜桃av一区二区| 国产欧美一区二区三区在线看蜜臀 | 精品国产91乱码一区二区三区 | 欧美久久高跟鞋激| 日韩一二三区不卡| 日本一区二区三级电影在线观看| 亚洲色图欧洲色图| 蜜臀av性久久久久蜜臀aⅴ四虎 | 欧美精品三级在线观看| 精品日韩在线观看| 1024成人网| 日韩成人一区二区| 成人动漫精品一区二区| 欧美人xxxx| 国产精品色哟哟| 日韩制服丝袜av| 色呦呦国产精品| 欧美精品一区二区在线观看| 亚洲欧美日韩电影| 国产精品一区二区久激情瑜伽| 在线观看欧美精品| 亚洲国产精品av| 久久不见久久见免费视频1| 不卡在线观看av| 精品国产一区二区三区忘忧草| 亚洲免费视频成人| 国产v日产∨综合v精品视频| 欧美一区二区三区在线看| 亚洲欧洲精品一区二区三区 | 成人网在线播放| 日韩欧美一区二区在线视频| 国产精品久久久久久久岛一牛影视 | 欧洲日韩一区二区三区| 欧美精品一区二区久久久| 亚洲成人自拍一区| 成人99免费视频| 2021久久国产精品不只是精品| 午夜欧美在线一二页| 91一区一区三区| 欧美激情一区二区三区| 精品一区二区三区的国产在线播放| 亚洲电影在线免费观看| 欧美精品国产精品| 黑人巨大精品欧美一区| 亚洲人成7777| 欧美成人video| 欧美性生活久久| 91小视频在线观看| 懂色av一区二区三区蜜臀| 午夜欧美电影在线观看| 国产精品欧美久久久久一区二区| 欧美日韩国产中文| 在线观看不卡视频| 福利一区二区在线观看| 久热成人在线视频| 免费美女久久99| 亚洲图片另类小说| 亚洲一级二级三级| 国产精品久久毛片a| 5566中文字幕一区二区电影| 美女任你摸久久| 欧美一级在线视频| 日韩欧美另类在线| 欧美一级久久久久久久大片| 久久只精品国产| 色综合激情五月| 亚洲欧美一区二区久久| 久久新电视剧免费观看| 九九精品一区二区| 国产三区在线成人av| 成人av网在线| 亚洲精品成a人| 91精品国产综合久久香蕉麻豆 | 日韩一级免费观看| 久久国产精品区| 久久久精品tv| 97超碰欧美中文字幕| 亚洲123区在线观看| 日韩午夜精品电影| 成人午夜激情影院| 一区二区三区四区视频精品免费| 欧美日韩另类国产亚洲欧美一级| 日本成人在线一区| 久久人人超碰精品| 91国产丝袜在线播放| 日韩福利电影在线观看| 久久蜜桃av一区二区天堂| 99在线视频精品| 五月天欧美精品| 国产亚洲欧美激情| 色噜噜久久综合| 麻豆精品一区二区| 日韩码欧中文字| 精品粉嫩超白一线天av| 91一区二区三区在线观看| 日本在线不卡视频一二三区| 国产精品丝袜一区| 欧美一级专区免费大片| 色综合一区二区三区| 国产曰批免费观看久久久| 亚洲一区二区三区精品在线| 国产嫩草影院久久久久| 日韩一区二区三区视频在线| 91婷婷韩国欧美一区二区| 精品一区二区三区蜜桃| 亚洲成人激情社区| 亚洲欧美另类综合偷拍| 欧美激情综合五月色丁香小说| 7777女厕盗摄久久久| 97se狠狠狠综合亚洲狠狠| 国产成人精品免费网站| 日韩高清国产一区在线| 亚洲国产一区二区三区青草影视| 国产精品久久久久久久午夜片| 久久婷婷国产综合国色天香| 欧美一区二区三区电影| 91国在线观看| 在线观看日韩精品|