天天看點

Python web分析(gunicorn + werkzeug)

flask

FBI WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
           

兄弟們,熟悉的片頭有沒有,每次flask都會善意提醒大家僅限在開發環境使用,生産環境請用别的WSGI伺服器。

那什麼是WSGI伺服器?

WSGI全稱Python Web Server Gateway Interface,是專門為python web架構和web伺服器之間制定的标準接口。

Python web分析(gunicorn + werkzeug)

如上是web通信過程,使用者如何通路我們用Django和Flask架構編寫的接口?需要通過web伺服器(nginx、apache做轉發、負載均衡)和WSGI将請求送入web架構,其中WSGI就是web伺服器和web架構之間的橋梁,有多種實作

比如Gunicorn (/dʒi-'junɪ.kɔrn/)

Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.
           

flask分析

flask自帶了一個簡單的wsgi,通過app.run調用

werkzeug

(/ˈvɛrkʦɔyk/)提供的

run_simple

方法來啟動服務。我們可以看到,flask預設啟用了多線程,即每個請求單獨拉個線程處理。也可以開多程序(通過設定參數processes),隻不過flask多線程和多程序無法共存。

options.setdefault("use_reloader", self.debug)
options.setdefault("use_debugger", self.debug)
options.setdefault("threaded", True)

cli.show_server_banner(self.env, self.debug, self.name, False)

from werkzeug.serving import run_simple

try:
    run_simple(t.cast(str, host), port, self, **options)
finally:
    ...
           

但是能支援多少并發量呢,很遺憾,并發高了之後,線程已經建立不了了,服務也随之崩潰了,這在生産環境可是個要命的大問題。

libgomp: Thread creation failed: Resource temporarily unavailable
           

但gunicorn卻能安然無恙,它使用線程池的方式,不會無限制的建立線程。

werkzeug在每個請求來的時候通過

threading.Thread

os.fork

來建立線程和程序,請求結束即銷毀。這樣建立銷毀的時間開銷是個巨大的浪費。

當然flask也可以通過設定threaded=False且processes=1為單程序單線程,即每個請求在主線程中處理,可想而知性能會很差。

是以建議在生産環境使用gunicorn作為wsgi伺服器,來實作更高的性能和穩定性。

性能測評

分析一個系統的好壞,QPS是很關鍵的一個名額,即每秒請求次數,其與接口響應時間、WSGI伺服器、web伺服器、系統架構和硬體水準是息息相關的。

用wrk可以對系統的好壞進行測評。

root@:/# wrk --help
Usage: wrk <options> <url>
  Options:
    -c, --connections <N>  Connections to keep open
    -d, --duration    <T>  Duration of test
    -t, --threads     <N>  Number of threads to use

    -s, --script      <S>  Load Lua script file
    -H, --header      <H>  Add header to request
        --latency          Print latency statistics
        --timeout     <T>  Socket/request timeout
    -v, --version          Print version details

  Numeric arguments may include a SI unit (1k, 1M, 1G)
  Time arguments may include a time unit (2s, 2m, 2h)
           

python由于GIL鎖限制,多線程模式會受到限制,尤其是對于CPU密集型的接口。