搜尋
首頁運維安全如何進行gunicorn Arbiter 原始碼解析

如何進行gunicorn Arbiter 原始碼解析

May 12, 2023 pm 04:28 PM
gunicornarbiter

如前所述,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, 原始碼如下:

 Arbiter.spawn_worker如何进行gunicorn Arbiter 源码解析

  主要流程:

    (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: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 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 原始碼解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具