kill -9
RSTconnection refusedkill -9
很间接的感触就是:在重启过程中,会有一段时间不能给用户提供失常服务;同时粗鲁敞开服务,也可能会对业务依赖的数据库等状态服务造成净化。
所以咱们服务重启或者是从新公布过程中,要做到新旧服务无缝切换,同时能够保障变更服务 零宕机工夫!
go-zero
优雅退出
在实现优雅重启之前首先须要解决的一个问题是 如何优雅退出:
fdlisten
httpserver.ShutDown()
inShutdownlisteners
别离来解释一下这几个步骤的含意:
inShutdown
func (srv *Server) ListenAndServe() error {
if srv.shuttingDown() {
return ErrServerClosed
}
....
// 理论监听端口;生成一个 listener
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
// 进行理论逻辑解决,并将该 listener 注入
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
func (s *Server) shuttingDown() bool {
return atomic.LoadInt32(&s.inShutdown) != 0
}
ListenAndServeServer
inShutdown
listeners
func (srv *Server) Serve(l net.Listener) error {
...
// 将注入的 listener 退出外部的 map 中
// 不便后续管制从该 listener 链接到的申请
if !srv.trackListener(&l, true) {
return ErrServerClosed
}
defer srv.trackListener(&l, false)
...
}
Servelisteners maplistenerShutDownlistenerslistener.Close()
closeIdleConns
Server
敞开
func (srv *Server) Serve(l net.Listener) error {
...
for {
rw, err := l.Accept()
// 此时 accept 会产生谬误,因为后面曾经将 listener close了
if err != nil {
select {
// 又是一个标记:doneChan
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
}
}
}
getDoneChanlistenerdoneChan
Shutdown
但服务启动后的某一时刻,程序如何晓得服务被中断了呢?服务被中断时如何告诉程序,而后调用Shutdown作解决呢?接下来看一下零碎信号告诉函数的作用
服务中断
signalsignalNotify
https://github.com/tal-tech/go-zero/blob/master/core/proc/signals.go
func init() {
go func() {
var profiler Stopper
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGTERM)
for {
v := <-signals
switch v {
case syscall.SIGUSR1:
dumpGoroutines()
case syscall.SIGUSR2:
if profiler == nil {
profiler = StartProfile()
} else {
profiler.Stop()
profiler = nil
}
case syscall.SIGTERM:
// 正在执行优雅敞开的中央
gracefulStop(signals)
default:
logx.Error("Got unregistered signal:", v)
}
}
}()
}
SIGUSR1goroutineSIGUSR2SIGTERMgracefulStop
gracefulStop
wrap uptime.Sleep()shutdown
这样,服务不再承受新的申请,服务沉闷的申请期待解决实现,同时也期待资源敞开(数据库连贯等),如有超时,强制退出。
整体流程
dockerk8sSIGTERMShutDown
到这里,整个优雅敞开的流程就梳理结束了。
k8s
old podnew podold podnew podold pod
new podold pod
我的项目地址
https://github.com/tal-tech/go-zero
欢送应用 go-zero 并 star 反对咱们!
微信交换群
关注『微服务实际』公众号并点击 交换群 获取社区群二维码。