Fork me on GitHub

版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | http://vearne.cc

引言

使用Golang进行开发服务,我们会特别关心性能,fasthttp是标准库net/http性能的10倍。所以我们的web服务大量使用它。不过这个库并没有提供优雅退出方案, 查看了很多资料,我找到一个解决方案。

1.原理

对于web服务而言,优雅退出其实分为2步

  • 1)关闭监听的端口,不再接受新的请求
  • 2)对于正在处理的请求等待它们处理完成,如果全部处理完成,或者默认的超时时间已达,则退出

2. 实现

要达到这个目标需要实现

type Listener interface

下面展示一部分核心代码
grace_listener.go

type GracefulListener struct {
    // inner listener
    ln net.Listener

    // maximum wait time for graceful shutdown
    maxWaitTime time.Duration

    // this channel is closed during graceful shutdown on zero open connections.
    done chan struct{}

    // the number of open connections
    connsCount uint64

    // becomes non-zero when graceful shutdown starts
    shutdown uint64
}
// Close closes the inner listener and waits until all the pending open connections
// are closed before returning.
func (ln *GracefulListener) Close() error {
    // 不再接受新的请求
    err := ln.ln.Close()

    if err != nil {
        return nil
    }
    // 等待已经接到的请求处理完成
    return ln.waitForZeroConns()
}

func (ln *GracefulListener) waitForZeroConns() error {
    atomic.AddUint64(&ln.shutdown, 1)

    fmt.Println("waitForZeroConns", atomic.LoadUint64(&ln.connsCount))

    if atomic.LoadUint64(&ln.connsCount) == 0 {
        close(ln.done)
        return nil
    }

    select {
    case <-ln.done:
        return nil
    case <-time.After(ln.maxWaitTime):
        return fmt.Errorf("cannot complete graceful shutdown in %s", ln.maxWaitTime)
    }

    return nil
}

server.go
初始化&启动web服务

    addr := fmt.Sprintf("%v:%v", context.GlobalConfig.Bind.Host,
        context.GlobalConfig.Bind.Port)

    ln, err := net.Listen("tcp4", addr)
    if err != nil {
        log.WithField("error", err).Error("start server fail")
        os.Exit(-5)
    }

    // 最大等待3秒
    Listener = NewGracefulListener(ln, time.Second * 3)
    err = fasthttp.Serve(Listener, router.Handler)
    if err != nil {
        log.WithField("error", err).Error("start server fail")
        os.Exit(-5)
    }

    log.Info("server stop listen")

完整项目地址:
https://github.com/vearne/hello_server


如果我的文章对你有帮助,你可以给我打赏以促使我拿出更多的时间和精力来分享我的经验和思考总结。

微信支付码

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据