優雅關機就是伺服器端關機命令發出後不是立即關機,而是等待當前還在處理的請求全部處理完畢後再退出程式,是一種對使用者端友好的關機方式。而執行Ctrl+C關閉伺服器端時,會強制結束程序導致正在存取的請求出現問題。
Go 1.8版本之後, http.Server 內建的 Shutdown() 方法就支援優雅地關機,說明一下Shutdown工作的機制:當程式檢測到中斷訊號時,我們呼叫http.server種的shutdown方法,該方法將阻止新的請求進來,同時保持當前的連線,知道當前連線完成則終止程式!
package main
import (
"context"
"fmt"
"github.com/spf13/viper"
"go.uber.org/zap"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
//啟動服務(優雅關機)
srv := &http.Server{
Addr: fmt.Sprintf(":%d", viper.GetInt("app.port")),
Handler: r,
}
go func() {
// 開啟一個goroutine啟動服務
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()
// 等待中斷訊號來優雅地關閉伺服器,為關閉伺服器操作設定一個5秒的超時
quit := make(chan os.Signal, 1) // 建立一個接收訊號的通道
// kill 預設會傳送 syscall.SIGTERM 訊號
// kill -2 傳送 syscall.SIGINT 訊號,我們常用的Ctrl+C就是觸發系統SIGINT訊號
// kill -9 傳送 syscall.SIGKILL 訊號,但是不能被捕獲,所以不需要新增它
// signal.Notify把收到的 syscall.SIGINT或syscall.SIGTERM 訊號轉發給quit
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 此處不會阻塞
<-quit // 阻塞在此,當接收到上述兩種訊號時才會往下執行
zap.L().Info("Shutdown Server ...")
// 建立一個5秒超時的context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 5秒內優雅關閉服務(將未處理完的請求處理完再關閉服務),超過5秒就超時退出
if err := srv.Shutdown(ctx); err != nil {
zap.L().Fatal("Server Shutdown: ", zap.Error(err))
}
zap.L().Info("Server exiting")
}
import (
"log"
"net/http"
"time"
"github.com/fvbock/endless"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "hello xiaosheng !")
})
// 預設endless伺服器會監聽下列訊號:
// syscall.SIGHUP,syscall.SIGUSR1,syscall.SIGUSR2,syscall.SIGINT,syscall.SIGTERM和syscall.SIGTSTP
// 接收到 SIGHUP 訊號將觸發`fork/restart` 實現優雅重啟(kill -1 pid會傳送SIGHUP訊號)
// 接收到 syscall.SIGINT或syscall.SIGTERM 訊號將觸發優雅關機
// 接收到 SIGUSR2 訊號將觸發HammerTime
// SIGUSR1 和 SIGTSTP 被用來觸發一些使用者自定義的hook函數
if err := endless.ListenAndServe(":8080", router); err!=nil{
log.Fatalf("listen: %s\n", err)
}
log.Println("Server exiting...")
我們通過執行kill -1 pid命令傳送syscall.SIGINT來通知程式優雅重啟,具體做法如下:
但是需要注意的是,此時程式的PID變化了,因為endless 是通過fork子程序處理新請求,待原程序處理完當前請求後再退出的方式實現優雅重啟的。所以當你的專案是使用類似supervisor的軟體管理程序時就不適用這種方式了。
無論是優雅關機還是優雅重啟歸根結底都是通過監聽特定系統訊號,然後執行一定的邏輯處理保障當前系統正在處理的請求被正常處理後再關閉當前程序。使用優雅關機還是使用優雅重啟以及怎麼實現,這就需要根據專案實際情況來決定了。
以上就是使用go如何優雅關機和平滑重啟 的詳細內容,更多關於go關機重啟 的內容請關注博主的其它相關文章!