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

詳解如何熱重啟golang服務(wù)器

 更新時(shí)間:2018年08月16日 14:13:20   作者:black_ox  
這篇文章主要介紹了詳解如何熱重啟golang服務(wù)器,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

服務(wù)端代碼經(jīng)常需要升級(jí),對(duì)于線上系統(tǒng)的升級(jí)常用的做法是,通過(guò)前端的負(fù)載均衡(如nginx)來(lái)保證升級(jí)時(shí)至少有一個(gè)服務(wù)可用,依次(灰度)升級(jí)。

而另一種更方便的方法是在應(yīng)用上做熱重啟,直接升級(jí)應(yīng)用而不停服務(wù)。

原理

熱重啟的原理非常簡(jiǎn)單,但是涉及到一些系統(tǒng)調(diào)用以及父子進(jìn)程之間文件句柄的傳遞等等細(xì)節(jié)比較多。
處理過(guò)程分為以下幾個(gè)步驟:

  • 監(jiān)聽(tīng)信號(hào)(USR2)
  • 收到信號(hào)時(shí)fork子進(jìn)程(使用相同的啟動(dòng)命令),將服務(wù)監(jiān)聽(tīng)的socket文件描述符傳遞給子進(jìn)程
  • 子進(jìn)程監(jiān)聽(tīng)父進(jìn)程的socket,這個(gè)時(shí)候父進(jìn)程和子進(jìn)程都可以接收請(qǐng)求
  • 子進(jìn)程啟動(dòng)成功之后,父進(jìn)程停止接收新的連接,等待舊連接處理完成(或超時(shí))
  • 父進(jìn)程退出,升級(jí)完成

細(xì)節(jié)

  • 父進(jìn)程將socket文件描述符傳遞給子進(jìn)程可以通過(guò)命令行,或者環(huán)境變量等
  • 子進(jìn)程啟動(dòng)時(shí)使用和父進(jìn)程一樣的命令行,對(duì)于golang來(lái)說(shuō)用更新的可執(zhí)行程序覆蓋舊程序
  • server.Shutdown()優(yōu)雅關(guān)閉方法是go1.8的新特性
  • server.Serve(l)方法在Shutdown時(shí)立即返回,Shutdown方法則阻塞至context完成,所以Shutdown的方法要寫在主goroutine中

代碼

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 handler(w http.ResponseWriter, r *http.Request) {
  time.Sleep(20 * time.Second)
  w.Write([]byte("hello world233333!!!!"))
}
 
func main() {
  flag.Parse()
 
  http.HandleFunc("/hello", handler)
  server = &http.Server{Addr: ":9999"}
 
  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(), 20*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
    }
  }
}

references

Graceful Restart in Golang

facebookgo/grace

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Go 容器遍歷的實(shí)現(xiàn)示例

    Go 容器遍歷的實(shí)現(xiàn)示例

    Go 語(yǔ)言提供的基礎(chǔ)容器,免不了要查詢?nèi)萜髦械臄?shù)據(jù),那么是如何實(shí)現(xiàn)遍歷的呢?本文將會(huì)介紹幾種常用容易的遍歷及其使用。感興趣的可以了解一下
    2021-06-06
  • Go?net?http超時(shí)應(yīng)用場(chǎng)景全面詳解

    Go?net?http超時(shí)應(yīng)用場(chǎng)景全面詳解

    HTTP是一個(gè)復(fù)雜的多階段協(xié)議,因此沒(méi)有一個(gè)一刀切的超時(shí)解決方案,在這篇文章中,我將分解您可能需要應(yīng)用超時(shí)的各個(gè)階段,并研究在服務(wù)器端和客戶端上執(zhí)行超時(shí)的不同方法
    2024-01-01
  • go modules中replace使用方法

    go modules中replace使用方法

    這篇文章主要為大家介紹了go modules中replace使用方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 解決Golang json序列化字符串時(shí)多了\的情況

    解決Golang json序列化字符串時(shí)多了\的情況

    這篇文章主要介紹了解決Golang json序列化字符串時(shí)多了\的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • 文字解說(shuō)Golang Goroutine和線程的區(qū)別

    文字解說(shuō)Golang Goroutine和線程的區(qū)別

    goroutine 是 Go語(yǔ)言中的輕量級(jí)線程實(shí)現(xiàn),由 Go 運(yùn)行時(shí)(runtime)管理,使用每一個(gè) go 關(guān)鍵字將會(huì)額外開啟一個(gè)新的協(xié)程 goroutine,今天通過(guò)本文給大家介紹下Golang Goroutine和線程的區(qū)別,感興趣的朋友一起看看吧
    2022-03-03
  • Go語(yǔ)言實(shí)現(xiàn)機(jī)器大小端判斷代碼分享

    Go語(yǔ)言實(shí)現(xiàn)機(jī)器大小端判斷代碼分享

    這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)機(jī)器大小端判斷代碼分享,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2014-10-10
  • go語(yǔ)言中time包的各種函數(shù)總結(jié)

    go語(yǔ)言中time包的各種函數(shù)總結(jié)

    時(shí)間和日期是我們編程中經(jīng)常會(huì)用到的,下面這篇文章主要給大家介紹了關(guān)于go語(yǔ)言中time包的各種函數(shù)總結(jié)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • 淺談golang的json.Unmarshal的坑

    淺談golang的json.Unmarshal的坑

    本文主要介紹了淺談golang的json.Unmarshal的坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Go實(shí)現(xiàn)整合Logrus實(shí)現(xiàn)日志打印

    Go實(shí)現(xiàn)整合Logrus實(shí)現(xiàn)日志打印

    這篇文章主要介紹了Go實(shí)現(xiàn)整合Logrus實(shí)現(xiàn)日志打印,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-07-07
  • 詳解Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理

    詳解Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理

    這篇文章主要為大家詳細(xì)介紹了Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下
    2023-11-11

最新評(píng)論