fasthttp 的性能是超棒,打的招牌是 “Up to 10x faster than net/http”,曾一度停止更新,导致大家围观吃瓜,后来权限开放,好多高手加入维护,大家又开始关注,这里主要关注其优雅关闭/重启实现。
当选择一个新东西时,首先要了解一下有没有现成的库来实现自己想要的功能,其次是了解插件、中间件是否丰富,如果没有,自己能不能花时间和精力去实现……
相对标准库的 graceful shutdown / restart ,fasthttp 实现代码更简单,函数 func (*fasterhttp.Server) Shutdown
已经做得很好。
优雅关闭可以正常关闭服务器,而不会中断任何活动的连接。 关机的工作方式是先关闭所有打开的侦听器,然后无限期地等待所有连接返回空闲状态,然后关闭。
调用 Shutdown
时,Serve
的 ListenAndServe
和 ListenAndServeTLS
立即返回 nil
。 确保程序没有退出,而是等待关机返回。
即:等待活动的连接结束,不接受新的连接进来。使活动的请求不被中断,给程序处理资源关闭足够的时间。
优雅关闭例子
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package main
import (
"log"
"net"
"os"
"os/signal"
"syscall"
"time"
"github.com/valyala/fasthttp"
)
var address = ":38080"
func connStateCallback(conn net.Conn, state fasthttp.ConnState) {
log.Printf("conn: %+v\n", conn)
log.Printf("state: %+v\n", state)
}
func main() {
handler := processRequest
server := &fasthttp.Server{
Handler: handler,
Name: "Demo Service",
DisableKeepalive: true,
DisableHeaderNamesNormalizing: true,
ConnState: connStateCallback,
ReadTimeout: 5 * time.Second, // important
}
go func() {
log.Printf("%s listening on address %s\n", server.Name, address)
if err := server.ListenAndServe(address); err != nil {
log.Fatalf("Error in ListenAndServe: %s\n", err)
}
}()
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
//register for interupt (Ctrl+C) and SIGTERM (docker)
<-signalChan
log.Printf("os.Interrupt - shutting down...\n")
if err := srv.Shutdown(); err != nil {
log.Println("Shutdown err", err)
defer os.Exit(1)
} else {
// yourApp.Close() // <---- 这里可以做其它资源释放的工作,如关闭数据等
log.Println("gracefully stopped")
}
defer os.Exit(0)
return
}
func processRequest(ctx *fasthttp.RequestCtx) {
ctx.Conn()
time.Sleep(time.Second * 10)
ctx.Success("text/plain", []byte("123"))
log.Printf("connection '%+v' finshed\n", ctx.Conn())
return
}
应该注意:关机不会关闭 Keepalive
连接,因此建议将 ReadTimeout
设置为非0的值。比如上例设为 5秒。如果不设,则出发后会一直等待,直到其它控制软件,如 Supervisor ,强制关闭进程,或者等到有新请求时抛出错误。