优雅重启Go服务——gracehttp详解

前言

grace是facebook公司为golang服务开发的优雅重启和零停机部署的开源库。可以实现服务重启时,旧有连接不断,新服务启动后,新连接连入新服务,如此客户端无感知。

使用方法

(1)获取

go get github.com/facebookgo/grace/gracehttp

mod可以使用如下方式引入:

require github.com/facebookgo/grace latest

(2)使用

gracehttp.Serve(
        &http.Server{
   
   Addr: *address0, Handler: newHandler("Zero  ")},
        &http.Server{
   
   Addr: *address1, Handler: newHandler("First ")},
        &http.Server{
   
   Addr: *address2, Handler: newHandler("Second")},
    )

(3)重启命令

sudo kill -USR2 pidof yourservername
pidof yourservername 是指需要重启的服务进程id

源码解析

启动服务

// Serve will serve the given http.Servers and will monitor for signals
// allowing for graceful termination (SIGTERM) or restart (SIGUSR2).
func Serve(servers ...*http.Server) error {
   
   
    a := newApp(servers)
    return a.run()
}

func newApp(servers []*http.Server) *app {
   
   
    return &app{
   
   
        servers:   servers,
        http:      &httpdown.HTTP{
   
   },
        net:       &gracenet.Net{
   
   },
        listeners: make([]net.Listener, 0, len(servers)),
        sds:       make([]httpdown.Server, 0, len(servers)),

        preStartProcess: func() error {
   
    return nil },
        // 2x num servers for possible Close or Stop errors + 1 for possible
        // StartProcess error.
        errors: make(chan error, 1+(len(servers)*2)),
    }
}

构造app,具体的处理逻辑均在app中进行。

注意:

此处注释说明了Serve会启动指定的http.Servers,并且会监听系统信号以允许优雅结束(SIGTERM)或重启服务(SIGUSR2),实际代码中还支持SIGINT结束服务进程,我们可以根据需求指定信号来决定是结束还是重启服务。

func (a *app) run() error {
   
   
    // Acquire Listeners
    //获取所有http.Server服务地址的Listeners
    if err := a.listen(); err != nil {
   
   
        return err
    }

    // Some useful logging.
    // logger的处理
    if logger != nil {
   
   
        if didInherit {
   
   
            if ppid == 1 {
   
   
                logger.Printf("Listening on init activated %s", pprintAddr(a.listeners))
            } else {
   
   
                const msg = "Graceful handoff of %s with new pid %d and old pid %d"
                logger.Printf(msg, pprintAddr(a.listeners), os.Getpid(), ppid)
            }
        } else {
   
   
            const msg = "Serving %s with pid %d"
            logger.Printf(msg, pprintAddr(a.listeners), os.Getpid())
        }
    }

    // Start serving.
    // 启动各http服务
    a.serve()

    // Close the parent if we inherited and it wasn't init that started us.
    // 如果已经继承,并且不是从init启动,就说明是重启进程,需要将原进程关闭。
    if didInherit && ppid != 1 {
   
   
        if err := syscall.Kill(ppid, syscall.SIGTERM); err != nil {
   
   
            return fmt.Errorf("failed to close parent: %s", err)
        }
    }

    // 此处为最核心处理部分
    waitdone := make(chan struct{
   
   })
    go func() {
   
   
        defer close(waitdone)
        a.wait()
    }()

    select {
   
   
    case err := <-a.errors:/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值