溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Go如何實(shí)現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟功能

發(fā)布時(shí)間:2022-10-10 14:25:03 來源:億速云 閱讀:149 作者:iii 欄目:開發(fā)技術(shù)

這篇“Go如何實(shí)現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟功能”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Go如何實(shí)現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟功能”文章吧。

什么是優(yōu)雅關(guān)機(jī)?

優(yōu)雅關(guān)機(jī)就是服務(wù)端關(guān)機(jī)命令發(fā)出后不是立即關(guān)機(jī),而是等待當(dāng)前還在處理的請(qǐng)求全部處理完畢后再退出程序,是一種對(duì)客戶端友好的關(guān)機(jī)方式。而執(zhí)行Ctrl+C關(guān)閉服務(wù)端時(shí),會(huì)強(qiáng)制結(jié)束進(jìn)程導(dǎo)致正在訪問的請(qǐng)求出現(xiàn)問題。

實(shí)現(xiàn)原理

Go 1.8版本之后, http.Server 內(nèi)置的 Shutdown() 方法就支持優(yōu)雅地關(guān)機(jī),說明一下Shutdown工作的機(jī)制:當(dāng)程序檢測(cè)到中斷信號(hào)時(shí),我們調(diào)用http.server種的shutdown方法,該方法將阻止新的請(qǐng)求進(jìn)來,同時(shí)保持當(dāng)前的連接,知道當(dāng)前連接完成則終止程序!

實(shí)現(xiàn)優(yōu)雅重啟

package main

import (
	"context"
	"fmt"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	//啟動(dòng)服務(wù)(優(yōu)雅關(guān)機(jī))
	srv := &http.Server{
		Addr:    fmt.Sprintf(":%d", viper.GetInt("app.port")),
		Handler: r,
	}
	go func() {
		// 開啟一個(gè)goroutine啟動(dòng)服務(wù)
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()
	// 等待中斷信號(hào)來優(yōu)雅地關(guān)閉服務(wù)器,為關(guān)閉服務(wù)器操作設(shè)置一個(gè)5秒的超時(shí)
	quit := make(chan os.Signal, 1) // 創(chuàng)建一個(gè)接收信號(hào)的通道
	// kill 默認(rèn)會(huì)發(fā)送 syscall.SIGTERM 信號(hào)
	// kill -2 發(fā)送 syscall.SIGINT 信號(hào),我們常用的Ctrl+C就是觸發(fā)系統(tǒng)SIGINT信號(hào)
	// kill -9 發(fā)送 syscall.SIGKILL 信號(hào),但是不能被捕獲,所以不需要添加它
	// signal.Notify把收到的 syscall.SIGINT或syscall.SIGTERM 信號(hào)轉(zhuǎn)發(fā)給quit
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 此處不會(huì)阻塞
	<-quit                                               // 阻塞在此,當(dāng)接收到上述兩種信號(hào)時(shí)才會(huì)往下執(zhí)行
	zap.L().Info("Shutdown Server ...")
	// 創(chuàng)建一個(gè)5秒超時(shí)的context
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	// 5秒內(nèi)優(yōu)雅關(guān)閉服務(wù)(將未處理完的請(qǐng)求處理完再關(guān)閉服務(wù)),超過5秒就超時(shí)退出
	if err := srv.Shutdown(ctx); err != nil {
		zap.L().Fatal("Server Shutdown: ", zap.Error(err))
	}
	zap.L().Info("Server exiting")
}

實(shí)現(xiàn)平滑重啟

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 !")
	})
	// 默認(rèn)endless服務(wù)器會(huì)監(jiān)聽下列信號(hào):
	// syscall.SIGHUP,syscall.SIGUSR1,syscall.SIGUSR2,syscall.SIGINT,syscall.SIGTERM和syscall.SIGTSTP
	// 接收到 SIGHUP 信號(hào)將觸發(fā)`fork/restart` 實(shí)現(xiàn)優(yōu)雅重啟(kill -1 pid會(huì)發(fā)送SIGHUP信號(hào))
	// 接收到 syscall.SIGINT或syscall.SIGTERM 信號(hào)將觸發(fā)優(yōu)雅關(guān)機(jī)
	// 接收到 SIGUSR2 信號(hào)將觸發(fā)HammerTime
	// SIGUSR1 和 SIGTSTP 被用來觸發(fā)一些用戶自定義的hook函數(shù)
	if err := endless.ListenAndServe(":8080", router); err!=nil{
		log.Fatalf("listen: %s\n", err)
	}

	log.Println("Server exiting...")

測(cè)試

我們通過執(zhí)行kill -1 pid命令發(fā)送syscall.SIGINT來通知程序優(yōu)雅重啟,具體做法如下:

  • 打開終端,go build -o graceful_restart編譯并執(zhí)行./graceful_restart,終端輸出當(dāng)前pid(假設(shè)為43682)

  • 將代碼中處理請(qǐng)求函數(shù)返回的hello gin!修改為hello q1mi!,再次編譯go build -o graceful_restart

  • 打開一個(gè)瀏覽器,訪問127.0.0.1:8080/,此時(shí)瀏覽器白屏等待服務(wù)端返回響應(yīng)。

  • 在終端迅速執(zhí)行kill -1 43682命令給程序發(fā)送syscall.SIGHUP信號(hào)

  • 等第3步瀏覽器收到響應(yīng)信息hello gin!后再次訪問127.0.0.1:8080/會(huì)收到hello q1mi!的響應(yīng)。

  • 在不影響當(dāng)前未處理完請(qǐng)求的同時(shí)完成了程序代碼的替換,實(shí)現(xiàn)了優(yōu)雅重啟。

但是需要注意的是,此時(shí)程序的PID變化了,因?yàn)閑ndless 是通過fork子進(jìn)程處理新請(qǐng)求,待原進(jìn)程處理完當(dāng)前請(qǐng)求后再退出的方式實(shí)現(xiàn)優(yōu)雅重啟的。所以當(dāng)你的項(xiàng)目是使用類似supervisor的軟件管理進(jìn)程時(shí)就不適用這種方式了。

以上就是關(guān)于“Go如何實(shí)現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟功能”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

go
AI