Python、WSGI应用程序入门学习
1. 第一个WSGI应用程序
用pip安装uwsgi
foobar.py
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"]
2. 将其部署在HTTP端口9090上
启动uWSGI来运行HTTP服务器/路由器,将请求传递到WSGI应用程序:
uwsgi --http :9090 --wsgi-file foobar.py
3. 添加并发和监视
- 第一个调优是添加并发性(默认情况下,uWSGI以单个进程和单个线程开始)
--processes
添加更多进程--threads
添加更多线程(或者您可以同时拥有)
uwsgi --http :9090 --wsgi-file foobar.py --master --processes 4 --threads 2
将生成4个进程(每个进程有2个线程),一个主进程(将在它们死后重新生成您的进程)和HTTP路由器(之前见过)
- 监视,了解发生了什么对于生产部署至关重要。stats子系统允许您将uWSGI的内部统计信息导出为JSON
uwsgi --http :9090 --wsgi-file foobar.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191
首先向您的应用程序发出一些请求(访问localhost:9090),然后远程登录到端口9191(访问localhost:9191)
也可以用pip install uwsgitop
监视实例。
{
"version":"2.0.19.1",
"listen_queue":0,
"listen_queue_errors":0,
"signal_queue":0,
"load":0,
"pid":18811,
"uid":0,
"gid":0,
"cwd":"/opt",
"locks":[
{
"user 0":0
},
{
"signal":0
},
{
"filemon":0
},
{
"timer":0
},
{
"rbtimer":0
},
{
"cron":0
},
{
"rpc":0
},
{
"snmp":0
}
],
"sockets":[
{
"name":"127.0.0.1:33093",
"proto":"uwsgi",
"queue":0,
"max_queue":100,
"shared":0,
"can_offload":0
}
],
"workers":[
{
"id":1,
"pid":18812,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608822825,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":2,
"pid":18813,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608822825,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":3,
"pid":18814,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608822825,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":4,
"pid":18815,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608822825,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
}
]
}
发几次请求之后,其实我是想看看有什么不同
{
"version":"2.0.19.1",
"listen_queue":0,
"listen_queue_errors":0,
"signal_queue":0,
"load":0,
"pid":18811,
"uid":0,
"gid":0,
"cwd":"/opt",
"locks":[
{
"user 0":0
},
{
"signal":0
},
{
"filemon":0
},
{
"timer":0
},
{
"rbtimer":0
},
{
"cron":0
},
{
"rpc":0
},
{
"snmp":0
}
],
"sockets":[
{
"name":"127.0.0.1:33093",
"proto":"uwsgi",
"queue":0,
"max_queue":100,
"shared":0,
"can_offload":0
}
],
"workers":[
{
"id":1,
"pid":18812,
"accepting":1,
"requests":2,
"delta_requests":2,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":893,
"last_spawn":1608822825,
"respawn_count":1,
"tx":110,
"avg_rt":343,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":2,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":2,
"pid":18813,
"accepting":1,
"requests":2,
"delta_requests":2,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":379,
"last_spawn":1608822825,
"respawn_count":1,
"tx":110,
"avg_rt":131,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":2,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":3,
"pid":18814,
"accepting":1,
"requests":2,
"delta_requests":2,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":630,
"last_spawn":1608822825,
"respawn_count":1,
"tx":110,
"avg_rt":231,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":2,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":4,
"pid":18815,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608822825,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
}
]
}
4. 放置完整的Web服务器
uWSGI HTTP路由器可靠且性能高,但最好将应用程序放到web服务器中。
uWSGI本身支持HTTP、FastCGI、SCGI及特定协议uwsgi(这个命名不是很好)。性能最好的协议是uwsgi,nginx和Cherokee支持。
常见的nginx配置:
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:3031;
}
含义是,将使用uwsgi协议的请求传递给绑定到3031端口的服务器
we can spawn uWSGI to natively speak the uwsgi protocol
我们可以生成uWSGI来自然地表达uwsgi协议:
uwsgi --socket 127.0.0.1:3031 --wsgi-file foobar.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191
此时输入ps aux
将能看到uwsgi进程。
{
"version":"2.0.19.1",
"listen_queue":0,
"listen_queue_errors":0,
"signal_queue":0,
"load":0,
"pid":18881,
"uid":0,
"gid":0,
"cwd":"/opt",
"locks":[
{
"user 0":0
},
{
"signal":0
},
{
"filemon":0
},
{
"timer":0
},
{
"rbtimer":0
},
{
"cron":0
},
{
"rpc":0
},
{
"snmp":0
}
],
"sockets":[
{
"name":"127.0.0.1:3031",
"proto":"uwsgi",
"queue":0,
"max_queue":100,
"shared":0,
"can_offload":0
}
],
"workers":[
{
"id":1,
"pid":18882,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608823065,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":2,
"pid":18883,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608823065,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":3,
"pid":18884,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608823065,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":4,
"pid":18885,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608823065,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":0,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
}
]
}
可以看到http路由器不见了,变成了uwsgi协议的。
如果您的代理/网络服务器/路由器使用HTTP,则必须告诉uWSGI本机使用http协议(这与–http本身将生成代理的不同)
uwsgi --http-socket 127.0.0.1:3031 --wsgi-file foobar.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191
5. 部署Django
假设Django项目位于/home/foobar/myproject:
uwsgi --socket 127.0.0.1:3031 --chdir /home/foobar/myproject/ --wsgi-file myproject/wsgi.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191
- `--chdir` 参数可以让我们移至特定目录,然后找到wsgi文件
以上启动django的写法太蠢,需要改写成.ini文件,并用uwsgi yourfile.ini
启动
[uwsgi]
socket = 127.0.0.1:3031
chdir = /home/foobar/myproject/
wsgi-file = myproject/wsgi.py
processes = 4
threads = 2
stats = 127.0.0.1:9191
6. 关于Python线程的注释
如果您在没有线程的情况下启动uWSGI,则将不会启用Python GIL,因此您的应用程序生成的线程将永远不会运行。您可能不喜欢这种选择,但是请记住uWSGI是与语言无关的服务器,因此其大多数选择都是为了使其“不可知”。
但是不用担心,uWSGI开发人员基本上没有做出任何选择都无法更改的选择。
如果要保持Python线程支持而不为应用程序启动多个线程,只需添加--enable-threads
选项(或ini样式)。enable-threads = true
7. 安全性和可用性
始终避免以root用户身份运行uWSGI实例。您可以使用uid
和gid
选项放弃特权:
[uwsgi]
https = :9090,foobar.crt,foobar.key
uid = foo
gid = bar
chdir = path_to_web2py
module = wsgihandler
master = true
processes = 8
我对自己的后端项目进行测试
{
"version":"2.0.19.1",
"listen_queue":0,
"listen_queue_errors":0,
"signal_queue":0,
"load":0,
"pid":19150,
"uid":0,
"gid":0,
"cwd":"/opt/husky-back/husky",
"locks":[
{
"user 0":0
},
{
"signal":0
},
{
"filemon":0
},
{
"timer":0
},
{
"rbtimer":0
},
{
"cron":0
},
{
"rpc":0
},
{
"snmp":0
}
],
"sockets":[
{
"name":":3033",
"proto":"uwsgi",
"queue":0,
"max_queue":100,
"shared":0,
"can_offload":0
}
],
"workers":[
{
"id":1,
"pid":19155,
"accepting":1,
"requests":1,
"delta_requests":1,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":852730,
"last_spawn":1608824045,
"respawn_count":1,
"tx":404,
"avg_rt":426365,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":2,
"requests":1,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":2,
"pid":19157,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608824045,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":2,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":3,
"pid":19158,
"accepting":1,
"requests":0,
"delta_requests":0,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":0,
"last_spawn":1608824045,
"respawn_count":1,
"tx":0,
"avg_rt":0,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":2,
"requests":0,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":0,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
},
{
"id":4,
"pid":19160,
"accepting":1,
"requests":2,
"delta_requests":2,
"exceptions":0,
"harakiri_count":0,
"signals":0,
"signal_queue":0,
"status":"idle",
"rss":0,
"vsz":0,
"running_time":1006378,
"last_spawn":1608824045,
"respawn_count":1,
"tx":85187,
"avg_rt":330300,
"apps":[
{
"id":0,
"modifier1":0,
"mountpoint":"",
"startup_time":2,
"requests":2,
"exceptions":0,
"chdir":""
}
],
"cores":[
{
"id":0,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
},
{
"id":1,
"requests":1,
"static_requests":0,
"routed_requests":0,
"offloaded_requests":0,
"write_errors":0,
"read_errors":0,
"in_request":0,
"vars":[
],
"req_info": {
}
}
]
}
]
}