http server优雅启停原理及验证

  1. 问题背景    

                  在 http应用程序重启时,如果直接 kill -9 使程序退出,然后再启动,会存在的问题:
    1.  旧的请求未处理完,如果服务端进程直接退出,会造成客户端连接中断(收到 RST
    2.  新请求打过来,服务还没重启完毕,造成 connection refused
  2. 优雅重启整体思路

                    1.捕获到优雅重启的信号比如SIGUSR2
                    2. 启动新的子进程,新子进程接管监听端口
                    3. 新子进程处理新请求,旧进程处理完旧请求退出
  3. 优雅重启代码思路

                  

                1.新的bin文件覆盖旧的bin文件

                2.在程序中,通过拦截 signal,并针对 signal 做出相应处理,若是获取到SIGUSR2信号会触发优雅重启

                3. 进程收到SIGUSR2信号后,将服务监听的socket文件描述符传递给子进程(因为端口不可以重复监听,所以采用把监听端口的文件描述符传递给子进程,子进程里从文件描述符实现对端口的监听)

                4. 子进程监听父进程的socket,这个时候父进程和子进程都可以接收请求

                5. 子进程启动成功之后,父进程停止接收新的连接,等待旧连接处理完成

  4. http优雅关闭原理

           http请求的过程会建立TCP连接,http server的关闭本质上是TCP连接的关闭,TCP连接的关闭过程有两种:
           1. 一种是强制关闭:强制关闭时不能再接收数据,如果当前接收缓存中仍有未取出数据或者以后再有数据到达,则TCP会向发送端发送RST包,将连接重置,如图1所示
           2. 另一种是优雅关闭 :优雅关闭时如果缓存中有数据未发出则将其发出去,并且收到所有数据的ACK之后,发送FIN包,开始关闭过程,如图2所示
           RST知识补充: RST标示复位、用来异常的关闭连接
                                  a: 发送RST包关闭连接时,不必等缓冲区的包都发出去,直接就丢弃缓冲区中的包,发送RST
                                  b:接收端收到RST包后,也不必发送ACK包来确认

       golang代码中主要利用sync包的waitGroup实现协程的同步,每一个等待的协程进行waitgroup.add(1),每完成一个协程进行waitgroup.Done(),利用waitgroup.wait()进行堵塞,直到所有的协程都完成为止

     5.验证方法

               1. 强制关闭时: 利用tcpdump进行抓包(tcpdump -i eth0 host $host and tcp port $port),结果如下图,前3行是tcp连接的三次握手过程,第4行向服务端发送177的字节,第5行服务端直接发送RST给客户端,与预期结果一致

          2. 优雅关闭时:利用tcpdump进行抓包结果如下,关闭之前的请求发送ACK之后,发送FIN进行关闭

扫描二维码关注公众号,回复: 5105667 查看本文章

       3. 普通重启时:重启期间有短暂的http server 中断,利用curl  host:port/keepalive 验证http服务,以及tcpdump抓包验证,如下图, 

  4. 优雅重启: kill -SIGUSR2 $pid 进行优雅重启, 新进程接管老进程的监听端口,http服务没有出现异常, 以及tcpdump抓包数据中tcp连接没有异常 

其它:

常用信号量

猜你喜欢

转载自www.cnblogs.com/dapingguo/p/10331360.html