想要将 Python Web 应用部署到线上,目前主流的方案是在 Gunicorn/uWSGI 前面再加一层 Nginx,其中 Nginx 的主要作用是:
- 做负载均衡,便于后期服务器的水平扩展,可轻松将应用部署到多台服务器或多个进程中。
- 缓存请求和响应,让 nginx 先保持住连接,然后后端慢慢消化,可以吸收一些瞬时的并发请求。
- 拦截静态请求,nginx 可以直接处理静态文件请求而不用经过 Python 服务器
- 反向代理,可以使后端使用不同版本的 server 成为可能,可以做到灰度发布等,同时也支持 rewrite。
- 安全保护,隔离内网主机,提供 SSL 证书,强制 HTTP 转 HTTPS,做访问控制,限速,限连接数等
- 优化网络请求,比如配置 gzip 来压缩数据,伪静态化并缓存,减少动态请求数量
- 绑定不同的域名到不同的服务。对外统一使用 80 接口。
- 提供日志记录,方便的了解常见访问信息。
Gunicorn 与 uWSGI
Web 框架(应用)致力于如何生成 HTML 代码,而 Web 服务器用于处理和响应 HTTP 请求。Web 框架(应用)和 Web 服务器之间的通信,需要一套双方都遵守的接口协议。WSGI 协议就是用来统一这两者的接口的。Gunicorn 和 uWSGI 均为WSGI 实现。Gunicorn 和 uWSGI 都是 Python Web 应用的部署工具,它们都可以将 Python Web 应用部署到生产服务器上。下面分别介绍一下 Gunicorn 和 uWSGI 的特点:
Gunicorn
Gunicorn 是一个基于 Python 的 WSGI (Web Server Gateway Interface) 服务器。它是一个单进程多线程架构的服务器,使用 worker 进程管理请求并处理应用程序代码。
Gunicorn 支持 HTTP 和 HTTPS 协议,并提供有限的负载平衡和进程管理机制。它使用简单,部署方便,适合部署小型或中型 Python Web 应用。由于其轻量级和易用性,Gunicorn 是 Python 生态系统中最受欢迎的 WSGI 服务器之一。
uWSGI
uWSGI 是一个功能强大的应用服务器,支持多种语言和框架,其中包括 Python、Ruby、Node.js 等。它支持异步调用、协程和缓存机制等高级特性,可以处理更多的并发请求。uWSGI 也支持多种协议,包括 HTTP, FastCGI, SCGI 和 WebSocket。它提供了丰富的插件、扩展和自定义配置选项,可以根据不同需求进行灵活设置。不同于 Gunicorn, uWSGI 是使用 C 写的, 它的 socket fd 创建、worker 进程的启动都是使用 C 语言系统接口来实现的, 在 worker 进程处理循环中, 解析了 http 请求后, 使用 Python 的 C 接口生成 environ 对象, 再把这个对象作为参数塞到暴露出来的 WSGI application 函数中调用。这一切都是在 C 程序中进行, 只是在处理请求的时候交给 Python 虚拟机调用 application。完全使用 C 语言实现的好处是性能会好一些。
对于大型和复杂的 Python Web 应用,uWSGI 是一个很好的选择。由于其高度定制化和灵活性,uWSGI 需要更多的时间和精力来进行设置和管理。
综上所述,Gunicorn 配置更加简单,uWSGI 性能更优。
Nginx + Gunicorn + Supervisor 的部署 Python 应用
Gunicorn 的详细介绍
Gunicorn 是一个 Python 的 WSGI HTTP 服务器。它所在的位置通常是在反向代理(如 Nginx)或者负载均衡(如 AWS ELB)和一个 web 应用(比如 Django 或者 Flask)之间。
Gunicorn 架构
Gunicorn 实现了一个 UNIX 的预分发 web 服务端。
- Gunicorn 启动了被分发到的一个主线程,然后因此产生的子线程就是对应的 worker。
- 主进程的作用是确保 worker 数量与设置中定义的数量相同。因此如果任何一个 worker 挂掉,主线程都可以通过分发它自身而另行启动。
- worker 的角色是处理 HTTP 请求。
- 这个预(预分发)就意味着主线程在处理 HTTP 请求之前就创建了 worker。
- 操作系统的内核就负责处理 worker 进程之间的负载均衡。
为了提高使用 Gunicorn 时的性能,我们必须牢记 3 种并发方式。
第一种并发方式(workers 模式,又名 UNIX 进程模式)
每个 worker 都是一个加载 Python 应用程序的 UNIX 进程。worker 之间没有共享内存。建议的 workers 数量是 (2*CPU)+1。对于一个双核(两个 CPU)机器,5 就是建议的 worker 数量。
gunicorn --workers=5 main:app
第二种并发方式(多线程)
Gunicorn 还允许每个 worker 拥有多个线程。在这种场景下,Python 应用程序每个 worker 都会加载一次,同一个 worker 生成的每个线程共享相同的内存空间。为了在 Gunicorn 中使用多线程。我们使用了 threads 模式。每一次我们使用 threads 模式,worker 的类就会是 gthread:
gunicorn --workers=5 --threads=2 main:app
这条命令等同于:
gunicorn --workers=5 --threads=2 --worker-class=gthread main:app
在我们的例子里面最大的并发请求数就是 worker*线程,也就是 10。在使用 worker 和多线程模式时建议的最大并发数量仍然是 (2*CPU)+1。因此如果我们使用四核(4 个 CPU)机器并且我们想使用 workers 和多线程模式,我们可以使用 3 个 worker 和 3 个线程来得到最大为 9 的并发请求数量。
gunicorn --workers=3 --threads=3 main:app
第三种并发方式(”伪线程”)
有一些 Python 库比如(gevent 和 Asyncio)可以在 Python 中启用多并发。那是基于协程实现的”伪线程”。Gunicrn 允许通过设置对应的 worker 类来使用这些异步 Python 库。这里的设置适用于我们想要在单核机器上运行的 gevent:
gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 main:app
worker-connections 是对于 gevent worker 类的特殊设置。(2*CPU)+1 仍然是建议的 workers 数量。因为我们仅有一核,我们将会使用 3 个 worker。在这种情况下,最大的并发请求数量是 3000。(3 个 worker*1000 个连接/worker)
并发 vs. 并行
并发是指同时执行 2 个或更多任务,这可能意味着其中只有一个正在处理,而其他的处于暂停状态。并行是指两个或多个任务正在同时执行。
在 Python 中,线程和伪线程都是并发的一种方式,但并不是并行的。但是 workers 是一系列基于并发或者并行的方式。
最佳实践
通过调整 Gunicorn 设置,我们希望优化应用程序性能。
- 如果这个应用是 I/O 受限,通常可以通过使用”伪线程”(gevent 或 asyncio)来得到最佳性能。正如我们了解到的,Gunicorn 通过设置合适的 worker 类并将 workers 数量调整到 (2*CPU)+1 来支持这种编程范式。
- 如果不确定应用程序的内存占用,使用多线程以及相应的 gthread worker 类会产生更好的性能,因为应用程序会在每个 worker 上都加载一次,并且在同一个 worker 上运行的每个线程都会共享一些内存,但这需要一些额外的 CPU 消耗。
- 如果你不知道你自己应该选择什么就从最简单的配置开始,就只是 workers 数量设置为 (2*CPU)+1 并且不用考虑多线程。从这个点开始,就是所有测试和错误的基准环境。如果瓶颈在内存上,就开始引入多线程。如果瓶颈在 I/O 上,就考虑使用不同的 Python 编程范式。如果瓶颈在 CPU 上,就考虑添加更多内核并且调整 workers 数量。
如果这个应用是 CPU 受限,那么应用程序处理多少并发请求就并不重要。唯一重要的是并行请求的数量。因为 Python’s GIL,线程和“伪线程”并不能以并行模式执行。实现并行性的唯一方法是增加 workers 的数量到建议的 (2*CPU)+1,理解到最大的并行请求数量其实就是核心数。
使用 Gunicorn 部署 Flask
使用 Gunicorn 部署 Flask 很简单,以下是基本的步骤:
cd hello-app python3 -m venv .venv . .venv/bin/activate pip install gunicorn pip install flask
创建一个最简单的 flask 应用,新建 hello.py,文件内容为:
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>"
Gunicorn 唯一需要的参数告诉它如何加载 Flask 应用程序。语法为 {module_import}:{app_variable}。module_import 是应用程序中模块的导入名称。app_variable 是应用程序的变量。如果您使用的是应用程序工厂模式,它也可以是一个函数调用(带有任何参数)。
最简单的命令如下:
gunicorn hello:app
其中,第一个 hello 是 Python 文件名(不包括 “.py” 后缀),第二个 app 是 Flask 应用程序对象的名称。如果您的 Flask 应用程序对象具有不同的名称,则替换第二个 app 参数即可。执行上述命令后,Gunicorn 将会默认绑定到 127.0.0.1:8000 上,并开始监听请求。此时您就可以通过浏览器访问 http://127.0.0.1:8000 来查看您的应用程序是否能够正常工作。
在使用 Gunicorn 启动 Python 应用程序时,可以使用许多不同的命令行参数来控制 Gunicorn 的行为。以下是一些常用的 Gunicorn 命令行参数:
- -w, –workers。指定 worker 进程数,默认为 1。
- -b, –bind。绑定 IP 地址和端口号,默认为 0.0.1:8000。
- -t, –timeout。Worker 超时时间,默认为 30 秒。
- -k, –worker-class。Worker 类型,包括 sync、eventlet、gevent 等。
- -p, –pid。PID 文件路径。
- -D, –daemon。将 Gunicorn 进程后台运行。
- -c, –config。指定配置文件路径。
- –log-level。设置日志级别,默认为 ‘info’。可选项包括 debug、info、warning、error 和 critical。
- –access-logfile。设置访问日志文件的路径。
- –error-logfile。设置错误日志文件的路径。
- –preload。预加载应用程序代码,提高启动速度。
- –chdir。改变工作目录,即指定应用程序所在的目录。
- –user。指定应用程序运行的用户。
- –group。指定应用程序运行的用户组。
- –capture-output。捕获输出并发送到标准错误流中。
以上是部分常用的 Gunicorn 命令行参数,还有其他更多的参数可以在Gunicorn 官方文档 中查看。
值得一提的是,除了在命令行中指定 wsgi 程序外,还可以使用 Gunicorn 的配置文件来进行更多的设置和自定义。例如,可以通过配置文件指定绑定 IP 地址、端口号、进程数和 worker 类型等参数。
# file gunicorn.conf.py # coding=utf-8 # Reference: https://github.com/benoitc/gunicorn/blob/master/examples/example_config.py import os import multiprocessing _ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) _VAR = os.path.join(_ROOT, 'var') _ETC = os.path.join(_ROOT, 'etc') loglevel = 'info' # errorlog = os.path.join(_VAR, 'log/api-error.log') # accesslog = os.path.join(_VAR, 'log/api-access.log') errorlog = "-" accesslog = "-" # bind = 'unix:%s' % os.path.join(_VAR, 'run/gunicorn.sock') bind = '0.0.0.0:5000' # workers = 3 workers = multiprocessing.cpu_count() * 2 + 1 timeout = 3 * 60 # 3 minutes keepalive = 24 * 60 * 60 # 1 day capture_output = True
使用配置文件启动 Gunicorn,其中 -c 指定配置文件:
gunicorn -c gunicorn.conf.py hello:app
使用 Nginx 配置反向代理
在使用 Gunicorn 部署 Flask 应用程序之后,通常需要使用 Nginx 配置反向代理,将请求转发到 Gunicorn。
以下是配置 Nginx 的步骤:
创建一个新的 Nginx Server Block 文件
在 /etc/nginx/sites-available/ 目录下创建一个新的 Server Block 文件。例如,假设您的域名为 yourdomain.com,则可以使用以下命令创建文件:
sudo nano /etc/nginx/sites-available/yourdomain.com
然后,添加以下内容:
server { listen 80; server_name yourdomain.com; location / { proxy_pass http://localhost:8880; # 将请求转发到 Gunicorn include proxy_params; proxy_redirect off; } location /static { alias /path/to/static/files; # 设置静态文件目录 } }
其中 proxy_pass 指定将请求转发到 Gunicorn 所监听的地址和端口号。proxy_params 包含一些常见的代理参数,proxy_redirect 参数设置重定向行为。location /static 块指定了静态文件所在的目录。
创建软链接在/etc/nginx/sites-enabled/目录下创建一个指向上一步中创建的ServerBlock文件的符号链接,可以使用以下命令完成此操作:
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
测试并重启Nginx
sudo nginx -t sudo systemctl restart nginx
至此,Nginx将会把收到的所有访问http://yourdomain.com的请求都转发给Gunicorn,由Gunicorn处理这些请求并返回响应,然后再返回给Nginx。
使用supervisor守护进程
到目前为止,在配置完Nginx和运行了Gunicorn后,应该是可以通过你的公网ip或者域名访问到你的网站了。但gunicorn是直接通过命令行运行,并不能够在后台运行,也是当我们关闭了X-shell(或者你使用的是Putty及其他SSH连接的软件),将无法再访问到你的应用。所以我们需要gunicorn在后台运行,也就是所谓的daemon(守护进程)。
nohup
如果你熟悉Linux命令,你应该知道在Linux中后台运行可以通过nohup命令,例如我们要让gunicorn在后台运行,我们只需要运行nohup命令:
(venv)$ nohup gunicorn -c gunicorn.conf.py hello:app &
运行后你可以通过ps -e | grep gunicorn指令来查看到当前gunicorn的运行状态。
这样你就可以关闭连接服务器的终端,还能通过你的浏览器访问到你的Flask应用了!
supervisor
但是nohup运行的后台程序并不能够可靠的在后台运行,我们最好让我们的后台程序能够监控进程状态,还能在意外结束时自动重启,这就可以使用一个使用Python开发的进程管理程序supervisor。
首先我们通过apt来安装supervisor:
sudo apt-get install supervisor
使用service命令管理Supervisor服务:
$ sudo service supervisord start #启动Supervisor服务 $ sudo service supervisord stop #停止Supervisor服务 $ sudo service supervisord restart #重启Supervisor服务 $ sudo service supervisord status #查看Supervisor服务状态
使用systemctl命令管理Supervisor服务:
$ sudo systemctl start supervisord #启动Supervisor服务 $ sudo systemctl stop supervisord #停止Supervisor服务 $ sudo systemctl restart supervisord #重启Supervisor服务 $ sudo systemctl status supervisord #查看Supervisor服务状态 $ sudo systemctl enable supervisord #设置Supervisor服务开机自启动 $ sudo systemctl disable supervisord #关闭Supervisor服务开机自启动
安装完成后,我们在/etc/supervisor/conf.d/目录下创建我们控制进程的配置文件,并以.conf结尾,这样将会自动应用到主配置文件当中,创建后添加如下的配置内容:
[program:hello] command=/home/qw/flasktest/.venv/bin/gunicorn -c /home/qw/flasktest/gunicorn.conf.py hello:app directory=/home/qw/flasktest/ //项目目录 user=root autorestart=true startretires=3
在上面的配置文件中,[program:hello]设置了进程名,这与之后操作进程的状态名称有关,为hello;command为进程运行的命令,必须使用绝对路径,并且使用虚拟环境下的gunicorn命令;user指定了运行进程的用户,这里设置为root
保存配置文件之后,我们需要通过命令来更新配置文件:
sudo supervisorctl update
命令行将显示:hello: added process group,然后我们来启动这个demo进程:
sudo supervisorctl start hello
当然你也直接在命令行输入sudo supervisorctl status查看到当前的进程状态。
以下是一些常用的supervisorctl命令:
supervisorctl status:列出所有进程的状态。 supervisorctl start <processname>:启动一个进程。 supervisorctl stop <processname>:停止一个进程。 supervisorctl restart <processname>:重启一个进程。 supervisorctl reread:重新加载配置文件。 supervisorctl update:根据新配置重启所有进程。
Nginx+uWSGI+Supervisor部署Flask
uWSGI是一种Web服务器,它实现了WSGI协议和uwsgi协议,并提供了各种Web应用程序服务。PythonWeb应用程序通常使用WSGI(WebServerGatewayInterface)协议与Web服务器进行交互,而uWSGI就是实现WSGI的一种Web服务器。
以下是uWSGI的一些特性:
- 高性能:uWSGI的核心采用C编写,高效稳定。另外,它采用多进程和协程技术,可以充分利用机器的CPU资源,让Web应用程序响应更加快速。
- 多语言支持:uWSGI不仅支持Python,还支持PHP、Ruby、Perl等多种编程语言。
- 可扩展性:uWSGI具有强大的插件系统,可以添加各种功能模块,如缓存、负载均衡、日志处理等。
- 稳定性:uWSGI经过多次开发迭代和生产环境测试,已经成为一个非常成熟的Web服务器。
- 灵活性:uWSGI支持多种运行模式,如单进程、多进程、协程等模式,可以根据不同的应用场景进行选择。
- 安全性:uWSGI支持HTTPS和SSL/TLS等安全协议,可以确保Web应用程序的数据传输安全。
- 易于部署:uWSGI可以与多种Web服务器集成,如Apache、Nginx等,同时还提供了简洁易用的命令行工具,使得Web应用程序的部署变得更加简单方便。
要使用Nginx+uWSGI+Supervisor部署Flask应用程序,您需要进行以下步骤:
创建虚拟环境并安装uwsgi
cd hello-app python3 -m venv .venv . .venv/bin/activate pip install uwsgi
执行上述代码时,有可能报如下错误:
(.venv) qw@ROG-Strix-6-Plus:~/hello-app$ pip install uwsgi Looking in indexes: https://mirrors.aliyun.com/pypi/simple/ /usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/connectionpool.py:1004: InsecureRequestWarning: Unverified HTTPS request is being made to host 'mirrors.aliyun.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings Collecting uwsgi /usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/connectionpool.py:1004: InsecureRequestWarning: Unverified HTTPS request is being made to host 'mirrors.aliyun.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings Downloading https://mirrors.aliyun.com/pypi/packages/79/73/b5def500729e134d1cb8dfc334e27fa2e9cfd4e639c1f60c6532d40edaed/uwsgi-2.0.23.tar.gz (810kB) |████████████████████████████████| 810kB 3.1MB/s Building wheels for collected packages: uwsgi Building wheel for uwsgi (setup.py) ... error ERROR: Command errored out with exit status 1: command: /home/qw/hello-app/.venv/bin/python3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-61x9h3df/uwsgi/setup.py'"'"'; __file__='"'"'/tmp/pip-install-61x9h3df/uwsgi/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-nlb1i2vl cwd: /tmp/pip-install-61x9h3df/uwsgi/ Complete output (8 lines): /usr/lib/python3.8/distutils/dist.py:274: UserWarning: Unknown distribution option: 'descriptions' warnings.warn(msg) usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] or: setup.py --help [cmd1 cmd2 ...] or: setup.py --help-commands or: setup.py cmd --help error: invalid command 'bdist_wheel' ---------------------------------------- ERROR: Failed building wheel for uwsgi Running setup.py clean for uwsgi Failed to build uwsgi Installing collected packages: uwsgi Running setup.py install for uwsgi ... done Successfully installed uwsgi-2.0.23 (.venv) qw@ROG-Strix-6-Plus:~/hello-app$
解决方案:
sudo apt-get update sudo apt-get install build-essential python3-dev libssl-dev python3-pip python3-venv python3-wheel -y sudo apt-get install gcc libpq-dev -y
重新安装:
pip install wheel pip install cython pip install uwsgi
通过以上步骤,应该能够成功解决”Could not build wheels for uwsgi”的问题并正常安装uwsgi。
如果实在安装不上,可以尝试使用pip install pyuwsgi进行安装。
使用uwsgi部署Flask程序
如上,创建hello.py,执行如下命令启动服务:
uwsgi –http 127.0.0.1:8000 –master -p 4 -w hello:app
以下是uwsgi命令行参数的一些常用选项和说明:
- –http:开启HTTP协议支持,需要指定IP和端口号,如–http 0.0.0.0:8000
- –socket:开启Socket协议支持,需要指定Socket文件路径,如–socket /tmp/uwsgi.sock
- –plugin:指定uWSGI插件,如–plugin python启用Python插件
- –processes:指定工作进程数,默认为1
- –threads:指定每个工作进程的线程数,默认为1
- –master:开启主进程管理模式,可以使用–pidfile选项指定PID文件路径
- –daemonize:以守护进程方式运行uWSGI,可以使用–logfile选项指定日志文件路径
- –virtualenv:指定虚拟环境目录路径,如–virtualenv /path/to/venv
- –module:指定WSGI应用程序模块和可调用对象,如–module myapp.wsgi:application
更多uwsgi命令行参数的详细选项和说明,请参考uWSGI官方文档。
uWSGI可以使用INI格式的配置文件来部署应用程序。以下是一个简单的uWSGI配置文件示例:
[uwsgi] # 启用HTTP协议支持 http = 0.0.0.0:8000 # 指定WSGI应用程序模块和可调用对象 module = myapp.wsgi:application # 指定虚拟环境目录路径 venv = /path/to/venv # 指定工作进程数和线程数 processes = 4 threads = 2 # 开启主进程管理模式,指定PID文件路径 master = true pidfile = /var/run/uwsgi.pid # 以守护进程方式运行uWSGI,指定日志文件路径 daemonize = /var/log/uwsgi.log
在配置文件中,[uwsgi]是标识符,代表uWSGI配置部分。下面是一些常用选项的说明:
- http:开启HTTP协议支持,需要指定IP和端口号。
- module:指定WSGI应用程序模块和可调用对象。
- processes:指定工作进程数,默认为1。
- threads:指定每个工作进程的线程数,默认为1。
- master:开启主进程管理模式,可以使用 pidfile 选项指定 PID 文件路径。
- daemonize:以守护进程方式运行 uWSGI,可以使用 logfile 选项指定日志文件路径。
venv:指定虚拟环境目录路径。
要使用配置文件启动 uWSGI,请使用以下命令:
uwsgi --ini /path/to/uwsgi.ini
其中,/path/to/uwsgi.ini 是你的配置文件路径。更多关于 uWSGI 配置文件的选项和说明,请参考 uWSGI 官方文档。
配置 Nginx 和 Supervisor 和上面的 Gunicorn 类似,这里不再详述。
使用 Waitress 部署 Flask
Waitress是一个纯 Python 的 WSGI 服务器,可用于部署 Web 应用程序。它基于 Tornado 和 Twisted 框架,并提供了一些高级特性,例如优雅的关闭、线程池、多进程支持等。下面介绍一些 Waitress 的特点:
- 纯 Python 实现。Waitress 是一个纯 Python 实现的 WSGI 服务器,不依赖任何第三方 C 库,因此可以在 Windows 和 Unix 平台上运行。
- 高性能。虽然 Waitress 是一个纯 Python 实现的 WSGI 服务器,但它的性能表现非常优秀。相比于其他纯 Python 实现的 WSGI 服务器,如 Bjoern 和 Gunicorn,Waitress 的性能更加稳定?
- 多进程支持。Waitress 支持多进程模式,可以通过 –processes 选项指定进程数。每个进程都有自己的线程池,并且每个请求都会被分配到不同的进程中处理,以提高并发能力。
- 线程池。Waitress 使用了线程池来管理请求处理线程。线程池大小可以通过 –threads 选项指定。这种设计可以避免为每个请求创建新的线程,从而降低了系统开销。
- 优雅的关闭。Waitress 提供了优雅的关闭方式,可以在接收到关闭信号时等待所有处理中的请求完成后再关闭服务器。
- 支持 WebSocket。Waitress 支持 WebSocket 协议,可以用于实现实时通信功能。
- 轻量级。Waitress 是一个轻量级的 WSGI 服务器,代码库很小且易于维护。
Waitress 是一个纯 Python 实现的 WSGI 服务器,尽管它有一些优点,但也存在一些缺点和局限性。
- 并发处理能力受限。由于 Waitress 使用的是同步 I/O 编程模型,因此在面对高并发请求时,并发处理能力受限。在大流量情况下,会出现大量的线程创建,从而导致系统开销变大。
- 不支持异步 I/O。相比于基于 asyncio 的 ASGI 服务器,如 Hypercorn 和 Uvicorn,Waitress 在异步 I/O 方面的性能较弱。如果应用程序需要充分利用 CPU 资源,在处理异步请求时提供高性能,则可能需要选择其他 ASGI 服务器。
- 无法自动重载代码。相比于 Gunicorn 和 Uvicorn 等 ASGI 服务器,Waitress 不支持自动重载功能。每次修改代码后都需要手动重启服务器,这会增加开发和生产环境的操作负担。
- 依赖较多。虽然 Waitress 是一个纯 Python 实现的 WSGI 服务器,但仍需要依赖其他一些库,如 interface、setuptools 等。这增加了安装和部署的难度。
- 兼容性不完善。Waitress 在 Windows 平台上的兼容性不太好,某些情况下可能无法正常工作。此外,它也不支持 Python 2.x 版本。
Waitress 和 Gunicorn 都是 Python 的 WSGI 服务器,常用于部署 Web 应用程序。它们都提供了高级特性,例如多进程支持、线程池等。接下来对它们进行对比分析:
- 性能。在性能方面,Gunicorn 比 Waitress 稍微快一些。这是因为 Gunicorn 使用了基于 C 扩展的工作线程池,而 Waitress 纯粹是一个基于 Python 的服务器。
- 多进程支持。两者都支持多进程模式,可以通过选项指定进程数和线程数。不同之处在于,Gunicorn 采用的是预先创建子进程的方式,每个子进程独立处理连接;而 Waitress 则是按需创建新的进程,每个请求都会被分配到不同的进程中处理。
- 并发能力。由于 Waitress 为每个请求都创建新的进程,因此能够更好地利用 CPU 资源,从而提高并发能力。但是,在大流量负载下,会出现大量的进程创建和销毁,导致系统开销较大。
- 部署和配置。相比之下,Waitress 比 Gunicorn 更加易于部署和配置。Waitress 只需要安装相关依赖即可,而 Gunicorn 则需要安装 gunicorn 和 gevent 两个库,并且需要手动调整工作线程池大小。
- WebSocket 支持。Waitress 和 Gunicorn 都支持 WebSocket 协议,但是 Waitress 使用 websocket-client-legacy 库来实现,而 Gunicorn 则使用 WebSocket 标准 API。
- 兼容性。Waitress 的兼容性更好,可以在 Python 2 和 Python 3 环境中运行,而 Gunicorn 只能在 Python 2 或 Python 3 中选择其一运行。
总之,Waitress 和 Gunicorn 各有优缺点,在具体场景中需根据应用程序的特点来选择适合自己的服务器。如果希望轻量级、易于部署和配置,可以选择 Waitress;如果需要更高的性能和更好的并发能力,可以选择 Gunicorn。
安装:
cd hello-app python -m venv .venv . .venv/bin/activate pip install . # install your application pip install waitress
部署:
waitress-serve --host 127.0.0.1 hello:app
使用 Meinheld 部署 Flask
Meinheld 是一个快速、高性能的 Python WSGI 服务器,它使用基于协程和非阻塞式 I/O 的异步框架。以下是 Meinheld 的一些特点:
- 快速、高性能。Meinheld 是一个快速、高性能的 WSGI 服务器,具有出色的响应速度和请求处理能力,可以在高负载下保持稳定。
- 基于协程和非阻塞式 I/O。Meinheld 采用了基于协程和非阻塞式 I/O 的异步框架,能够充分利用 CPU 资源,在处理请求时提供高性能。相比于同步 I/O 编程模型,Meinheld 具有更好的性能和可伸缩性。
- 多进程支持。Meinheld 支持多进程模式,可以通过 -w 选项指定进程数。每个进程都有自己的监听套接字,以实现请求负载均衡。
- 轻量级。Meinheld 代码库很小,运行内存占用较低,易于维护和部署。
- 支持 WebSocket。Meinheld 支持 WebSocket 协议,可以用于实现实时通信功能。
- 兼容性良好。Meinheld 兼容性良好,可以与其他流行的 Python Web 框架一起使用,例如 Django、Flask 等。
- 开源的社区支持。由于 Meinheld 是一个开源项目,因此开发者可以从社区中获得广泛的支持和帮助。
在选择 Web 服务器时,需要根据自己的应用程序需求和业务场景进行权衡和取舍。以下是 Meinheld 相比其他流行 Web 服务器的一些优缺点。
- 相比于 Gunicorn。Meinheld 和 Gunicorn 都是 Python WSGI 服务器,但它们的实现方式不同。Meinheld 采用异步 I/O 编程模型,可以充分利用 CPU 资源,在处理请求时提供高性能。而 Gunicorn 采用多进程模型,可以通过预先创建子进程来处理请求,从而提高并发能力。
- 相比于 uWSGI。Meinheld 和 uWSGI 都是高性能的 Python Web 服务器,但它们的设计目标略有不同。uWSGI 支持多种应用程序容器、语言和协议,具有更加广泛的适用范围;而 Meinheld 专注于提供高性能的 WSGI 服务,并且采用基于协程和非阻塞式 I/O 的异步框架,具有更好的性能和可伸缩性。
相比于Tornado。Meinheld和Tornado都是Python的高性能Web服务器,但它们采用不同的实现方式。Tornado采用异步I/O编程模型,使用了事件驱动的非阻塞式I/O,以保证在高负载下的稳定性和吞吐量;而Meinheld则使用基于协程的异步框架,以提供更好的性能和可伸缩性。
总之,选择Meinheld还是其他Web服务器需要根据具体应用程序的特点和需求,综合考虑它们的优缺点,选择最适合自己应用程序的Web服务器。如果应用程序需要高性能和可伸缩性,可以考虑使用Meinheld;如果需要更广泛的适用范围和更丰富的功能,可以考虑使用其他Web服务器。
使用Meinheld部署Flask可以提高应用程序的性能和并发能力。以下是具体步骤:
安装Meinheld和Flask
首先需要安装Meinheld和Flask库。可以通过pip命令进行安装:
pip install meinheld flask编写Flask应用程序
接下来编写一个简单的Flask应用程序,作为示例代码:
from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return 'Hello, World!' if __name__ == '__main__': app.run()
使用Meinheld启动应用程序
最后,可以使用Meinheld启动Flask应用程序。可以在代码中添加以下几行代码:
from meinheld import server if __name__ == '__main__': server.listen(('0.0.0.0', 5000)) server.run(app)
在这个示例中,我们使用Meinheld启动了Flask应用程序。server.listen()指定服务器监听的地址和端口号,server.run()指定要运行的Flask应用程序对象。这样,就可以使用Meinheld启动Flask应用程序了。
总之,使用Meinheld部署Flask应用程序可以提高应用程序的性能和并发能力。只需要在代码中添加几行简单的代码,即可使用Meinheld启动Flask应用程序。
Hypercorn与Uvicorn
Hypercorn
Hypercorn是一个基于asyncio的Python ASGI服务器,用于部署ASGI应用程序。它是一个轻量级、高性能的服务器,可以实现高并发和低延迟的请求处理。以下是一些Hypercorn的特点:
- 基于asyncio。Hypercorn使用asyncio库进行异步I/O操作,可以充分利用CPU资源,在处理异步请求时提供高性能。
- ASGI支持。Hypercorn支持ASGI协议,可以处理符合ASGI规范的Web应用程序,并且可以与Django、FastAPI等Web框架无缝集成。
- 高并发。Hypercorn采用了基于协程的异步I/O模型,可以同时处理大量的并发连接请求,具有出色的并发性能。
- 低延迟。Hypercorn支持HTTP/2协议和WebSocket协议,可以在多路复用的机制下,快速地响应客户端请求,降低请求延迟。
- 轻量级。Hypercorn代码库很小,易于维护和部署,同时也比较容易定制和扩展。
- 支持SSL/TLS。Hypercorn支持SSL/TLS加密连接,可以通过配置文件指定证书和私钥文件路径。
- 自动重载。Hypercorn支持自动重载功能,可以在代码发生变化时,自动重新加载代码并启动新的服务器进程。
Hypercorn是一个功能齐全、性能优良的Python ASGI服务器,适合用于部署中小规模的Web应用程序。但它也有一些缺点:
- 较新的项目。Hypercorn是一个比较新的项目,尚未被广泛使用和测试。虽然Hypercorn已经取得了很好的进展,但是在可靠性方面仍有待考验。
- 缺乏文档。Hypercorn文档相对而言较少,还有一些关键细节没有完全阐明。这可能会使初学者在使用Hypercorn时感到困惑。
- 开发人员数量。Hypercorn是由少数几个开发人员组成的开源项目,因此相对于其他更大型的Web服务器项目来说,Hypercorn的代码质量和可维护性可能还需要提升。
- 不支持同步I/O。Hypercorn只支持异步I/O编程模型,如果应用程序采用了同步I/O编程模型,则需要重构代码以适应Hypercorn。这可能会带来额外的工作量和复杂度。
Uvicorn
Uvicorn是基于asyncio和Pydantic的Python ASGI服务器,用于部署ASGI应用程序。它具有高性能、低延迟、易于部署和维护等优点,可以在生产环境中广泛使用。以下是一些Uvicorn的特点:
- 基于asyncio。Uvicorn采用了基于asyncio的异步I/O模型,能够充分利用CPU资源,在处理异步请求时提供高性能。
- ASGI支持。Uvicorn完全支持ASGI协议,可以处理符合ASGI规范的Web应用程序,并且可以与Starlette、FastAPI等Web框架无缝集成。
- 高并发。Uvicorn采用了基于协程的异步I/O模型,可以同时处理大量的并发连接请求,具有出色的并发性能。
- 低延迟。Uvicorn支持HTTP/2协议和WebSocket协议,可以在多路复用的机制下,快速地响应客户端请求,降低请求延迟。
- 轻量级。Uvicorn代码库很小,易于维护和部署,同时也比较容易定制和扩展。
- 支持SSL/TLS。Uvicorn支持SSL/TLS加密连接,可以通过配置文件指定证书和私钥文件路径。
- 自动重载。Uvicorn支持自动重载功能,可以在代码发生变化时,自动重新加载代码并启动新的服务器进程。
Uvicorn是一个高性能、低延迟、易于部署和维护的Python ASGI服务器,适合用于部署中小规模的Web应用程序。但它也有一些缺点。
- 不支持同步I/O。Uvicorn只支持异步I/O编程模型,如果应用程序采用了同步I/O编程模型,则需要重构代码以适应Uvicorn。这可能会带来额外的工作量和复杂度。
- 依赖较多。Uvicorn的运行需要依赖asyncio和Pydantic等库,相对于其他Web服务器来说,它有更多的依赖项。这可能增加了安装和部署的难度。
- 对WSGI支持不完全。虽然Uvicorn提供了对ASGI协议的完全支持,但其对WSGI协议的支持并不完全。要在Uvicorn中运行WSGI应用程序,还需要使用额外的中间件或插件。
- 在Windows系统上支持存在问题。Uvicorn在Windows系统上支持存在问题,并且在一些情况下可能无法正常运行。这可能会影响开发者在Windows环境下进行应用程序开发和测试。
Django+Daphne
Daphne是一个用于运行Django和其他ASGI(Asynchronous Server Gateway Interface)应用程序的高性能HTTP和WebSocket服务器。它是Django Channels项目的一部分,旨在提供一个高效、可靠的服务器,支持现代Web应用程序所需的异步功能。
主要特性
- 异步支持:Daphne是一个异步服务器,支持ASGI协议,可以处理大量的并发连接,特别适合处理WebSocket连接和其他长轮询请求。
- 高性能:采用异步I/O技术,能够在单个进程中处理数千个并发连接,显著提高了服务器的性能和响应能力。
- 兼容性强:支持Django和其他ASGI兼容的应用程序,可以轻松集成到现有的Django项目中。
- WebSocket支持:内置对WebSocket协议的支持,使得开发实时应用变得更加简单。
- HTTP/2支持:支持HTTP/2协议,提高了数据传输的效率和性能。
- 配置灵活:提供多种配置选项,可以根据具体需求进行调整,如端口、工作进程数、日志级别等。
安装要使用Daphne,首先需要安装channels和daphne。可以通过pip安装这些包:
pip install channels daphne
基本用法
配置Django项目
首先,确保你的Django项目已经配置为使用ASGI。在settings.py中,添加channels到INSTALLED_APPS:
INSTALLED_APPS = [ #其他应用 'channels', ]
然后,在项目的根目录下创建一个asgi.py文件,内容如下:
import os from django.core.asgi import get_asgi_application from channels.routing import ProtocolTypeRouter, URLRouter from channels.auth import AuthMiddlewareStack import your_app.routing #替换为你的应用名 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": AuthMiddlewareStack( URLRouter( your_app.routing.websocket_urlpatterns #替换为你的WebSocket路由 ) ), })
启动Daphne服务器
在项目的根目录下,使用以下命令启动Daphne服务器:
daphne -p 8000 your_project.asgi:application
- -p 8000指定服务器监听的端口。
- asgi:application指定ASGI应用程序的入口点。
高级用法
多进程模式:可以通过 -p 参数指定端口,通过 -b 参数指定绑定地址,通过 -w 参数指定工作进程数。
daphne -p 8000 -b 0.0.0.0 -w 4 your_project.asgi:application
日志配置:可以通过 –access-log 和 –log-level 参数配置访问日志和日志级别。
daphne --access-log -- --log-level info -p 8000 your_project.asgi:application
SSL/TLS支持:可以通过 –ssl-keyfile 和 –ssl-certfile 参数启用SSL/TLS支持。
daphne --ssl-keyfile key.pem --ssl-certfile cert.pem -p 8000 your_project.asgi:application
参考链接: