Gin实践 连载七 Golang优雅重启HTTP服务
优雅的重启服务在前面编写案例代码时,我相信你会想到 每次更新完代码,更新完配置文件后 在这一节中我们简单讲述 项目地址:https://github.com/EDDYCJY/go... ctrl + c
内核在某些情况下发送信号,比如在进程往一个已经关闭的管道写数据时会产生
在终端执行特定的组合键可以使系统发送特定的信号给此进程,完成一系列的动作
因此在我们执行 常见的 信号本段中反复出现信号是什么呢? 信号是 它是一种异步的通知机制,用来提醒进程一个事件(硬件异常、程序执行异常、外部发出信号)已经发生。当一个信号发送给一个进程,操作系统中断了进程正常的控制流程。此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数 所有信号$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX 怎样算优雅目的
流程1、替换可执行文件或修改配置文件 2、发送信号量 3、拒绝新连接请求旧进程,但要保证已有连接正常 4、启动新的子进程 5、新的子进程开始 6、系统将新的请求转交新的子进程 7、旧进程处理完所有旧连接后正常结束 实现优雅重启endlessZero downtime restarts for golang HTTP and HTTPS servers. (for golang 1.3+) 我们借助 fvbock/endless 来实现
安装go get -u github.com/fvbock/endless 编写打开 gin-blog 的 package main import ( "fmt" "log" "syscall" "github.com/fvbock/endless" "gin-blog/routers" "gin-blog/pkg/setting" ) func main() { endless.DefaultReadTimeOut = setting.ReadTimeout endless.DefaultWriteTimeOut = setting.WriteTimeout endless.DefaultMaxHeaderBytes = 1 << 20 endPoint := fmt.Sprintf(":%d",setting.HTTPPort) server := endless.NewServer(endPoint,routers.InitRouter()) server.BeforeBegin = func(add string) { log.Printf("Actual pid is %d",syscall.Getpid()) } err := server.ListenAndServe() if err != nil { log.Printf("Server err: %v",err) } }
验证编译$ go build main.go 执行$ ./main [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. ... Actual pid is 48601 启动成功后,输出了 [root@localhost go-gin-example]# ./main [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] GET /auth --> ... [GIN-debug] GET /api/v1/tags --> ... ... Actual pid is 48601 ... Actual pid is 48755 48601 Received SIGTERM. 48601 [::]:8000 Listener closed. 48601 Waiting for connections to finish... 48601 Serve() returning... Server err: accept tcp [::]:8000: use of closed network connection 可以看到该命令已经挂起,并且 48601 Received SIGTERM. 48601 [::]:8000 Listener closed. 48601 Waiting for connections to finish... 48601 Serve() returning... Server err: accept tcp [::]:8000: use of closed network connection 大致意思为主进程( 唤醒这时候在 Actual pid is 48755 48601 Received SIGTERM. 48601 [::]:8000 Listener closed. 48601 Waiting for connections to finish... 48601 Serve() returning... Server err: accept tcp [::]:8000: use of closed network connection $ [GIN] 2018/03/15 - 13:00:16 | 200 | 188.096μs | 192.168.111.1 | GET /api/v1/tags... 这就完成了一次正向的流转了 你想想,每次更新发布、或者修改配置文件等,只需要给该进程发送SIGTERM信号,而不需要强制结束应用,是多么便捷又安全的事! 问题
http.Server - Shutdown()如果你的 package main import ( "fmt" "net/http" "context" "log" "os" "os/signal" "time" "gin-blog/routers" "gin-blog/pkg/setting" ) func main() { router := routers.InitRouter() s := &http.Server{ Addr: fmt.Sprintf(":%d",setting.HTTPPort),Handler: router,ReadTimeout: setting.ReadTimeout,WriteTimeout: setting.WriteTimeout,MaxHeaderBytes: 1 << 20,} go func() { if err := s.ListenAndServe(); err != nil { log.Printf("Listen: %sn",err) } }() quit := make(chan os.Signal) signal.Notify(quit,os.Interrupt) <- quit log.Println("Shutdown Server ...") ctx,cancel := context.WithTimeout(context.Background(),5 * time.Second) defer cancel() if err := s.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:",err) } log.Println("Server exiting") } 小结在日常的服务中,优雅的重启(热更新)是非常重要的一环。而 参考本系列示例代码
本系列目录
拓展阅读
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |