WSGI & uWSGI 以及 uwsgi

主要內容:html

  • 1.WSGI
  • 2.uWSGI
  • 3.uwsgi

 

1. WSGIpython

1.1 WSGI相關概述linux

引子: wsgi server (好比uWSGI) 要和 wsgi application(好比django )交互,uwsgi須要將過來的請求轉給django 處理,那麼uWSGI 和 django的交互和調用就須要一個統一的規範,這個規範就是WSGI WSGI(Web Server Gateway Interface)nginx

  • WSGI,全稱 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是爲 Python 語言定義的 Web 服務器和 Web 應用程序或框架之間的一種簡單而通用的接口。自從 WSGI 被開發出來之後,許多其它語言中也出現了相似接口。
  • WSGI 的官方定義是,the Python Web Server Gateway Interface。從名字就能夠看出來,這東西是一個Gateway,也就是網關。網關的做用就是在協議之間進行轉換。
  • WSGI 是做爲 Web 服務器與 Web 應用程序或應用框架之間的一種低級別的接口,以提高可移植 Web 應用開發的共同點。WSGI 是基於現存的 CGI 標準而設計的

1.2 定義一個簡版的WSGI 接口git

  • 一個 application函數
    from wsgiref.simple_server import make_server
    
    def application(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [b'<h1>Hello, web!</h1>']
    
    httpd = make_server('', 8080, application)
    
    print('Serving HTTP on port 8080...')
    # 開始監聽HTTP請求:
    httpd.serve_forever()
  • 相關分析
    注意:
    
        整個application()函數自己沒有涉及到任何解析HTTP的部分,也就是說,底層代碼不須要咱們本身編寫,
    
        咱們只負責在更高層次上考慮如何響應請求就能夠了。
        application()函數必須由WSGI服務器來調用。有不少符合WSGI規範的服務器,咱們能夠挑選一個來用。
    
        Python內置了一個WSGI服務器,這個模塊叫wsgiref   
        application()函數就是符合WSGI標準的一個HTTP處理函數,它接收兩個參數:
    
            //environ:一個包含全部HTTP請求信息的dict對象;  
            //start_response:一個發送HTTP響應的函數。
    
    在application()函數中,調用:start_response('200 OK', [('Content-Type', 'text/html')])
    
    就發送了HTTP響應的Header,注意Header只能發送一次,也就是隻能調用一次start_response()函數。
        start_response()函數接收兩個參數,一個是HTTP響應碼,一個是一組list表示的HTTP Header,每一個Header用一個包含兩個str的tuple表示。
    
        一般狀況下,都應該把Content-Type頭髮送給瀏覽器。其餘不少經常使用的HTTP Header也應該發送。
    而後,函數的返回值b'<h1>Hello, web!</h1>'將做爲HTTP響應的Body發送給瀏覽器。
    有了WSGI,咱們關心的就是如何從environ這個dict對象拿到HTTP請求信息,而後構造HTML,經過start_response()發送Header,最後返回Body。

1.3 WSGI 的做用web

WSGI有兩方:「服務器」或「網關」一方,以及「應用程序」或「應用框架」一方。服務方調用應用方,提供環境信息,以及一個回調函數(提供給應用程序用來將消息頭傳遞給服務器方),並接收Web內容做爲返回值。

所謂的 WSGI中間件同時實現了API的兩方,所以能夠在WSGI服務和WSGI應用之間起調解做用:從WSGI服務器的角度來講,中間件扮演應用程序,而從應用程序的角度來講,中間件扮演服務器。「中間件」組件能夠執行如下功能:

重寫環境變量後,根據目標URL,將請求消息路由到不一樣的應用對象。
容許在一個進程中同時運行多個應用程序或應用框架。
負載均衡和遠程處理,經過在網絡上轉發請求和響應消息。
進行內容後處理,例如應用XSLT樣式表
View Code

2. uWSGIdjango

1.1 uWSGI的相關概述瀏覽器

uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的做用是與uWSGI服務器進行交換。服務器

  • WSGI是一種通訊協議。
  • uwsgi同WSGI同樣是一種通訊協議。
  • 而uWSGI是實現了uwsgi和WSGI兩種協議的Web服務器。

1.2 uWSGI配置的的理解網絡

(1) 通訊接口:    http/http-socket/socket

socket 方式:     socket  = 0.0.0.0:8000

  • 如今大部分web服務器(如nginx)支持uwsgi,這是這三種方式最高效的一種形式,socket通訊速度會比http快 , 
  •  注: 指定socket協議,運行django,只能與nginx結合時

    

http 方式:  http = 0.0.0.0:8000

   

   

     

 

上面兩個圖都是http方式,使用http啓動uwsgi,系統會額外啓動一個http進程,從級別上來講,它和nginx是同一級別的,因此客戶端和uwsgi通訊,徹底能夠繞過nginx,不須要額外進行一個轉發(如第二張圖同樣),但很顯然,這是並非一個很明智但選擇,這樣會失去了nginx不少優秀的功能。

所以:  若是你沒用nginx,只想本身啓動一個http界面,用這個

 

--- 另外 還有一方式,可是在uWSGI的配置文件中並未展現出: 具體使用待定---

 http -socket 方式        http-socket=127.0.0.1:8000

       

http-socket方式,這個適用於web服務器不支持uwsgi時。

 

(2)    processes/workers.

   表示開啓多進程,根據你的應有開啓合適的進程數,在一些參考資料上,可能會看到processes = 2 * cpucores或者workers = 2 * cpucores,若是應有比較簡單,這樣設置通常能夠。若是想更合理,官方提供了uwsgitop去得到一個較爲合理的值。

(3)threads & enable-threads
python中存在GIL,實際上不存在真正意義上的多線程,可是否須要,這個就根據各自但需求設定了。結合processes:

  • processes=2
  • threads=4

表示2個進程,每一個進程中有4個線程。

  • 因爲GIL的存在,uwsgi索性默認不支持多線程,不對GIL進行初始化。但若是但願程序中的線程發揮做用,須要加入enable-threads=True;
  • 但若是已經在多線程模式(使用 threads 選項)下,那麼uWSGI將會自動啓用線程支持。

(4)uid & gid & chmod-socket
       uwsgi不建議使用root權限去啓動uwsgi實例。能夠經過root用戶去運行uwsgi文件,當經過uid和gid去修改用戶(移除root權限)。而且,若是你使用的是socket的通訊方式,最好加上chmod-socket字段,在linux下,socket的啓動方式,套接字相似文件,你必須保證有權限去讀取它。

  • chmod-socket=664
  • uid=1000
  • gid=1000

(5)master
       意味着啓動一個master主進程來管理其餘進程,建議啓動這個進程,在管理的時候比較方便;若是kill這個master進程,至關於關閉全部的uwsgi進程

----------- 內容摘自: https://blog.csdn.net/l_vip/article/details/81487608  -------------------------------------------

3. uwsgi

 概述: uwsgi是服務器和服務端應用程序的通訊協議,規定了怎麼把請求轉發給應用程序和返回 

關於 uwsgi的理解 

  本文根據代碼閱讀以及參照多種文檔,描述了uwsgi的啓動多進程+多線程工做緣由,以及thunder_lock參數的做用:

  • uwsgi是用c語言寫的一個webserver,能夠啓動多個進程,進程裏面能夠啓動多個線程來服務。進程分爲主進程和worker進程,worker裏面能夠有多個線程。
  • 一開始進入main函數,啓動這個就是主進程了,uwsgi_setup函數(主進程)裏面針對選項參數作一些處理,執行環境設置,執行一些hook,語言環境初始化(python),若是沒有設置延遲加載app,則app在主進程加載;若是設置了延遲加載,則在每個worker進程中都會加載一次。uwsgi_setup函數還執行了插件的初始化(當前我只關心http、python:http是gateway類型的插件,這種插件是向外暴露http服務的,python的requests類型的插件,用來服務請求的)、tcp socket的綁定與監聽(這個是指http與work之間的通訊,且它的端口是自動產生的)。最後uwsgi主進程fork了指定worker進程用來接收(accept)請求。雖然在setup中就fork了子進程,可是如今尚未開始accept。
  • wsgi_run函數就是真正的開始執行了,這個函數分爲倆個部分,主進程執行部分和worker進程執行部分。主進程執行部分是一個無限循環,他能夠執行特定的hook以及接收信號等,總之是用來管理worker進程以及一些定時或者事件觸發任務。worker部分:註冊型號處理函數,執行一些hook,循環接收(accept)請求。在啓動woker時能夠根據--threads參數指定要產生的線程個數,不然只在當前進程啓動一個線程。這些線程循環接收請求並處理。
  • 在worker中接收請求的函數wsgi_req_accept有一個鎖:thunder_lock,這個鎖用來串行化accept,防止「驚羣」現象:參考這裏
    •   驚羣現象出如今這樣的狀況:主進程綁定並監聽socket,而後調用fork,在各個子進程進行accept。不管任什麼時候候,只要有一個鏈接嘗試鏈接,全部的子進程都將被喚醒,但只有一個會鏈接成功,其餘的會獲得一個EAGAIN的錯誤,浙江致使巨大的CPU資源浪費,若是在進程中使用線程,這個問題被再度放大。一個解決方法是串行化accept,在accept前防止一個鎖。

-------- 以上內容摘自:   https://blog.csdn.net/pzqingchong/article/details/79522215 -------

相關文章
相關標籤/搜索