Web 服务,直接重启会导致重启时间段的请求丢失,一个比较简便的优化方式是使用:greuse

SO_REUSEADDR and SO_REUSEPORT

可以同时启动多个程序来监听相同端口,当不同来路的请求到达后,内核会把请求“均衡负载”到多个实例上。

不中断的更新服务的流程:两个运行中的实例,先停止一个,替换程序包,启动新的实例,再重启旧的实例,完成更新。

关于 Socket 端口复用的介绍文章很多,摘录一些知识点:

(remote_ip, remote_port, local_ip, local_port)

基础示例

package main

import (
    "fmt"
    "net/http"
)

func main() {

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello World!\n")
    })

    http.ListenAndServe(":8080", nil)
}

使用 Greuse 改造

package main

import (
    "fmt"
    "net/http"
    "os"

    "github.com/gogf/greuse"
)

func main() {
    listener, err := greuse.Listen("tcp", ":8881")
    if err != nil {
        panic(err)
    }
    defer listener.Close()

    server := &http.Server{}
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "gid: %d, pid: %d\n", os.Getgid(), os.Getpid())
    })

    panic(server.Serve(listener))
}

Iris 框架基础示例

package main

import "github.com/kataras/iris/v12"

func main() {
    app := iris.New()

    root := app.Party("/")
    {
        root.Use(iris.Compression)
        root.Get("/", func(ctx iris.Context) {
          ctx.Writef("Hello World!\n")
        })
    }

    app.Listen(":8080")
}

Iris 框架使用 Greuse 改造

package main

import (
  "fmt"
  "github.com/gogf/greuse"
  "github.com/kataras/iris/v12"
)

func main() {
  app := iris.New()

  root := app.Party("/")
  {
    root.Use(iris.Compression)
    root.Get("/", func(ctx iris.Context) {
      fmt.Fprintf(ctx, "gid: %d, pid: %d\n", os.Getgid(), os.Getpid())
    })
  }

  listener, err := greuse.Listen("tcp", ":8080")
  if err != nil {
    panic(err)
  }

  if err := app.Run(iris.Listener(listener)); err != nil {
    fmt.Println("Failed to start web server")
  }
}

参考: