Golang的優雅重啟

2022-07-04 01:57:13 字數 4263 閱讀 9935

更新(2023年4月):florian von bock

已將本文中描述的內容轉換為乙個名為

endless

的優秀go包 。

如果您有golang http服務,可能需要重新啟動它以公升級二進位制檔案或更改某些配置。

如果你(像我一樣)因為網路伺服器處理它而優雅地重新啟動是理所當然的,你可能會發現這個配方非常方便,因為使用golang你需要自己動手。

實際上這裡有兩個問題需要解決。

首先是正常重啟的unix方面,即程序可以在不關閉偵聽套接字的情況下自行重啟的機制。

第二個問題是確保所有正在進行的請求正確完成或超時。

使用golang lib分支程序的方法不止一種,但對於這種特殊情況, 

exec.command是可行

的方法。

這是因為

此函式返回

的cmd結構

具有此extrafiles成員,

該成員指定要由新程序繼承的開啟檔案(除了stdin / err / out)。

這是這樣的:

2 3

4 5

6 7

8 9

10 11

12 13

14

file := netlistener.file() // this returns a dup()

path := "/path/to/executable"

args := string

cmd := exec.command(path, args...)

cmd.stdout = os.stdout

cmd.stderr = os.stderr

cmd.extrafiles = *os.file

err := cmd.start()

if err != nil

在上面的**中netlistener是乙個指向

net.listener

的指標, 

用於監聽http請求。

path如果要公升級

,變數應該包含新可執行檔案的路徑(可能與當前執行的路徑相同)。

上面**中的乙個重點是netlistener.file()返回

檔案描述符

的 dup(2)

。重複的檔案描述符不會

設定fd_cloexec標誌

,這會導致檔案在子節點中關閉(不是我們想要的)。

您可能會遇到通過命令列引數將繼承的檔案描述符編號傳遞給子項的示例,但extrafiles實現

的方式 

使其不必要。

文件指出「如果非零,則條目i變為檔案描述符3 + i。」這意味著在上面的**片段中,子代中的繼承檔案描述符將始終為3,因此不需要明確地傳遞它。

最後,args陣列包含乙個-graceful選項:你的程式需要某種方式通知孩子這是乙個正常重啟的一部分,孩子應該重新使用套接字而不是嘗試開啟乙個新套接字。

另一種方法可能是通過環境變數。

這是程式啟動序列的一部分

此時我們已準備好接受請求,但就在我們這樣做之前,我們需要告訴我們的父母停止接受請求並退出,這可能是這樣的:

2 3

4 5 6 7

if gracefulchild 

server.serve(l)

為此,我們需要使用

sync.waitgroup

跟蹤開啟的連線 

。我們需要在每個接受的連線上遞增等待組,並在每個連線關閉時遞減它。

乍一看,golang標準的http包不提供任何鉤子來對accept()或close()採取行動,但這就是介面魔法拯救的地方。

(非常感謝

jeff r. allen

對這篇文章的評價

)。下面是乙個偵聽器示例,它在每個accept()上遞增乙個等待組。

首先,我們「子類」 

net.listener(你會明白我們為什麼需要stopstopped以下):

2 3 4 5

type gracefullistener struct 

接下來,我們「覆蓋」accept方法。

gracefulconn暫時

沒關係,稍後會介紹)。

我們還需要乙個「建構函式」:

2 3

4 5

6 7 8 9

func newgracefullistener(l net.listener) (gl *gracefullistener) 

go func() ()

return

}

上面的函式啟動goroutine的原因是因為它不能在我們accept()上面

完成,因為它會阻塞 

gl.listener.accept()

goroutine將通過關閉檔案描述符來解鎖它。

我們的close()方法只是傳送乙個nil停止通道,以便上面的goroutine完成其餘的工作。

2 3

4 5 6 7

func (gl *gracefullistener) close() error 

gl.stop <- nil

return <-gl.stop

}

最後,這個小方便方法從中提取檔案描述符net.tcplistener

2 3 4 5

func (gl *gracefullistener) file() *os.file 

當然,我們還需要乙個

net.conn減少等待組

的變體 

close()

2 3

4 5

6 7

8

type gracefulconn struct 

func (w gracefulconn) close() error

要開始使用上面優雅的listener版本,我們只需要將server.serve(l)

更改為:

2

netlistener = newgracefullistener(l)

server.serve(netlistener)

還有一件事。

您應該避免結束通話客戶端無意關閉的連線(或不是本週)。

最好按如下方式建立伺服器:

php fpm的優雅重啟關閉

參考 php 5.3.3 下的php fpm 不再支援 php fpm 以前具有的 usr local php sbin php fpm start stop reload 等命令,需要使用訊號控制 master程序可以理解以下訊號 int,term 立刻終止 quit 平滑終止 usr1 重新開啟...

exec go 重啟 golang平滑重啟

背景 更新配置檔案 更新server程式等,需要重啟伺服器,需要做到重啟伺服器時,伺服器不停止執行,請求不丟失 原理 熱重啟原理涉及到一些系統呼叫及父子程序之間檔案控制代碼的傳遞等較多細節,處理過程大致如下 監聽訊號 收到 kill 1 訊號時,fork子程序 使用相同的啟動命令 將檔案描述符 環境...

如何優雅的入門golang

golang標準庫文件 高效能分布式系統開發 海量並行處理 遊戲服務端開發再好不過了 package main import fmt func main 複製 go run main.go hello world 複製 識別符號用來命名變數 型別等程式體。乙個或者多個字母 a za z 數字 0 9...