ijd8.COM

A simple blog for an old Ma Nong.

超快go fasthttp库的优雅关闭/重启实现

Permalink

fasthttp 的性能是超棒,打的招牌是 “Up to 10x faster than net/http”,曾一度停止更新,导致大家围观吃瓜,后来权限开放,好多高手加入维护,大家又开始关注,这里主要关注其优雅关闭/重启实现。

当选择一个新东西时,首先要了解一下有没有现成的库来实现自己想要的功能,其次是了解插件、中间件是否丰富,如果没有,自己能不能花时间和精力去实现……

相对标准库的 graceful shutdown / restart ,fasthttp 实现代码更简单,函数 func (*fasterhttp.Server) Shutdown 已经做得很好。

优雅关闭可以正常关闭服务器,而不会中断任何活动的连接。 关机的工作方式是先关闭所有打开的侦听器,然后无限期地等待所有连接返回空闲状态,然后关闭。

调用 Shutdown 时,ServeListenAndServeListenAndServeTLS 立即返回 nil。 确保程序没有退出,而是等待关机返回。

即:等待活动的连接结束,不接受新的连接进来。使活动的请求不被中断,给程序处理资源关闭足够的时间。

优雅关闭例子

Go: fasthttp 优雅关闭/重启
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 ,强制关闭进程,或者等到有新请求时抛出错误。

Write a Comment

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.16.7 Processed in 0ms