鍍金池/ 問(wèn)答/Java  PHP  C  C++  GO/ golang http server重啟過(guò)程中如何繼續(xù)提供服務(wù)(優(yōu)雅重啟)

golang http server重啟過(guò)程中如何繼續(xù)提供服務(wù)(優(yōu)雅重啟)

架構(gòu)是這樣的:
nginx做反向代理,將http請(qǐng)求proxy pass到后端的golang http server

 nginx==>httpserver

可否這樣實(shí)現(xiàn)優(yōu)雅重啟
1.啟動(dòng)一個(gè)新的golang http server監(jiān)聽(tīng)其他端口
2.修改nginx配置文件,將之前的代理端口改為新啟動(dòng)的server監(jiān)聽(tīng)的端口
3.reload nginx
4.并行一段時(shí)間老的http server沒(méi)有請(qǐng)求處理,則kill掉

整體實(shí)現(xiàn)優(yōu)雅重啟?這個(gè)是否可行,還有什么更好的方案?

回答
編輯回答
荒城

想到兩個(gè)方法:

方法一:
如果是比較新的內(nèi)核版本3.9以上,支持SO_REUSEPORT,那么你可以:

  1. 啟動(dòng)一個(gè)新的進(jìn)程,也監(jiān)聽(tīng)相同的端口。
  2. 新的進(jìn)程啟動(dòng)后給老的進(jìn)程發(fā)個(gè)信號(hào)。
  3. 老的進(jìn)程收到后停止接收新的連接請(qǐng)求(停止Accept,關(guān)閉Listen Socket),
    等所有已經(jīng)存在的連接處理完自動(dòng)退出。

如果不支持SO_REUSEPORT,不同進(jìn)程無(wú)法同時(shí)監(jiān)聽(tīng)同一個(gè)端口,則需要在老的進(jìn)程內(nèi)fork一個(gè)子進(jìn)程,并且把負(fù)責(zé)監(jiān)聽(tīng)的文件描述符傳給新進(jìn)程。
這個(gè)方法可以實(shí)現(xiàn)你的需求,但需要比較多的修改Golang封裝的net/http等系統(tǒng)庫(kù),技術(shù)復(fù)雜度比較高。
好處是不需要nginx參與,對(duì)它透明。

方法二:
可以同時(shí)運(yùn)行兩個(gè)或更多個(gè)http server,同時(shí)提供服務(wù),讓nginx做負(fù)載均衡,其中有一個(gè)需要升級(jí)重啟時(shí),就發(fā)個(gè)信號(hào),收到信號(hào)后停止接收新請(qǐng)求,已有請(qǐng)求處理完畢正常退出就可以了。這個(gè)過(guò)程不需要修改nginx配置,也不需要reload nginx。
這個(gè)方法也需要改Golang封裝的net/http,但修改量相比方法一會(huì)小很多。

2017年2月20日 04:19