fastcgi ,經過flup模塊來支持,在nginx裏對應的配置指令是 fastcgi_passphp
http,nginx使用proxy_pass轉發,這個要求後端appplication必須內置一個能處理高併發的http server,在python的web框架當中,只能選擇tornado.html
uwsgi,包括4部分組成:python
nginx從0.8.4開始內置支持uwsgi協議,uwsgi協議很是簡單,一個4個字節header+一個body,body能夠是不少協議的包,好比說http,cgi等(經過header裏面字段標示)。nginx
uwsgi的特色在於自帶的進程控制程序.它是用c語言編寫,使用natvie函數,其實和spawn-fcgi/php-fpm相似。因此uwsgi能夠支持多種應用框架,包括(python,lua,ruby,erlang,go)等等程序員
mod_python,這是apache內置的模塊,很嚴重的依賴於mod_python編譯使用的python版本,和apache配套使用,不推薦web
cgi,這個太old,不推薦,並且nginx不支持cgi方式,只能用lighttpd或者apacheapache
spawn-fcgi,這個是fastcgi多進程管理程序,lighttpd安裝包附帶的,和 flup效果同樣,區別是flup是 python代碼級引入,spawn-fcgi是外部程序。spawn-fcgi用途很廣,能夠支持任意語言開發的代碼,php,python,perl,只要你代碼實現了fastcgi接口,它均可以幫你管理你的進程json
scgi,全名是Simple Common Gateway Interface,也是cgi的替代版本,scgi協議很簡單,我以爲和fastcgi差很少,只是沒有怎麼推廣開來,nginx對應的配置指令是scgi_pass,你想用就用,flup也支持。flask
Gunicorn,和uwsgi相似的工具,從rails的部署工具(Unicorn)移植過來的。可是它使用的協議是 WSGI,全稱是Python Web Server Gateway Interface ,這是python2.5時定義的官方標準(PEP 333 ),根紅苗正,並且部署比較簡單,http://gunicorn.org/ 上有詳細教程後端
mod_wsgi,apache的一個module,也是支持WSGI協議,https://code.google.com/p/modwsgi/
pip install uwsgi
uwsgi 有多種配置可用:
1,ini 2,xml 3,json 4,yaml
$ cat etc/uwsgi.ini [uwsgi] socket = 127.0.0.1:9005 chdir = /Users/suoning/python_project/trunk/ wsgi-file = main.py processes = 4 stats = 127.0.0.1:9000 daemonize = /tmp/uwsgiServer.log pidfile = /tmp/uwsgi.pid vacuum = true log-maxsize = 50000000 disable-logging = true callable = app $
經常使用選項:
socket : 地址和端口號,例如:socket = 127.0.0.1:50000
processes : 開啓的進程數量
workers : 開啓的進程數量,等同於processes(官網的說法是spawn the specified number of workers / processes)
chdir : 指定運行目錄(chdir to specified directory before apps loading)
wsgi-file : 載入wsgi-file(load .wsgi file)
stats : 在指定的地址上,開啓狀態服務(enable the stats server on the specified address)
threads : 運行線程。因爲GIL的存在,我以爲這個真心沒啥用。(run each worker in prethreaded mode with the specified number of threads)
master : 容許主進程存在(enable master process)
daemonize : 使進程在後臺運行,並將日誌打到指定的日誌文件或者udp服務器(daemonize uWSGI)。實際上最經常使用的,仍是把運行記錄輸出到一個本地文件上。
log-maxsize :以固定的文件大小(單位KB),切割日誌文件。 例如:log-maxsize = 50000000 就是50M一個日誌文件。
pidfile : 指定pid文件的位置,記錄主進程的pid號。
vacuum : 當服務器退出的時候自動清理環境,刪除unix socket文件和pid文件(try to remove all of the generated file/sockets)
disable-logging : 不記錄請求信息的日誌。只記錄錯誤以及uWSGI內部消息到日誌中。若是不開啓這項,那麼你的日誌中會大量出現這種記錄:
[pid: 347|app: 0|req: 106/367] 117.116.122.172 () {52 vars in 961 bytes} [Thu Jul 7 19:20:56 2016] POST /post => generated 65 bytes in 6 msecs (HTTP/1.1 200) 2 headers in 88 bytes (1 switches on core 0)
$ cat etc/nginx/servers/pan.conf server { listen 80; server_name localhost; location / { include uwsgi_params; uwsgi_pass 127.0.0.1:9005; } location /webstatic/ { expires 7d; add_header Cache-Control public; alias /Users/suoning/probject/python_project/webstatic/trunk/; } } $ $ nginx -t nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful $ $ nginx -s reload $
... app = Flask('pan') ... if __name__ == '__main__': # app.run(host='0.0.0.0', port=5000) app.run() # 注意:變量app對應uwsgi配置文件uwsgi.ini中 callable = app
$ $ uwsgi --ini /usr/local/etc/uwsgi.ini [uWSGI] getting INI configuration from /usr/local/etc/uwsgi.ini $ $ ps -ef|grep uwsgi 501 11428 1 0 11:40下午 ?? 0:01.23 uwsgi --ini /usr/local/etc/uwsgi.ini 501 11432 11428 0 11:40下午 ?? 0:00.00 uwsgi --ini /usr/local/etc/uwsgi.ini 501 11433 11428 0 11:40下午 ?? 0:00.00 uwsgi --ini /usr/local/etc/uwsgi.ini 501 11434 11428 0 11:40下午 ?? 0:00.00 uwsgi --ini /usr/local/etc/uwsgi.ini 501 11435 11428 0 11:40下午 ?? 0:00.00 uwsgi --ini /usr/local/etc/uwsgi.ini 501 11440 69240 0 11:40下午 ttys000 0:00.00 grep uwsgi $ $ lsof -i tcp:9000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME uwsgi 11428 suoning 28u IPv4 0x5583e11534d24e73 0t0 TCP localhost:cslistener (LISTEN) $ $ lsof -i tcp:9005 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME uwsgi 11428 suoning 6u IPv4 0x5583e11535699e73 0t0 TCP localhost:9005 (LISTEN) uwsgi 11432 suoning 6u IPv4 0x5583e11535699e73 0t0 TCP localhost:9005 (LISTEN) uwsgi 11433 suoning 6u IPv4 0x5583e11535699e73 0t0 TCP localhost:9005 (LISTEN) uwsgi 11434 suoning 6u IPv4 0x5583e11535699e73 0t0 TCP localhost:9005 (LISTEN) uwsgi 11435 suoning 6u IPv4 0x5583e11535699e73 0t0 TCP localhost:9005 (LISTEN) $
參考:http://webpy.org/cookbook/fastcgi-nginx
$ cat etc/nginx/servers/pan.conf server { listen 80; server_name localhost; error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } location / { fastcgi_param REQUEST_METHOD $request_method; fastcgi_param QUERY_STRING $query_string; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param SCRIPT_FILENAME $fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_pass 127.0.0.1:9005; } location /webstatic/ { expires 7d; add_header Cache-Control public; alias /Users/suoning/probject/python_project/webstatic/trunk/; } } $
from flup.server.fcgi import WSGIServer from pan import app WSGIServer( app, bindAddress=(host, port),
maxThreads=threads ).run()
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'suoning' import sys import argparse from flup.server.fcgi import WSGIServer from lib.daemon import Daemon from pan import app APP_NAME = 'pan_platform' APP_INST_NAME = '20170501' parser = argparse.ArgumentParser(description=u'Run an pan FastCGI server') parser.add_argument('command', type=str, help=u'command [start|stop|restart]', choices=['start', 'stop', 'restart']) parser.add_argument('-p', '--port', type=int, help=u'port of this server', required=True) parser.add_argument('-t', '--threads', type=int, default=50, help=u'max number of threads') parser.add_argument('-host', '--host', default='0.0.0.0', help=u'Listen to the main clause') class panPlatformDaemon(Daemon): def run(self): # 運行服務 try: WSGIServer( app, bindAddress=(args.host, args.port), maxThreads=args.threads, umask=0111 ).run() except: sys.stderr.write('oops') def gen_pidfile(port): return '/var/run/%s_%s_%d.pid' % (APP_NAME, APP_INST_NAME, port) if __name__ == '__main__': args = parser.parse_args() daemon = panPlatformDaemon(gen_pidfile(args.port)) if 'start' == args.command: daemon.start() elif 'stop' == args.command: daemon.stop() elif 'restart' == args.command: daemon.restart() else: print "Unknown command" sys.exit(2) sys.exit(0)
fastcgi雖然是二進制協議,相對於http協議,並不節省資源。二進制協議,只能節省數字的表達,好比 1234567,用字符串表示須要7個Byte,用數字就是4個Byte,而字符串到哪裏都同樣
fastcgi在傳輸數據的時候,爲了兼容cgi協議,還要帶上一堆cgi的環境變量,因此和http協議相比,用fastcgi傳輸數據並不省,反而多一些
fastcgi 惟一的優勢是,它是長鏈接的,用戶併發1000個request,fastcgi可能就用10個 連接轉發給後端的appplication,若是用http協議,那來多少給多少,會向後端appplication 發起1000個請求
http代理轉發方式,在面對超高併發的狀況下會出問題,由於,tcp協議棧當中,port是int16整型 你本地新建一個connect,須要消耗一個端口,最多能到65536。外部併發幾十萬個請求,port池耗幹,你的服務器只能拒絕響應了
WIKI Links: