• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    详解如何热重启golang服务器

    服务端代码经常需要升级,对于线上系统的升级常用的做法是,通过前端的负载均衡(如nginx)来保证升级时至少有一个服务可用,依次(灰度)升级。

    而另一种更方便的方法是在应用上做热重启,直接升级应用而不停服务。

    原理

    热重启的原理非常简单,但是涉及到一些系统调用以及父子进程之间文件句柄的传递等等细节比较多。
    处理过程分为以下几个步骤:

    细节

    代码

    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

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    您可能感兴趣的文章:
    • golang DNS服务器的简单实现操作
    • golang-gin-mgo高并发服务器搭建教程
    • golang HTTP 服务器 处理 日志/Stream流的操作
    • golang项目如何上线部署到Linu服务器(方法详解)
    • golang文件服务器的两种方式(可以访问任何目录)
    • golang搭建静态web服务器的实现方法
    • 浅谈Golang中创建一个简单的服务器的方法
    • 基于 HLS 创建 Golang 视频流服务器的优缺点
    上一篇:1行Go代码实现反向代理的示例
    下一篇:Golang学习之平滑重启
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    详解如何热重启golang服务器 详解,如何,热,重启,golang,