0%

Golang HTTP服务热重启

在高并发Http服务中, 更新应用时会出现短暂的connect resuse和部分http请求数据丢失问题。这样在有些服务中是不可容忍的,所有需要Http服务做平滑重启处理。

1. 开源解决方案

名称 地址 说明
grace https://github.com/facebookgo/grace 旧API不会断掉会执行原来的逻辑,pid会变化
endless https://github.com/fvbock/endless 旧API不会断掉会执行原来的逻辑,pid会变化
overseer https://github.com/jpillora/overseer 旧API不会断掉,会执行原来的逻辑,主进程pid不会变化

2. 方案测试

1. grace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
"net/http"
"os"
"time"

"github.com/facebookgo/grace/gracehttp"
)

var startTime time.Time

type HttpHandle int

func (h HttpHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Second * 10)
w.Write([]byte(fmt.Sprintf("pid:%v, startTime:%v\n", os.Getpid(), startTime)))
}

func main() {
startTime = time.Now()
gracehttp.Serve(
&http.Server{Addr: ":7070", Handler: new(HttpHandle)},
)
}

测试结果:

2. endless

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"fmt"
"net/http"
"os"
"time"

"github.com/fvbock/endless"
)

var startTime time.Time

type HttpHandle int

func (h HttpHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Second * 10)
w.Write([]byte(fmt.Sprintf("pid:%v, startTime:%v\n", os.Getpid(), startTime)))
}

func main() {
startTime = time.Now()
endless.ListenAndServe(":7070", new(HttpHandle))
}

测试结果:

3. overseer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"fmt"
"net/http"
"os"
"time"

"github.com/jpillora/overseer"
)

var startTime time.Time

type HttpHandle int

func (h HttpHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Second * 10)
w.Write([]byte(fmt.Sprintf("pid:%v, startTime:%v\n", os.Getpid(), startTime)))
}

func realMain(state overseer.State){
startTime = time.Now()
http.Serve(state.Listener, new(HttpHandle))
}

func main() {
overseer.Run(overseer.Config{
Program: realMain,
Address: ":7070",
})
}

测试结果:

3. 选择

从上面测试可以看出三个软件都能满足Http服务平滑启动的功能;
grace endless功能实现方式:两个都是以开启子进程来加载新可执行程序, 父进程处理完成当前请求后退出;
overseer功能实现方式:启动后会有两个进程[管理进程/功能进程],重启过程中, 管理进程后启动新子进程来执行新可执行程序, 旧子进程处理完成当前请求后退出;

overseer能够兼容进程管理软件(systemd, upstart, supervisor, etc),而grace endless不支持