Python框架下django 的併發和多執行緒
django 的併發能力真的是令人擔憂,django本身框架下只有一個執行緒在處理請求,任何一個請求阻塞,就會影響另一個情感求的響應,尤其是涉及到IO操作時,基於框架下開發的檢視的響應並沒有對應的開啟多執行緒,再者Python的多執行緒對於多核CPU有效利用率非常低,參照
這裡就使用 nginx + uwsgi 提供高併發
nginx 的併發能力超高,單臺併發能力過萬(這個也不是絕對),在純靜態的 web 服務中更是突出其優越的地方,由於其底層使用 epoll 非同步IO模型進行處理,使其深受歡迎
做過運維的應該都知道,php 需要使用 nginx + fastcgi 提供高併發,java 需要使用 nginx + tomcat 提供 web 服務
如何再次增加併發量
採用nginx做負載
去掉自增主鍵
原因很簡單,因為自增主鍵的存在寫庫存在搶鎖, 可以利用全域性id生成器提前生成id直接寫入資料庫
換成非同步任務去寫庫
如果資料只是存在mysql中做備份,建議使用非同步的方式寫入庫,先把資料寫到快取下發給使用者,之後在利用後臺非同步任務一點點的寫入,例如聊天系統可以這樣幹
換成更高效的框架或者語言
可以試試tornado, 如果tornado依然無法滿足,可以嘗試使用golango,畢竟golang是以高併發著稱, 而且是編譯語言,而且基於它的web框架也很容易上手,效能很可觀,例如Iris
======================================
django
毫無疑問,用原生django的server做處理的表現是最爛的,在10000次請求的情況下brokenpipe的機率極高,只有1400次請求被處理,成功率只有14%,我也懶得繼續測下去了。
django + nginx
這次搭上了nginx做反向代理,也使的脆弱的django伺服器的情況有所緩解,但成功率仍然不高(10000次請求中有3684個請求被處理)。
uwsgi + nginx
uwsgi是效能極高的一個由C編寫的伺服器,它使用uwsgi協議,這次讓它配合nginx處理django的request,引數為4程序+2執行緒,效能立即直線上升,處理請求的成功率也基本在90%左右,不過我在測試時遇到了一個坑,就是uwsgi在處理請求的時候傳送了佇列溢位的問題,因為當前測試設定的併發數為每秒1000次併發,而uwsgi的處理佇列容量預設為100,導致處理請求的時間加長,而這個問題則可以通過修改somaxcon的大小解決,總的來說,使用uwsgi+nginx是一個理想的選擇。
gunicorn + nginx
gunicorn跟uwsgi類似,也是一個高效能的http伺服器,它由ruby的unicorn專案移植,是由python編寫的,它的配置簡單,而且可以靈活地搭配其他網路庫,部署十分方便,在測試資料中可以看到,用這種配置執行django能在短時間內就能處理大量的併發請求,成功率在90%左右。
gunicorn + nginx + gevent
前面說的幾種環境,看似不錯,但我們需要追求完美!由於gunicorn是同步(sync)單執行緒模型的,有的時候它不免會發生一些阻塞問題,這時候我們為gunicorn加上-k gevent引數來用gevent做處理介面,這就比較靠譜地處理了阻塞問題,從資料中可以看到,gunicorn + nginx + gevent的模式不僅擁有100%的處理成功率,而且時間也在很短之內完成,是5組測試資料當中的效能最好的。
=======================================
多套方案來提高 python web 框架的併發處理能力
Python 常見部署方法有 :
- fcgi :用 spawn-fcgi 或者框架自帶的工具對各個 project 分別生成監聽程序,然後和 http 服務互動
- wsgi :利用 http 服務的 mod_wsgi 模組來跑各個 project(Web 應用程式或框架簡單而通用的 Web 伺服器 之間的介面)。
- uWSGI 是一款像 php-cgi 一樣監聽同一埠,進行統一管理和負載平衡的工具,uWSGI,既不用 wsgi 協議也不用 fcgi 協議,而是自創了一個 uwsgi 的協議,據說該協議大約是 fcgi 協議的 10 倍那麼快。
其實 WSGI 是分成 server 和 framework (即 application) 兩部分 (當然還有 middleware)。
嚴格說 WSGI 只是一個協議, 規範 server 和 framework 之間連線的介面。
WSGI server 把伺服器功能以 WSGI 介面暴露出來。比如 mod_wsgi 是一種 server, 把 apache 的功能以 WSGI 介面的形式提供出來。
- WSGI framework 就是我們經常提到的 Django 這種框架。不過需要注意的是, 很少有單純的 WSGI framework , 基於 WSGI 的框架往往都自帶 WSGI server。比如 Django、CherryPy 都自帶 WSGI server 主要是測試用途, 釋出時則使用生產環境的 WSGI server。而有些 WSGI 下的框架比如 pylons、bfg 等, 自己不實現 WSGI server。使用 paste 作為 WSGI server。
- Paste 是流行的 WSGI server, 帶有很多中介軟體。還有 flup 也是一個提供中介軟體的庫。
- 搞清除 WSGI server 和 application, 中介軟體自然就清楚了。除了 session、cache 之類的應用, 前段時間看到一個 bfg 下的中介軟體專門用於給網站換膚的 (skin) 。中介軟體可以想到的用法還很多。
- 這裡再補充一下, 像 django 這樣的框架如何以 fastcgi 的方式跑在 apache 上的。這要用到 flup.fcgi 或者 fastcgi.py (eurasia 中也設計了一個 fastcgi.py 的實現) 這些工具, 它們就是把 fastcgi 協議轉換成 WSGI 介面 (把 fastcgi 變成一個 WSGI server) 供框架接入。整個架構是這樣的: django -> fcgi2wsgiserver -> mod_fcgi -> apache 。
- 雖然我不是 WSGI 的粉絲, 但是不可否認 WSGI 對 python web 的意義重大。有意自己設計 web 框架, 又不想做 socket 層和 http 報文解析的同學, 可以從 WSGI 開始設計自己的框架。在 python 圈子裡有個共識, 自己隨手搞個 web 框架跟喝口水一樣自然, 非常方便。或許每個 python 玩家都會經歷一個倒騰框架的
uWSGI 的主要特點如下:
- 超快的效能。
- 低記憶體佔用(實測為 apache2 的 mod_wsgi 的一半左右)。
- 多app管理。
- 詳盡的日誌功能(可以用來分析 app 效能和瓶頸)。
- 高度可定製(記憶體大小限制,服務一定次數後重啟等)。
=========================================
https://segmentfault.com/q/1010000002548045
學習tornado時,發現tornado的非同步請求使用tornado.gen或者callback實現。
做實驗兩個請求,一個sleep上5秒,一個立即返回。先請求sleep,再請求立即返回的。 發現django並沒有做什麼處理。同樣可以在第一個請求sleep時,不影響第二個立即返回的請求。請問下django是怎麼處理的。
你應該是使用了Django自己的開發伺服器跑的例子,在Django關於manage.py的文件中寫道:
--nothreading
The development server is multithreaded by default. Use the --nothreading option to disable the use of threading in the development server.
也就是說,預設情況下你使用./manage.py runserver
會開啟多個執行緒對HTTP請求進行伺服,所以第二個請求進來時雖然第一個請求仍在sleep,但已經新開了一個執行緒進行響應處理,看起來像是“非阻塞”的工作模式,其實質是多執行緒而非單執行緒,想禁用這一行為也已經給出了答案,加上--nothreading
引數:./manage.py runserver --nothreading
即可。
Django就沒有用非同步,通過執行緒來實現併發,這也是WSGI普遍的做法,跟tornado不是一個概念