gunicorn是一個python Wsgi http server,只支持在Unix系統上運行,來源於Ruby的unicorn項目。Gunicorn使用
prefork master-worker模型(在gunicorn中,master被稱為arbiter),能夠與各種wsgi web框架協作。gunicorn的文檔是比較完善的,
這里也有部分中文翻譯,不過還是建議直接讀英文文檔。筆者並沒有在項目中真正使用過gunicorn,閱讀其源碼只要是為了了解其master worker模型,如有紕漏,還請多多指教。
gunicorn的安裝非常簡單,pip install guncorn 即可。后續如果用到異步的worker模型,還需要安裝對應的模塊(如gevent)
在裝好gunicorn之后, 我們來看看gunicorn的hello world。代碼來自官網,將下面的代碼放到gunicorn_app.py中:
1 def app(environ, start_response): 2 data = b"Hello, World!\n" 3 start_response("200 OK", [ 4 ("Content-Type", "text/plain"), 5 ("Content-Length", str(len(data))) 6 ]) 7 8 return iter([data])
可以看到app是非常標准的wsgi應用,然后我們啟動gunicorn:gunicorn -w 2 gunicorn_app:app。 輸出如下:
上圖展示了兩個很重要的信息:
第一:啟動了兩個worker,這是通過"-w 2"指定(默認為1)
第二:worker的工作模型是sync(默認),后面會詳細介紹worker模型
然后在另外一個terminal運行:ps -ef | grep python

可以看出 worker進程(pid:19469, 19470)是master進程(pid:19464)的子進程。
新起一個terminal,用curl測試: curl 127.0.0.1:8000
在該terminal輸出“Hello, World!”
前面提到,官方gunicorn只能在Unix上運行(貌似也有非官網的補丁,使其能在windows上運行,未求證),主要是因為源碼中使用了
fcntl,os.fork等只在unix上存在的模塊和接口。pre-fork就是指gunicorn啟動的時候,在主進程中會預先fork出指定數量(-w)的worker進程。這里先簡介Master Worker的工作流程,后文再對代碼做詳細介紹。
啟動gunicorn,首先初始化gunicorn.app.base.Application(或者基類,比如上面從命令行啟動時,是wsgiApplication),初始化中最重要的是讀取配置,支持文件或者命令行。然后調用Application.run(),該方法代碼如下:
調用Arbiter(self).run()之后,主進程(master)的所有邏輯都運行在Arbiter類里面。
Arbiter首先讀取配置項, 如worker數量,worker工作模式,監聽的地址等;然后初始化信號處理函數,然后建立socket,不過並不listen;接下來fork出所有的worker進程;最后進入循環:處理信號隊列中的信號,殺掉並重啟失去響應的子進程,如果沒事兒干,就“sleep”一會兒。
worker進程就更加簡單一下,首先是讀取配置,初始化信號處理函數,然后進入循環:處理監聽端口上的請求(也就是會調用到wsgi app的地方),然后向master報告自己還活着。另外,worker中是在信號發生的時候直接處理信號,而不是像master一樣放入信號隊列。
可以稍微改動一下app代碼,以便在客戶端請求的時候,服務器端能打印調用棧,下面是在我的機器上的輸出,后面將會對Arbiter和worker進行介紹。
- 0: FUNC:app(...) /home/xxx/gunicorn_app.py::16
- 1: FUNC:handle_request(...) /usr/local/lib/python2.7/dist-packages/gunicorn/workers/sync.py::176
- 2: FUNC:handle(...) /usr/local/lib/python2.7/dist-packages/gunicorn/workers/sync.py::135
- 3: FUNC:accept(...) /usr/local/lib/python2.7/dist-packages/gunicorn/workers/sync.py::30
- 4: FUNC:run_for_one(...) /usr/local/lib/python2.7/dist-packages/gunicorn/workers/sync.py::68
- 5: FUNC:run(...) /usr/local/lib/python2.7/dist-packages/gunicorn/workers/sync.py::124
- 6: FUNC:init_process(...) /usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py::132
- 7: FUNC:spawn_worker(...) /usr/local/lib/python2.7/dist-packages/gunicorn/arbiter.py::557
- 8: FUNC:spawn_workers(...) /usr/local/lib/python2.7/dist-packages/gunicorn/arbiter.py::590
- 9: FUNC:manage_workers(...) /usr/local/lib/python2.7/dist-packages/gunicorn/arbiter.py::524
- 10: FUNC:run(...) /usr/local/lib/python2.7/dist-packages/gunicorn/arbiter.py::189
- 11: FUNC:run(...) /usr/local/lib/python2.7/dist-packages/gunicorn/app/base.py::72
- 12: FUNC:run(...) /usr/local/lib/python2.7/dist-packages/gunicorn/app/base.py::192
- 13: FUNC:run(...) /usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py::74
- 14: FUNC:<module>(...) /usr/local/bin/gunicorn::11