大數(shù)據(jù)開(kāi)發(fā)技術(shù)學(xué)習(xí)忱屑,Python程序中不同的重啟機(jī)制

科多大數(shù)據(jù)帶你看看,大數(shù)據(jù)開(kāi)發(fā)技術(shù)學(xué)習(xí)之Python程序中不同的重啟機(jī)制

分析典型案例:

Celery 分布式異步任務(wù)框架

Gunicorn Web容器

之所以挑這兩個(gè)携栋,不僅僅是應(yīng)用廣泛柳刮,而且兩個(gè)的進(jìn)程模型比較類似挖垛,都是Master、Worker的形式秉颗,在熱重啟上思路和做法又基本不同痢毒,比較有參考意義

知識(shí)點(diǎn):

atexit

os.execv

模塊共享變量

信號(hào)處理

sleep原理:select

文件描述符共享

這幾個(gè)知識(shí)點(diǎn)不難,區(qū)別只在于Celery和Gunicorn的應(yīng)用方式站宗。如果腦海中有這樣的知識(shí)點(diǎn)闸准,這篇文章也就是開(kāi)闊下視野而已。梢灭。夷家。

Celery和Gunicorn都會(huì)在接收到HUP信號(hào)時(shí),進(jìn)行熱重啟操作

Celery的重啟:關(guān)舊Worker敏释,然后execv重新啟動(dòng)整個(gè)進(jìn)程

Gunicorn的重啟:建立新Worker库快,再關(guān)舊Worker,Master不動(dòng)

下面具體的看下它們的操作和核心代碼闽铐。

對(duì)于Celery:

def _reload_current_worker():

platforms.close_open_fds([

sys.__stdin__, sys.__stdout__, sys.__stderr__,

])

os.execv(sys.executable, [sys.executable] + sys.argv)

def install_worker_restart_handler(worker, sig='SIGHUP'):

def restart_worker_sig_handler(*args):

"""Signal handler restarting the current python program."""

import atexit

atexit.register(_reload_current_worker)

from celery.worker import state

state.should_stop = EX_OK

platforms.signals[sig] = restart_worker_sig_handler

HUP上掛的restart_worker_sig_handler 就做了兩件事:

注冊(cè)atexit函數(shù)

設(shè)置全局變量

考慮到這個(gè)執(zhí)行順序沐悦,應(yīng)該就能明白Celery 是Master和Worker都退出了,嶄新呈現(xiàn)。继薛。

看過(guò)APUE的小伙伴蓝谨,應(yīng)該比較熟悉 atexit 了督笆,這里也不多說(shuō)。os.execv還挺有意思,根據(jù)Python文檔,這個(gè)函數(shù)會(huì)執(zhí)行一個(gè)新的函數(shù)用于替換掉 當(dāng)前進(jìn)程 ,在Unix里,新的進(jìn)程直接把可執(zhí)行程序讀進(jìn)進(jìn)程,保留同樣的PID舅柜。

在Python os標(biāo)準(zhǔn)庫(kù)中梭纹,這是一整套基本一毛一樣的函數(shù),也許應(yīng)該叫做函數(shù)族了:

os. execl ( path , arg0 , arg1 , … )

os. execle ( path , arg0 , arg1 , … , env )

os. execlp ( file , arg0 , arg1 , … )

os. execlpe ( file , arg0 , arg1 , … , env )

os. execv ( path , args )

os. execve ( path , args , env )

os. execvp ( file , args )

os. execvpe ( file , args , env )

以exec開(kāi)頭致份,后綴中的l和v兩種变抽,代表命令行參數(shù)是否是變長(zhǎng)的(前者不可變),p代表是否使用PATH定位程序文件,e自然就是在新進(jìn)程中是否使用ENV環(huán)境變量了

然后給worker的state.should_stop變量設(shè)置成False氮块。绍载。。 模塊共享變量 這個(gè)是PythonFAQ里提到的一種方便的跨模塊消息傳遞的方式滔蝉,運(yùn)用了Python module的單例击儡。我們都知道Python只有一個(gè)進(jìn)程,所以單例的變量到處共享

而should_stop這個(gè)變量也是簡(jiǎn)單粗暴蝠引,worker在執(zhí)行任務(wù)的循環(huán)中判斷這個(gè)變量阳谍,即執(zhí)行異步任務(wù)->查看變量->獲得異步任務(wù)->繼續(xù)執(zhí)行 的循環(huán)中,如果True就拋出一個(gè)【應(yīng)該關(guān)閉】異常螃概,worker由此退出矫夯。

這里面有一個(gè)不大不小的坑是:信號(hào)的發(fā)送對(duì)于外部的工具,例如kill吊洼,是非阻塞的训貌,所以當(dāng)HUP信號(hào)被發(fā)出后,worker可能并沒(méi)有完成重啟(等待正在執(zhí)行的舊任務(wù)完成 才退出和新建)冒窍,因此如果整個(gè)系統(tǒng)中只使用HUP信號(hào)挨個(gè)灰度各個(gè)機(jī)器递沪,那么很有可能出現(xiàn)全部worker離線的情況

接下來(lái)我們看看Gunicorn的重啟機(jī)制:

信號(hào)實(shí)質(zhì)上掛在在Arbiter上,Arbiter相當(dāng)于master超燃,守護(hù)和管理worker的区拳,管理各種信號(hào),事實(shí)上它init的時(shí)候就給自己起好Master的名字了意乓,打印的時(shí)候會(huì)打出來(lái):

class Arbiter(object):

def __init__(self, app):

#一部分略

self.master_name = "Master"

def handle_hup(self):

"""\

HUP handling.

- Reload configuration

- Start the new worker processes with a new configuration

- Gracefully shutdown the old worker processes

"""

self.log.info("Hang up: %s", self.master_name)

self.reload()

這里的函數(shù)文檔里寫了處理HUP信號(hào)的過(guò)程了樱调,簡(jiǎn)單的三行:

讀取配置

開(kāi)啟新worker

優(yōu)雅關(guān)閉舊Worker

reload函數(shù)的實(shí)現(xiàn)本身沒(méi)什么復(fù)雜的约素,因?yàn)镚unicorn 是個(gè)Web容器,所以master里面是沒(méi)有業(yè)務(wù)邏輯的笆凌,worker都是master fork出來(lái)的圣猎,fork是可以帶著文件描述符(自然也包括socket)過(guò)去的。這也是Gunicorn可以隨意增減worker的根源

master只負(fù)責(zé)兩件事情:

拿著被Fork的worker的PID乞而,以供關(guān)閉和處理

1秒醒來(lái)一次送悔,看看有沒(méi)有worker超時(shí)了需要被干掉

while True:

sig = self.SIG_QUEUE.pop(0) if len(self.SIG_QUEUE) else None

if sig is None:

self.sleep()

self.murder_workers()

self.manage_workers()

continue

else:

#處理信號(hào)

在sleep函數(shù)中,使用了select.select+timeout實(shí)現(xiàn)爪模,和time.sleep的原理是一樣的欠啤,但不同之處在于select監(jiān)聽(tīng)了自己創(chuàng)建的一個(gè)PIPE,以供wakeup立即喚醒

總結(jié)

以上就介紹了Celery和Gunicorn的重啟機(jī)制差異屋灌。

從這兩者的設(shè)計(jì)來(lái)看洁段,可以理解他們這樣實(shí)現(xiàn)的差異。

Celery是個(gè)分布式共郭、異步的任務(wù)隊(duì)列祠丝,任務(wù)信息以及排隊(duì)信息實(shí)質(zhì)上是持久化在外部的MQ中的,例如RabbitMQ和redis除嘹,其中的持久化方式写半,這應(yīng)該另外寫一篇《高級(jí)消息隊(duì)列協(xié)議AMQP介紹》,就不在這里說(shuō)了尉咕,對(duì)于Celery的Master和Worker來(lái)說(shuō)叠蝇,可以說(shuō)是完全沒(méi)有狀態(tài)的。由Celery的部署方式也可以知道年缎,近似于一個(gè)服務(wù)發(fā)現(xiàn)的框架蟆肆,下線的Worker不會(huì)對(duì)整個(gè)分布式系統(tǒng)帶來(lái)任何影響。唯一的例外可能是Beat組件晦款,作為Celery定時(shí)任務(wù)的節(jié)拍器,要做少許改造以適配分布式的架構(gòu)枚冗,并且實(shí)現(xiàn)Send Once功能缓溅。

Gunicorn作為Python的Web容器之一,會(huì)接收用戶的請(qǐng)求赁温,雖然我們通常都會(huì)使用nginx放在Gunicorn前方做反向代理坛怪,通常也可以使用nginx來(lái)做upstream offline、online的熱重啟股囊,但那就不是一個(gè)層次的事情了

這里回頭來(lái)再吐槽Golang

項(xiàng)目中使用到了Golang的一個(gè)Web框架袜匿,Golang在1.8中也已經(jīng)支持Http.Server的熱關(guān)閉了,但是一是因?yàn)閯偝霾痪?竟然現(xiàn)在才出)稚疹,二是因?yàn)镚olang的進(jìn)程模型和Python大相近庭居灯,go協(xié)程嘛,目前還沒(méi)有看到那個(gè)Web框架中真正實(shí)現(xiàn)Gunicorn類似的熱重啟。

Golang 在fcgi的操作應(yīng)該就類似Python之于wsgi了怪嫌。义锥。我感覺(jué)我是選擇錯(cuò)了一個(gè)web框架

也沒(méi)看見(jiàn)有人用syscall.Exec來(lái)用一下execve系統(tǒng)調(diào)用,Golang也沒(méi)看見(jiàn)有人用socket REUSE岩灭。拌倍。作為一個(gè)懶惰的人感覺(jué)很蛋疼。噪径。柱恤。

先讓nginx大法做這件事情好了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末找爱,一起剝皮案震驚了整個(gè)濱河市梗顺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缴允,老刑警劉巖荚守,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異练般,居然都是意外死亡矗漾,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門薄料,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)敞贡,“玉大人,你說(shuō)我怎么就攤上這事摄职√芤郏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵谷市,是天一觀的道長(zhǎng)蛔垢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)迫悠,這世上最難降的妖魔是什么鹏漆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮创泄,結(jié)果婚禮上艺玲,老公的妹妹穿的比我還像新娘。我一直安慰自己鞠抑,他們只是感情好饭聚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著搁拙,像睡著了一般秒梳。 火紅的嫁衣襯著肌膚如雪法绵。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天端幼,我揣著相機(jī)與錄音礼烈,去河邊找鬼。 笑死婆跑,一個(gè)胖子當(dāng)著我的面吹牛此熬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播滑进,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼犀忱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了扶关?” 一聲冷哼從身側(cè)響起阴汇,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎节槐,沒(méi)想到半個(gè)月后搀庶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铜异,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年哥倔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揍庄。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咆蒿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蚂子,到底是詐尸還是另有隱情沃测,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布食茎,位于F島的核電站蒂破,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏别渔。R本人自食惡果不足惜寞蚌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钠糊。 院中可真熱鬧,春花似錦壹哺、人聲如沸抄伍。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)截珍。三九已至攀甚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岗喉,已是汗流浹背秋度。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钱床,地道東北人荚斯。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像查牌,于是被迫代替她去往敵國(guó)和親事期。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容