golang的facebookgo grace優雅重啟原理分析
從原理上來說是這樣一個過程:
1)釋出新的bin檔案去覆蓋老的bin檔案 2)傳送一個訊號量,告訴正在執行的程序,進行重啟 3)正在執行的程序收到訊號後,會以子程序的方式啟動新的bin檔案 4)新程序接受新請求,並處理 5)老程序不再接受請求,但是要等正在處理的請求處理完成,所有在處理的請求處理完之後,便自動退出 6)新程序在老程序退出之後,由init程序收養,但是會繼續服務。
所以一步一步來看,關鍵是從第2步開始之後怎麼做,所以我們先來看看第2步的實現,這個應該說很簡單,傳送訊號量到一個程序,使用kill命令即可,在facebook這個專案中傳送的訊號量有3個:SIGINT,SIGTERM,SIGUSR2,前面兩個訊號收到後程序會直接退出,後面一個訊號SIGUSR2才會執行所謂的優雅重啟。
第3步,正在執行的程序收到SIGUSR2訊號後,會以子程序的方式啟動新的bin檔案。先直接上程式碼看:https://github.com/facebookgo/grace/blob/master/gracehttp/http.go
func (a *app) signalHandler(wg *sync.WaitGroup) { ch := make(chan os.Signal, 10) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR2) for { sig := <-ch switch sig { case syscall.SIGINT, syscall.SIGTERM: // this ensures a subsequent INT/TERM will trigger standard go behaviour of // terminating. 執行標準的go終止行為,程式就結束了 signal.Stop(ch) a.term(wg) return case syscall.SIGUSR2: // 這裡開始執行優雅重啟 err := a.preStartProcess() // 這個函式在原始碼中沒有具體實現功能,只是預留了一個鉤子函式,使用者可以註冊自己的函式,可以在重啟之前做些自定義的事情。一般情況下也沒有什麼可以做的,除非有些特殊的服務環境或是狀態儲存之類的,至少目前,我們的server還沒有遇到 if err != nil { a.errors <- err } // we only return here if there's an error, otherwise the new process // will send us a TERM when it's ready to trigger the actual shutdown. if _, err := a.net.StartProcess(); err != nil { // 這裡開始正式所謂的優雅重啟 a.errors <- err } } } }
a.net.StartProcess的過程我們來看看基本過程:
func (n *Net) StartProcess() (int, error) { listeners, err := n.activeListeners() // 獲取目前在監聽的埠,這塊也是重點,下面重點介紹 if err != nil { return 0, err } // Extract the fds from the listeners. 從監聽埠中把檔案描述符取出來 files := make([]*os.File, len(listeners)) for i, l := range listeners { files[i], err = l.(filer).File() if err != nil { return 0, err } defer files[i].Close() } // Use the original binary location. This works with symlinks such that if // the file it points to has been changed we will use the updated symlink. // 獲取可執行bin檔案的路勁,也可以是連結路勁,會使用最新的連結路徑作為啟動檔案路勁的 argv0, err := exec.LookPath(os.Args[0]) if err != nil { return 0, err } // Pass on the environment and replace the old count key with the new one. // 獲取 LISTEN_FDS 換進變數值 var env []string for _, v := range os.Environ() { if !strings.HasPrefix(v, envCountKeyPrefix) { env = append(env, v) } } env = append(env, fmt.Sprintf("%s%d", envCountKeyPrefix, len(listeners))) allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr}, files...) // 這裡呼叫一個golang底層的程序啟動函式,來指定,上面獲取的引數來啟動程序 process, err := os.StartProcess(argv0, os.Args, &os.ProcAttr{ Dir: originalWD, Env: env, Files: allFiles, }) if err != nil { return 0, err } // 返回新程序id。 return process.Pid, nil }
以上是啟動新程序,並且接管監聽埠的過程, 一般情況下埠是不可以重複監聽的,所以這裡就要需要使用比較特別的辦法,從上面的程式碼來看就是讀取監聽埠的檔案描述符,並且把監聽埠的檔案描述符傳遞給子程序,子程序裡從這個檔案描述符實現對埠的監聽
另外還有一個比較特別的地方就是老的介面怎麼關閉的問題,關閉必須要把已經收到的請求處理完成之後再關閉。為此facebook的同學另外開了一個專案httpdown,繼承了原始的httpserver,但是多了對各種連結狀態的維護和處理,這部分後面在分析。
相關推薦
golang的facebookgo grace優雅重啟原理分析
從原理上來說是這樣一個過程: 1)釋出新的bin檔案去覆蓋老的bin檔案 2)傳送一個訊號量,告訴正在執行的程序,進行重啟 3)正在執行的程序收到訊號後,會以子程序的方式啟動新的bin檔案 4)新程序接受新請求,並處理 5)老程序不再
Golang開發支持平滑升級(優雅重啟)的HTTP服務
response def files all 結束 wait stop error: 如何 Golang開發支持平滑升級(優雅重啟)的HTTP服務 前段時間用Golang在做一個HTTP的接口,因編譯型語言的特性,修改了代碼需要重新編譯可執行文件,關閉正在運行的老程序,並
彈出SD卡導致的重啟問題分析
2018-10-10 在Android8.0上,安裝SD卡,設定為內部儲存,然後把安裝的應用move到SD卡上,開啟應用,然後在setting裡彈出(reject)SD卡,會發生重啟。 log 01-01 21:04:55.321858 1050 1081 D Pack
Android patch後重啟問題分析
在合入Android patch過程中會遇到Crash重啟的情況,在logcat日誌也只會列印一些崩潰的堆疊,這些資訊很難 幫助我們定位問題。 首先先看一下我遇到的一個logcat關於Crash的列印資訊: 如: 952 555
平滑重啟和平滑重啟原理
什麼是平滑重啟? 平滑重啟不同於普通的重啟,平滑重啟可以做到在不影響使用者的情況下重啟服務,以便重新載入PHP程式,完成業務程式碼更新。 平滑重啟一般應用於業務更新或者版本釋出過程中,能夠避免因為程式碼釋出重啟服務導致的暫時性服務不可用的影響。 注意:只有子程序執行過程
android展訊平臺 重啟案例分析(二)
./0000.log watchdog重啟 01-02 02:01:02.458 551 1010 W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in monitor com.android.s
notification使用不當導致的宕機重啟問題分析(Could not copy bitmap to parcel blob. )
前言 前段時間遇到了一個宕機重啟問題,比較複雜,涉及到多方面的知識,我也分析了很長的時間,期間學到了很多東西,現在把分析的過程整理一下,希望可以給大家一點幫助和啟發,同時也幫助自己再鞏固一下。 一、問題的復現 首先說一下問題最開始的分析思路以及復現的過程,log 中最核心的部
Android重啟原因分析
重啟原因分類 1.上層造成重啟 system_server被殺watchdog重啟重要執行緒阻塞2.kernel造成重啟 空指標非法地址3.kernel watchdog造成重啟,原因不確定 記憶體原因nand驅動log檢視步驟及關鍵字 1. 重啟後的kernel.log或
JNI引用溢位導致的重啟問題分析
問題描述 JNI全域性引用異常導致的重啟問題JNI ERROR (app bug): global reference table overflow (max=51200)' Log pid: 1279, tid: 2518, name: Binder:1279_9
Android 系統(74)--Android重啟原因分析
重啟原因分類1.上層造成重啟system_server被殺watchdog重啟重要執行緒阻塞2.kernel造成重啟空指標非法地址3.kernel watchdog造成重啟,原因不確定記憶體原因nand驅動log檢視步驟及關鍵字1. 重啟後的kernel.log或misc/cmdline.log在log最前面
21. 重啟log分析
案例一 : kernel重啟 - mt6580.dtsi 現象 : 平臺 : androidN,MTK6580 排查過程: 1. 打串列埠log,發現如下: [ 1.607970] <2>.(2)[1:swapper/0]musb-hdrc
ELF格式的重定位原理分析
前面有篇文章分析了ELF格式,也只是讓我們對目標檔案有了一個大概的瞭解,並沒有說明一個十分重要的問題:重定位,今天重新看了下重定位的資料,終於弄懂了重定位的過程,下面來做一個分析。 我們將使用下面兩個
Android 系統(126)---Android的宕機、重啟問題分析方法
Android的宕機、重啟問題分析方法當手機長時間無法再被使用者控制操作時,我們稱為宕機。在這裡我們強調長時間,如果是短時間,歸結為效能問題。* 使用者操作手機無任何響應,如觸控式螢幕幕,按鍵操作等。* 手機螢幕黑屏,無法點亮螢幕。* 手機介面顯示內容和使用者輸入不相干。1. 系統簡圖當用戶對手機進行操作時,
MySQL無限重啟原因分析
最近在CentOS配置LAMP環境,裝完MySQL執行/usr/local/mysql/bin/mysqld_safe --user=mysql &,MySQL無限重啟: “number of
linux 優雅的退出/關閉/重啟gunicorn進程
inux HR down ref 通過 AS 銷毀 發生 html 在工作中,會發現gunicorn啟動的web服務,無論怎麽使用kill -9 進程號都是無法殺死gunicorn,經過我一番百度和谷歌,發現想要刪除gunicorn進程其實很簡單。 第一步獲取Gunicor
Spring Boot 1.X和2.X優雅彩38平臺出租重啟實戰
main pau ble eas ren 超過 kill -9 tst 兼容 項目在彩38平臺出租 haozbbs.com Q1446595067 重新發布的過程中,如果有的請求時間比較長,還沒執行完成,此時重啟的話就會導致請求中斷,影響業務功能,優雅重啟可以保證在停止的時
生產環境優雅的重啟基於Nginx、Tornado的Web服務進程
進程關閉 nod add ocs unix 內部 start logfile stop Nginx是一個高效的Web服務器及代理服務器,Tornado是一個基於epoll的異步Web開發框架,通常使用Nginx做為Web服務器時,都會以FastCGI模式,而我們從開發、調試
優雅的退出/關閉/重啟gunicorn進程
unicorn ati local 進程id 命令 怎麽 gun 百度 hup 在工作中,會發現gunicorn啟動的web服務,無論怎麽使用kill -9 進程號都是無法殺死gunicorn,經過我一番百度和谷歌,發現想要刪除gunicorn進程其實很簡單。 第一步獲
1.報出問題: Please change caller according to com.intellij.openapi.project. IndexNotReadyException documentation 2.分析問題: 提示資訊,不影響編譯 3.解決方案: 重啟AS
1.報出問題: Please change caller according to com.intellij.openapi.project. IndexNotReadyException documentation 2.分析問題: 提示資訊,不影響編譯 3.解
Spring Developer Tools 原始碼分析:三、重啟自動配置'
接上文 Spring Developer Tools 原始碼分析:二、類路徑監控,接下來看看前面提到的這些類是如何配置,如何啟動的。 spring-boot-devtools 使用了 Spring Boot 的自動配置方式,我們先關注本地開發環境中自動重啟的部分。 在 LocalDevToolsAut