器→工具, 开源项目, 术→技巧, 研发

Python Web应用的线上部署

钱魏Way · · 2 次浏览

想要将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 来支持这种编程范式。
  • 如果这个应用是 CPU 受限,那么应用程序处理多少并发请求就并不重要。唯一重要的是并行请求的数量。因为 Python’s GIL,线程和“伪线程”并不能以并行模式执行。实现并行性的唯一方法是增加workers的数量到建议的 (2*CPU)+1,理解到最大的并行请求数量其实就是核心数。
  • 如果不确定应用程序的内存占用,使用多线程以及相应的 gthread worker 类 会产生更好的性能,因为应用程序会在每个 worker 上都加载一次,并且在同一个 worker 上运行的每个线程都会共享一些内存,但这需要一些额外的 CPU 消耗。
  • 如果你不知道你自己应该选择什么就从最简单的配置开始,就只是 workers 数量设置为 (2*CPU)+1 并且不用考虑 多线程。从这个点开始,就是所有测试和错误的基准环境。如果瓶颈在内存上,就开始引入多线程。如果瓶颈在 I/O 上,就考虑使用不同的 Python 编程范式。如果瓶颈在 CPU 上,就考虑添加更多内核并且调整 workers 数量。

使用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/ 目录下创建一个指向上一步中创建的 Server Block 文件的符号链接,可以使用以下命令完成此操作:

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) $ nohop 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应用程序服务。Python Web应用程序通常使用WSGI(Web Server Gateway Interface)协议与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 (810 kB)
     |████████████████████████████████| 810 kB 3.1 MB/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应用程序模块和可调用对象。
  • venv:指定虚拟环境目录路径。
  • processes:指定工作进程数,默认为1。
  • threads:指定每个工作进程的线程数,默认为1。
  • master:开启主进程管理模式,可以使用pidfile选项指定PID文件路径。
  • daemonize:以守护进程方式运行uWSGI,可以使用logfile选项指定日志文件路径。

要使用配置文件启动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环境下进行应用程序开发和测试。

参考链接:

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注