0x00 引言
我觉得,使用工具时,了解其中的原理才能用的更舒心,更加无所顾忌。 对于程序员来说更是如此。
抱着这样的心态,针对 Python 处理 HTTP 请求的工作过程做了实验,并做了一些总结归纳。
0x01 uwsgi 与 uWSGI 与 WSGI
WSGI:编程接口协议,专为 Python 设计,用于 Web 开发 (类比 COM 编程接口协议)
WSGI 协议预先约定了一些 callee (Python) 必须实现的 callable (Function),以使 caller 能正确调用 callee,来处理 HTTP 请求。
uWSGI:一个 WSGI 协议 caller 方的具体实现,使用 C 语言编写 (类比 COM 组件的调用方)
uWSGI 是 caller 方,我们写的 Python 程序自然就是 callee 方了。
uWSGI 可以通过 uwsgi 协议与 HTTP Server 进行通信,只作为调用 Python 处理请求的桥梁。
uWSGI 当然也提供了一个 HTTP 服务器的功能,直接处理 HTTP 请求。
uwsgi:通信协议,描述了 HTTP Server 与 WSGI caller 如何通信(类比 CGI,FastCGI)
具体通信协议的差别在这里不再赘述,但值得一提的是:
uwsgi 继承了 FastCGI 的并发优点,但不是通过多进程,而是通过消息分片的方式,在同一 Socket 上并发传输多个请求,这使得资源被更有效的利用了。
于是一个常规的处理过程是这样的:
Client ==HTTP==> Nginx ==uwsgi==> uWSGI ==WSGI==> Python 程序
0x02 所以
经过实验发现,uWSGI 通过将支持 WSGI 的 Python 程序载入到其每个 Worker Process 中,各作为单独的实例存在于内存中。在接受Web请求时,分配给各 Worker Process 进行处理。
0x03 相关实验代码
nginx.conf
location / {
include uwsgi_params;
uwsgi_pass uwsgi://127.0.0.1:5001;
}
server.py
#!/usr/bin/env python
# coding: utf-8
from flask import Flask
from count_module import Count
app = Flask(__name__)
app.debug = True
count = 0
@app.route("/")
def index():
Count.current_count = Count.current_count + 1
return "count:" + str(Count.current_count)
count_module.py
class Count(object):
current_count = 0
最后安装 Python 环境,启动 uWSGI
virtualenv --always-copy .env
source .env/bin/activate
pip install flask uwsgi
uwsgi --uwsgi 127.0.0.1:5001 --master --module server --callable app --processes 4 --home .env
可以观察到在刷新页面的时候,count 值虽然递增,但却是随机显示了四个 Worker Process 的实例中包含的 count 值。
0x04 参考
https://www.zhihu.com/question/46945479 https://www.rapospectre.com/blog/31