使用Go实现优雅重启服务功能

2020-01-28 14:37:39王振洲

fork() 方法也比较简单,主要是使用  exec 包的  Command() 方法来创建一个  Cmd 对象,然后调用其  Start() 方法来启动一个新进。要注意的是,创建新进程前需要设置环境变量  ENDLESS_CONTINUE ,这是告诉新进程需要发送  syscall.SIGTERM 信号给父进程。还有就是通过  Cmd 对象的  ExtraFiles 成员把监听客户端连接的socket句柄传递给新服务处理进程了。

再来看看关闭服务进程的 shutdown() 方法:


func (srv *endlessServer) shutdown() {
  err := srv.EndlessListener.Close()
}

这个方法很简单,就是调用 net.Listener 对象的  Close() 方法来关闭监听客户端请求的socket。关闭监听客户端请求的socket后,主循环会退出处理,然后会退出进程。

接着我们来看看接收客户端请求的 endlessListener.Accept() 方法:


func (el *endlessListener) Accept() (c net.Conn, err error) {
  tc, err := el.Listener.(*net.TCPListener).AcceptTCP()
  if err != nil {
    return
  }
  tc.SetKeepAlive(true)         // see http.tcpKeepAliveListener
  tc.SetKeepAlivePeriod(3 * time.Minute) // see http.tcpKeepAliveListener
  c = endlessConn{
    Conn:  tc,
    server: el.server,
  }
  el.server.wg.Add(1)
  return
}

主要要注意的是,函数最后会调用 el.server.wg.Add(1) 这行代码来增加客户端请求的计数器,这是优雅重启的关键。因为在  endlessServer.Serve() 方法中会等待所有客户端请求处理完毕才会退出,我们来看看  endlessServer.Serve() 方法的实现:


func (srv *endlessServer) Serve() (err error) {
  err = srv.Server.Serve(srv.EndlessListener)
  srv.wg.Wait()
  return
}

可以看到, endlessServer.Serve() 方法最后会调用  srv.wg.Wait() 这行代码来等待所有客户端请求完成。那么客户端连接计数器什么时候会减少呢?在  endlessConn.Close() 方法中可以看到计数器减少的操作:


func (w endlessConn) Close() error {
  err := w.Conn.Close()
  if err == nil {
    w.server.wg.Done()
  }
  return err
}

可以看到, endlessConn.Close() 方法最后会调用  w.server.wg.Done() 这 行代码来减少客户端请求计数器。 至此,优雅重启服务的实现就完成。

当然,本篇文章主要介绍的是优雅重启的原理,完成的源码实现还是要查看 endless 这个库。

总结

以上所述是小编给大家介绍的使用Go实现优雅重启服务功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对易采站长站网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!