中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何進行gunicorn Arbiter 源碼解析

發布時間:2022-01-10 09:41:29 來源:億速云 閱讀:159 作者:柒染 欄目:網絡安全

小編今天帶大家了解如何進行gunicorn Arbiter 源碼解析,文中知識點介紹的非常詳細。覺得有幫助的朋友可以跟著小編一起瀏覽文章的內容,希望能夠幫助更多想解決這個問題的朋友找到問題的答案,下面跟著小編一起深入學習“如何進行gunicorn Arbiter 源碼解析”的知識吧。

如前文所述,Arbiter是gunicorn master進程的核心。Arbiter主要負責管理worker進程,包括啟動、監控、殺掉Worker進程;同時,Arbiter在某些信號發生的時候還可以熱更新(reload)App應用,或者在線升級gunicorn。Arbiter的核心代碼在一個文件里面,代碼量也不大,源碼在此:https://github.com/benoitc/gunicorn。

Arbiter主要有以下方法:

setup:

    處理配置項,最重要的是worker數量和worker工作模型

init_signal

    注冊信號處理函數

handle_xxx:

    各個信號具體的處理函數

kill_worker,kill_workers:

    向worker進程發信號

spawn_worker, spawn_workers:

    fork出新的worker進程

murder_workers:

    殺掉一段時間內未響應的worker進程

manage_workers:

    根據配置文件的worker數量,以及當前active的worker數量,決定是要fork還是kill worker進程

reexec

    接收到信號SIGUSR2調用,在線升級gunicorn

reload:

    接收到信號SIGHUP調用,會根據新的配置新啟動worker進程,并殺掉之前的worker進程

sleep

    在沒有信號處理的時候,利用select的timeout進行sleep,可被喚醒

wakeup

    通過向管道寫消息,喚醒進程

run

    主循環

  Arbiter真正被其他代碼(Application)調用的函數只有__init__和run方法,在一句代碼里:

    Arbiter(self).run()

  上面代碼中的self即為Application實例,其中__init__調用setup進行配置項設置。下面是run方法偽代碼


def run()
    self.init_signal()
    self.LISTENERS = create_sockets(self.cfg, self.log)
    self.manage_workers()    while True:        if no signal in SIG_QUEUE
            self.sleep()        else:
            handle_signal()


 關于fork子進程

  fork子進程的代碼在 spawn_worker, 源碼如下:

如何進行gunicorn Arbiter 源碼解析 Arbiter.spawn_worker

  主要流程:

    (1)加載worker_class并實例化(默認為同步模型 SyncWorker)

    (2)父進程(master進程)fork之后return,之后的邏輯都在子進程中運行

    (3)調用worker.init_process 進入循環,新航道雅思培訓的所有工作都在這個循環中

    (4)循環結束之后,調用sys.exit(0)

    (5)最后,在finally中,記錄worker進程的退出

    

    下面是我自己寫的一點代碼,把主要的fork流程簡化了一下


 1 # prefork.py 2 import sys 3 import socket 4 import select 5 import os 6 import time 7   8 def do_sub_process(): 9     pid = os.fork()10     if pid < 0:11         print 'fork error'12         sys.exit(-1)13     elif pid > 0:14         print 'fork sub process %d'  % pid15         return16  17     # must be child process18     time.sleep(1)19     print 'sub process will exit', os.getpid(), os.getppid()20     sys.exit(0)21  22 def main():23     sub_num = 224     for i in range(sub_num):25         do_sub_process()26     time.sleep(10)27     print 'main process will exit', os.getpid()28  29 if __name__ == '__main__':30     main()


在測試環境下輸出:

  fork sub process 9601

  fork sub process 9602

  sub process will exit 9601 9600

  sub process will exit 9602 9600

  main process will exit 9600

  需要注意的是第20行調用了sys.exit, 保證子進程的結束,否則會繼續main函數中for循環,以及之后的邏輯。注釋掉第19行重新運行,看輸出就明白了。

關于kill子進程

  master進程要kill worker進程就很簡單了,直接發信號,源碼如下:


 1     def kill_worker(self, pid, sig): 2         """\ 3         Kill a worker 4  5         :attr pid: int, worker pid 6         :attr sig: `signal.SIG*` value 7          """ 8         try: 9             os.kill(pid, sig)10         except OSError as e:11             if e.errno == errno.ESRCH:12                 try:13                     worker = self.WORKERS.pop(pid)14                     worker.tmp.close()15                     self.cfg.worker_exit(self, worker)16                     return17                 except (KeyError, OSError):18                     return19             raise


關于sleep與wakeup

  我們再來看看Arbiter的sleep和wakeup。Arbiter在沒有信號需要處理的時候會"sleep",當然,不是真正調用time.sleep,否則信號來了也不能第一時間處理。這里得實現比較巧妙,利用了管道和select的timeout。看代碼就知道了


        def sleep(self):        """\
        Sleep until PIPE is readable or we timeout.
        A readable PIPE means a signal occurred.        """
            ready = select.select([self.PIPE[0]], [], [], 1.0) # self.PIPE = os.pipe()
            if not ready[0]: 
                return
            while os.read(self.PIPE[0], 1):                pass

  代碼里面的注釋寫得非常清楚,要么PIPE可讀立即返回,要么等待超時。管道可讀是因為有信號發生。這里看看pipe函數

  •   os.pipe()

  • Create a pipe. Return a pair of file descriptors (r,w) usable for reading and writing, respectively.

  那我們看一下什么時候管道可讀:肯定是往管道寫入的東西,這就是wakeup函數的功能

        def wakeup(self):            """
            Wake up the arbiter by writing to the PIPE            """
            os.write(self.PIPE[1], b'.')

最后附上Arbiter的信號處理

退出,INT:快速關閉

TERM: 優雅關機。等待工作人員完成其當前請求,直到超時。

HUP:重新加載配置,用新配置啟動新的工作進程,并優雅地關閉舊的工作進程。如果應用程序未預加載(使用--preload選項),Gunicorn也將加載新版本。

TTIN:將進程數增加一個

TTOU:將進程數減少一個

USR1:重新打開日志文件

USR2:在飛行中升級Gunicorn。應使用單獨的術語信號終止舊進程。此信號也可用于使用預加載應用程序的新版本。

絞盤:當Gunicorn被守護時,優雅地關閉工作進程。

感謝大家的閱讀,以上就是“如何進行gunicorn Arbiter 源碼解析”的全部內容了,學會的朋友趕緊操作起來吧。相信億速云小編一定會給大家帶來更優質的文章。謝謝大家對億速云網站的支持!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

云南省| 资中县| 甘谷县| 阜康市| 交城县| 松原市| 石景山区| 阿尔山市| 赤城县| 定日县| 平度市| 朝阳县| 连山| 邳州市| 格尔木市| 枣庄市| 南雄市| 台南县| 锦州市| 淅川县| 新郑市| 江达县| 富平县| 西贡区| 河北区| 扎囊县| 枝江市| 池州市| 新余市| 东明县| 南漳县| 永济市| 马边| 恩平市| 白山市| 太仆寺旗| 景泰县| 中方县| 凌海市| 醴陵市| 抚顺县|