1. Why Flask+Gunicorn+Nginx

Flask+Gunicorn+Nginx是最常用的Flask部署方案,大家深究过为何用这样的搭配么?

1.1 Why?

Flask 是一个web框架,而非web server,直接用Flask拉起的web服务仅限于开发环境使用,生产环境不够稳定,也无法承受大量请求的并发,在生茶环境下需要使用服务器软件来处理各种请求,如Gunicorn、 Nginx或Apache,而Gunicorn+Nginx的搭配,好处多多,一方面基于Nginx转发Gunicorn服务,在生产环境下能补充Gunicorn服务在某些情况下的不足,另一方面,如果做一个Web网站,除了服务外,还有很多静态文件需要被托管,这是Nginx的强项,也是Gunicorn不适合做的事情。所以,基于Flask开发的网站,部署时用Gunicorn和Nginx,是一个很好的选择。

1.2 Anything More?

1、为什么需要Nginx转发Gunicorn服务?

Nginx功能强大,使用Nginx有诸多好处,但用Nginx转发Gunicorn服务,重点是解决“慢客户端行为”给服务器带来的性能降低问题;另外,在互联网上部署HTTP服务时,还要考虑的“快客户端响应”、SSL处理和高并发等问题,而这些问题在Nginx上一并能搞定,所以在Gunicorn服务之上加一层Nginx反向代理,是个一举多得的部署方案。

2、为什么会有“慢客户端行为”带来的服务性能降低问题?

服务器和客户端的通信,我们简略的分为三个部分:request,request handling,和response,即客户端向服务器发起请求,服务器端响应并处理请求,和将请求结果返回客户端,这三个过程。

通常,request handling这部分即服务端的计算,拼的是服务器的性能,处理是比较高效和稳定的,而request和response部分,影响因素比较多,如果这三个过程放到同一个进程中同步处理,如果request和response部分耗时比较多,会使计算资源被占据并无法及时释放,导致计算资源无法有效利用,降低服务器的处理能力。

上述“慢客户端行为”,指的就是request(或response)部分耗时比较多的情况,Gunicorn恰好会把上面三个过程放到同一个进程中,当出现“慢客户端行为”时,效率很低:

Gunicorn 是一个pre-forking的软件,这类软件对低延迟的通信,如负载均衡或服务间的互相通信,是非常有效的。但pre-forking系统的不足是,每个通信都会独占一个进程,当向服务器发出的请求多于服务器可用的进程时,由于服务器端没有更多进程响应新的请求,其响应效率会降低。

对于Web网站或服务而言,由于request和response延时是不可控的,我们需要在考虑处理高延迟客户端请求的情况。这些请求会占据服务器端的进程。当慢客户端直接与服务通信时,由于慢客户端请求会占据进程,可用于处理新请求的进程就会减少,如果有很多慢客户端请求把所有进程都占据后,新的请求只能等待有进程被释放掉后,得到响应。另外,如果应用希望有更高的并发,服务器与客户端的通信要更高效,异步的通信会比同步的通信更有效。

Nginx这类异步的服务器软件擅长用很少的内存和cpu开销来处理大量的请求。由于他们擅长于同时处理大量客户端请求,所以慢客户端请求对他们影响不大。就Nginx而言,现在一般的服务器硬件条件下,同时处理上万个请求都不在话下。

所以把Nginx挡在pre-forking服务前面处理请求是一种很好的选择。Nginx能够异步、高并发的响应客户端request(慢客户端请求对Nginx影响不大),Nginx一旦接收到的请求后立刻转给Gunicorn服务处理,处理结果再由Nginx以response的形式发回给客户端。这样,整个服务端和客户端的通信,就由原来仅通过Gunicorn的同步通信,变成了基于Nginx和Gunicorn的异步通信,通信效率和并发能力得到大大提升。

对于网站而言,除了要考虑上面介绍的情况,还要考虑各种静态文件的托管问题。静态文件既包括CSS、JavaScript等前端文件,也包括图片、视频和各类文档等,所以静态文件要么可能会比较大,要么会调用比较频繁,静态文件的托管功能,就是要保证各类静态能正常的加载、预览或下载,这其实就是Response耗时长的“慢客户端行为”。用Gunicorn托管静态文件,也会严重影响Gunicorn的响应效率,而这恰恰又是Nginx擅长的工作,所以静态文件的托管也交给Nginx搞定就好。

2. Flask网站如何部署

结合上一节的解释,Flask网站如何部署也很明确了:

  1. 用一个服务器软件(如Gunicorn)把Flask写好的应用拉起来
  2. 用Nginx给上一步拉起的应用做一个反向代理
  3. 网站涉及到的静态文件,用Nginx做文件托管

常见的服务器软件是Gunicorn和uWSGI,由于Gunicorn配置使用简单,效率也不错,Gunicorn拉起Flask网站的配置极为简单,所以通常用Gunicorn来部署Flask网站是最常见的部署方案。(另,Gevin个人还有一个喜欢Gunicorn的原因是,Gunicorn是纯Python写的,直接pip安装即可,而uwsgi还要系统装额外的依赖,这在与docker配合使用时,Gunicorn的简单性尤为突出)

对于静态文件的托管,由于在开发阶段通常会基于Flask框架做静态文件托管的实现,所以当用Gunicorn拉起Flask网站时,网站已经实现了基于Gunicorn的文件托管功能,所以配置Nginx的静态文件托管URL时,可以直接配置成与基于Gunicorn托管一致的文件路径,这样能简化开发和部署的逻辑,而且由于Nginx比Gunicorn更靠外一层,客户端请求静态文件时,Nginx就直接返回Response了,不用担心会请求到Gunicorn中去影响服务器效率。

2.1 Gunicorn

Gunicorn如何部署Flask网站,直接看Flask或Gunicorn官方文件即可,通常只要执行类似下面的一行命令:

/usr/local/bin/gunicorn -w 2 -b :4000 manage:app

2.2 Nginx

用Nginx做反向代理和托管静态文件,也很简单,我这里提供一个可用Demo,更多玩法大家自行查阅Nginx文档吧

server {
listen 80; server_name localhost; access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log; location / {
proxy_pass http://localhost:8000/;
proxy_redirect off; proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /media {
alias /usr/share/nginx/html/media;
} location /static {
alias /usr/share/nginx/html/static;
}
}

其中,做反向代理的配置是:

    location / {
proxy_pass http://localhost:8000/;
proxy_redirect off; proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }

做静态文件托管的配置是:

    location /media  {
alias /usr/share/nginx/html/media;
} location /static {
alias /usr/share/nginx/html/static;
}

我这里对两个文件夹的文件做了托管。

3. 基于Docker的Flask网站部署

Docker具有一次部署,到处运行的好处,把上述传统部署的方法,封装到docker image中,然后配合Docker Compose编排服务,在实践中更方便。

3.1 构建Flask网站的镜像

通常,镜像中包含Flask网站的运行环境,然后把Gunicorn拉起服务作为image的运行命令即可,比如,我的OctBlog的Dockerfile编写如下:

# MAINTAINER        Gevin <flyhigher139@gmail.com>
# DOCKER-VERSION 18.03.0-ce, build 0520e24 FROM python:3.6.5-alpine3.7
LABEL maintainer="flyhigher139@gmail.com" RUN mkdir -p /usr/src/app && \
mkdir -p /var/log/gunicorn WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/requirements.txt RUN pip install --no-cache-dir gunicorn && \
pip install --no-cache-dir -r /usr/src/app/requirements.txt COPY . /usr/src/app ENV PORT 8000
EXPOSE 8000 5000 CMD ["/usr/local/bin/gunicorn", "-w", "2", "-b", ":8000", "manage:app"]

这里,Gevin直接用了最小的Python-alpine镜像作为基础镜像,大大减少了即将构建的Flask应用镜像的体积。对于alpine这种只有几M的极简image而言,不安装其他系统依赖,直接pip install uwsgi就会报错。

3.2 Nginx 相关的配置

Nginx上主要做反向代理和静态文件托管,和上面的配置文件一致,如:

server {
listen 80; server_name localhost; access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log; location / {
proxy_pass http://blog:8000/;
proxy_redirect off; proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /media {
alias /usr/share/nginx/html/media;
} location /static {
alias /usr/share/nginx/html/static;
}
}

这个配置文件和上一章节的唯一区别是,第10行的proxy_pass http://blog:8000/; 这里的反向代理的服务为blog,是下面Docker-compose中配置的OctBlog网站服务。

3.3 用Docker-compose编排服务

OctBlog的Docker-compose编排文件如下:

version: '3'
services:
blog:
# restart: always
image: gevin/octblog:0.4.1
volumes:
- blog-static:/usr/src/app/static
env_file: .env
networks:
- webnet mongo:
# restart: always
image: mongo:3.2
volumes:
- /Users/gevin/projects/data/mongodb:/data/db
networks:
- webnet blog-proxy:
# restart: always
image: nginx:stable-alpine
ports:
- "8080:80"
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf
- blog-static:/usr/share/nginx/html/static:ro
- blog-static:/usr/share/nginx/html/media:ro
networks:
- webnet volumes:
blog-static:
networks:
webnet:

其中,为了让多个服务能互通,创建了自定义的network webnet,为了让文件能在多个服务之间共享,公用了volume blog-static

4. 其他Python web网站的部署

基于上面的内容,举一反三,我们也可以梳理出Python 各类web框架做网站部署时的一般套路:

  1. 用一个Python WSGI HTTP Server来部署代码,如:

  2. 用Nginx做反向代理
  3. 做好静态文件的托管

Flask 应用如何部署的更多相关文章

  1. flask+uwsgi+supervisor部署流程

    背景: 小鱼最近搞了个工程,python用的2.7(用3也可以),后端使用的是flask,服务器用的linux,使用 flask+uwsgi+supervisor部署 ,查阅相关博客.调试.实操,已经 ...

  2. 采用flask+uwsgi+nginx架构将flask应用程序部署在腾讯云

    最近一星期加班为学校做了一个教师发展中心平台,在此总结一下部署经验 环境:Centos7.0  python2.7.5 1.安装nginx 命令行输入指令:sudo yum install nginx ...

  3. Flask + Gunicorn + Nginx 部署

    最近很多朋友都在问我关于 Flask 部署的问题,说实在的我很乐意看到和回答这样的问题,至少证明了越来越多人开始用 Flask 了. 之前我曾发表过一篇在 Ubuntu 上用 uwsgi + ngin ...

  4. 将Flask应用程序部署在nginx,tornado的简单方法

    来自:http://www.xuebuyuan.com/618750.html 在网上搜索了一下部署flask应用的方法,大部分是用wsgi部署在nginx上面,部署了很久,都没有成功,可能是我领悟能 ...

  5. Flask 系列之 部署发布

    说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验目标 通过 Windows 的 WSL,将我们的项目网站部署到 ...

  6. Python3 Flask+nginx+Gunicorn部署(上)

    前言:一般在本地运行flask项目通常是直接python3 文件名.py,然后打开:http://127.0.0.1:5000 查看代码结果 这次主要是记录flask在python3 环境结合ngin ...

  7. centos6.5+python2.7+flask+apache+mod-wsgi部署

    flask部署,使用的是centos6.5,python2.7,版本很重要.基本步骤如下: 一.创建虚拟环境,创建目录把项目拷进去 二.安装mod-wsgi和apache easy_install m ...

  8. flask+apache+mod-wsgi部署遇到的坑

    首先,看到这种方式部署,我也有疑问,为什么不用nginx,gunicorn.接手的项目,就先按照前人思路run起来. 线上使用ubuntu系统,apache2,而给我玩耍的测试机是centos6.5, ...

  9. 使用Flask+uwsgi+Nginx部署Flask正式环境

    环境准备 在开始正式讲解之前,我们将首先进行环境准备. Step1:安装Python,pip以及nginx: sudo apt-get update sudo apt-get install pyth ...

随机推荐

  1. idea启动springboot项目报Error running 'ServiceStarter': Command line is too long. Shorten command line for ServiceStarter or also for Application

    解决办法:在.idea文件夹下面的workspace.xml中的 <component name="PropertiesComponent">标签下面添加: <p ...

  2. java中的strictfp的作用

    自Java2以来,Java语言增加了一个关键字strictfp,虽然这个关键字在大多数场合比较少用,但是还是有必要了解一下. strictfp 的意思是FP-strict,也就是说精确浮点的意思.在J ...

  3. Hive窗口函数案例详解

    语法: 分析函数 over(partition by 列名 order by 列名 rows between 开始位置 and 结束位置) 常用分析函数: 聚合类 avg().sum().max(). ...

  4. BZOJ 2699: 更新 (DP)

    题目 对于一个数列A[1-N],一种寻找最大值的方法是:依次枚举A[2]到A[N],如果A[i]比当前的A[1]值要大,那么就令A[1]=A[i],最后A[1]为所求最大值.假设所有数都在范围[1, ...

  5. HDU-1398-Square Coins(母函数)

    链接: https://vjudge.net/problem/HDU-1398 题意: People in Silverland use square coins. Not only they hav ...

  6. Vue动态创建注册component的实例代码

    https://segmentfault.com/a/1190000015698278

  7. LaTex编译时出错:PK font *** could not be created

    参考https://blog.csdn.net/dancing11/article/details/60978642 在用TeXworks (Miktex) 编译OSA投稿模板时,遇到错误PK fon ...

  8. SIGAI机器学习第十七集 线性模型1

    讲授logistic回归的基本思想,预测算法,训练算法,softmax回归,线性支持向量机,实际应用 大纲: 再论线性模型logistic回归的基本思想预测函数训练目标函数梯度下降法求解另一种版本的对 ...

  9. 51nod 3 * problem

    1640题意:一张无向图在最小化最大边后求最大边权和 Slove:sort 最小生成树倒叙最大生成树 #include <iostream> #include <cstdio> ...

  10. 原生table表格的使用

    近期公司让我修改一些之前的table标签写的页面,感觉对table相关的标签不是太熟悉,于是专门整理一下: 1.如果给td标签设置百分比宽度,比如有10列内容,我们却设置了每个单元格是30%的宽度,会 ...