django 的並發能力真的是令人擔憂,這里就使用 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 性能和瓶頸)。
- 高度可定制(內存大小限制,服務一定次數后重啟等)。
你應該是使用了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
即可。