网站首页 文章专栏 服务器热启动或者热升级
服务端代码经常需要升级,有一种更方便的方法是在应用上做热重启,直接更新源码、配置或升级应用而不停服务。很多人认为 web服务有必要支持热升级吗?我认为非常有必要,不中断服务始终是我们所追求的目标,虽然很多人说可能服务器会坏掉等等,这个是属于高可用的设计范畴,有另外的解决之道,但在正常的服务更新上需要避免这样的升级带来的用户不可用。
热重启的原理比较简单,但是涉及到一些系统调用以及父子进程之间文件句柄的传递等等细节比较多。
处理过程分为以下几个步骤:
(1)监听信号(USR2..)
(2)收到信号时fork子进程(使用相同的启动命令),将服务监听的socket文件描述符传递给子进程
(3)子进程监听父进程的socket,这个时候父进程和子进程都可以接收请求
(4)子进程启动成功之后,父进程停止接收新的连接,等待旧连接处理完成(或超时)
(5)父进程退出,重启完成
以beego框架的grace模块为例说明,原理可以看grace模块的源码。
import(
"log"
"net/http"
"os"
"strconv"
"github.com/astaxie/beego/grace"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("WORLD!"))
w.Write([]byte("ospid:" + strconv.Itoa(os.Getpid())))
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/hello", handler)
err := grace.ListenAndServe("localhost:8080", mux)
if err != nil {
log.Println(err)
}
log.Println("Server on 8080 stopped")
os.Exit(0)
}
测试:
打开两个终端
一个终端输入:ps -ef|grep 应用名
一个终端输入请求:curl "http://127.0.0.1:8080/hello"
热升级
kill -HUP 进程 ID
打开一个终端输入请求:curl "http://127.0.0.1:8080/hello"
最后如果不想用了,kill 进程ID结束进程