Golang 服务优雅重启

lingchao · · 4416 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

很多时候对于服务升级的做法简单粗暴, 就简单的杀进程启动新的进程.

还有的好一点就是多个相同的服务依次升级, 保证有服务可用. 但是公平的说这两种都会丢失请求中的连接.

鉴于这种情况, 在现实中我们可以使用优雅重启来搞定这个问题. Golang 实现优雅重启的原理也很简单:

  • 监听 USR2 信号;

  • 收到信号后将服务监听的文件描述符传递给新的子进程;

  • 此时新老进程同时接收请求;

  • 父进程停止接收新请求, 等待旧请求完成(或超时);

  • 父进程退出.

对于上面的原理看似简单, 其实是分成了两个大的要点:

  • 新老进程同时监听同一端口, 这个很简单, Go 很早旧支持;

  • 如何等待旧的请求完成, 这个在 Go 1.8 (新增了Server.Shutdown) 之前是需要费一番功夫的.

我们搞定了上面的原理之后, 加上 Go 1.8 的完美等待旧请求的实现,

我实现了一个简单的优雅重启库: https://github.com/douglarek/zerodown.

zerodown 完美兼容基于 Go 标准库 Server 监听服务.

对于标准库的使用, 我们可以象下面一样使用:

package main

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

    "github.com/douglarek/zerodown"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        time.Sleep(5 * time.Second)
        fmt.Fprintln(w, "Hello, World!")
    })
    log.Fatalln(zerodown.ListenAndServe(":8080", nil))

对于第三方库 Gin 我们可以:

package main

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

    "github.com/douglarek/zerodown"

    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.GET("/", func(c *gin.Context) {
        time.Sleep(5 * time.Second)
        c.String(http.StatusOK, "Hello, World!")
    })
    log.Fatalln(zerodown.ListenAndServe(":8080", router))
}

有疑问加站长微信联系(非本文作者)

本文来自:lingchao.xin

感谢作者:lingchao

查看原文:Golang 服务优雅重启

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

4416 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传