python-39-flask+nginx+Gunicorn的组合应用

news2024/11/29 2:53:30

flask + nginx + Gunicorn = 王炸

1 flask+nginx+gunicorn+supervisor

1.1 myapp.py

from flask import Flask
app = Flask(__name__)

@app.route("/")
def test_link():
    return "the link is very good"

if __name__=="__main__":
    app.run()

默认是5000端口。
打开虚拟机pip install flask
运行代码python3 myapp.py
访问 curl http://127.0.0.1:5000

1.2 Gunicorn

WSGI (Web Server Gateway Interface) 是 Python 应用程序与 Web 服务器之间的标准接口。Gunicorn 和 uWSGI 是两个常用的 WSGI 服务器。
(1)安装pip install gunicorn。
安装sudo apt install gunicorn。
安装后的路径:/usr/bin/gunicorn。
(2)可以使用Gunicorn来运行Flask应用。 此时Flask应用的入口文件是 myapp.py,可以使用以下命令来运行它:

默认分配给flask应用一个端口8000
gunicorn --workers=2 myapp:app  

也可以使用-b参数显式指定
gunicorn --workers=2 -b 0.0.0.0:5000 myapp:app

在这个命令中,workers=2表示使用2个工作进程,myapp:app表示Flask应用的入口文件是myapp.py,并且Flask应用的实例名是app。

在生产环境中,我们通常会使用进程管理工具(如Supervisor或systemd)来保证Gunicorn服务器的持续运行。

1.3 Supervisor

(1)安装sudo apt install supervisor。
(2)然后需要创建一个配置文件来告诉Supervisor如何运行你的Gunicorn服务器。

[program:myapp]
directory=/home/zb/mydir
command=/usr/bin/gunicorn -w 2 myapp:app
autostart=true
autorestart=true
stderr_logfile=/var/log/myapp.err.log
stdout_logfile=/var/log/myapp.out.log
user=zb

在这个配置中,directory是你的应用程序的目录,command是运行你的Gunicorn服务器的命令,user是运行服务器的用户。
(3)保存并关闭文件,然后使用以下命令来更新Supervisor的配置:

sudo supervisorctl reread
sudo supervisorctl update

此时已经生效了。

(4)最后可以使用以下命令来启动你的应用程序:

sudo supervisorctl start myapp
sudo supervisorctl stop myapp

现在,你的Gunicorn服务器应该会一直运行,即使你的服务器重启。

注意:在生产环境中,可能需要使用Nginx或Apache等Web服务器来代理你的Flask应用。

1.4 Nginx

要在Flask应用程序前使用Nginx作为反向代理,你需要进行以下步骤:
(1)安装sudo apt-get install nginx
(2)配置Nginx
sudo vi /etc/nginx/sites-available/default

server {
    listen 80;
    location / {
        proxy_pass http://localhost:8000;
    }
}

在这个配置中,Nginx会监听80端口,并将所有请求转发到本地的8000端口(你的gunicorn启动的Flask应用)。
(3)启动或重启Nginx

sudo systemctl restart nginx

此时curl http://127.0.0.1:8000/
或者curl http://127.0.0.1/都可以。

2 flask中的日志模块

Python Flask + Gunicorn + Docker 的日志输出设置
flask学习之日志logging

2.1 缺省配置(普通Flask日志设置)

Flask本身使用Python的logging模块来实现日志记录、输出。

Flask中也有自己的日志模块,通过flask的实例(一般叫作app)能够直接调用日志模块,输出或者记录日志。
(1)主程序main.py

import logging
from flask import Flask, jsonify
from flask import current_app
from children import task
app = Flask(__name__)

@app.route('/')
def default_route():
    """Default route"""
    app.logger.debug('this is a DEBUG message')
    app.logger.info('this is an INFO message')
    app.logger.warning('this is a WARNING message')
    app.logger.error('this is an ERROR message')
    app.logger.critical('this is a CRITICAL message')
    task()
    return jsonify('hello world')


@app.route('/current_app')
def default_route_current_app():
    current_app.logger.debug('this is a DEBUG message current app')
    task()
    return jsonify('hello world current app')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000, debug=True)

(2)子程序children.py

from flask import current_app
def task():
    current_app.logger.info("I am children")

有一个问题就是在蓝图中如何使用flask的日志模块呢?还记得flask中的current_app吗,这个current_app返回的就是该蓝图注册所在的flask实例。在flask中的蓝图要使用app(flask的实例)中的一些方法或者属性就需要用到current_app。
在这里插入图片描述

我们是在flask应用实例创建之后在添加的handler,因此,在flask应用实例创建的时候已经使用了缺省配置,添加了一个StreamHandler到app.logger了。

2.2 输出到文件方式一

可以使用 logging 模块的不同输出处理器(Handler)来实现标准输出、文件输出或邮件提醒。例如添加日志文件:

import logging
from flask import Flask, jsonify
from flask import current_app
from children import task
app = Flask(__name__)

@app.route('/')
def default_route():
    """Default route"""
    app.logger.debug('this is a DEBUG message')
    app.logger.info('this is an INFO message')
    app.logger.warning('this is a WARNING message')
    app.logger.error('this is an ERROR message')
    app.logger.critical('this is a CRITICAL message')
    task()
    return jsonify('hello world')


@app.route('/current_app')
def default_route_current_app():
    current_app.logger.debug('this is a DEBUG message current app')
    task()
    return jsonify('hello world current app')

if __name__ == '__main__':
    print(app.debug)  # 默认为False
    app.debug = True
    handler = logging.FileHandler('flask.log')
    app.logger.addHandler(handler)
    app.run(host='0.0.0.0', port=8000)

可以看到在当前目录下生成了flask.log日志文件。

2.3 输出到文件方式二

import logging
from flask import Flask, jsonify
from flask import current_app
from children import task
from flask.logging import default_handler
app = Flask(__name__)

@app.route('/')
def default_route():
    """Default route"""
    app.logger.debug('this is a DEBUG message')
    app.logger.info('this is an INFO message')
    app.logger.warning('this is a WARNING message')
    app.logger.error('this is an ERROR message')
    app.logger.critical('this is a CRITICAL message')
    task()
    return jsonify('hello world')


@app.route('/current_app')
def default_route_current_app():
    current_app.logger.debug('this is a DEBUG message current app')
    task()
    return jsonify('hello world current app')

if __name__ == '__main__':
    # 设置日志的记录等级
    logging.basicConfig(level=logging.DEBUG)
    # app.logger.removeHandler(default_handler)  # 是否移除默认配置
    # 创建日志记录器
    handler = logging.FileHandler('flask.log')
    # 定义handler的输出格式
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    # 为全局的日志工具对象(flask app使用的)添加日志记录器
    logging.getLogger().addHandler(handler)
    # app.logger.addHandler(handler)
    app.run(host='0.0.0.0', port=8000)

有两种使用方式

import logging

from flask import current_app
def task():
    current_app.logger.info("I am children, current app")
    logging.info("I am children, logging")

在这里插入图片描述
在控制台输出时
若用current_app.logger,则标识main1(app的代码所在名称)
若用logging,则标识为root。

至此,Flask 的日志一切都运转良好。然后我们在生产服务器上部署的时候,现在常常会使用 Gunicorn 来运行,这时候的日志输出就有问题了,日志文件没有内容写入。

2.4 按天分割并调整格式

import logging
from flask import Flask, jsonify
from flask import current_app
from logging.handlers import TimedRotatingFileHandler
from children import task
app = Flask(__name__)

@app.route('/')
def default_route():
    """Default route"""
    app.logger.debug('this is a DEBUG message')
    app.logger.info('this is an INFO message')
    app.logger.warning('this is a WARNING message')
    app.logger.error('this is an ERROR message')
    app.logger.critical('this is a CRITICAL message')
    task()
    return jsonify('hello world')


@app.route('/current_app')
def default_route_current_app():
    current_app.logger.debug('this is a DEBUG message current app')
    task()
    return jsonify('hello world current app')

if __name__ == '__main__':
    print(app.debug)  # 默认为False
    app.debug = True
    formatter = logging.Formatter(
        "[%(asctime)s][%(filename)s:%(lineno)d][%(levelname)s][%(thread)d] - %(message)s")

    handler = TimedRotatingFileHandler("flask.log",
                                       when="D",
                                       interval=1,
                                       backupCount=30,
                                       encoding="UTF-8",
                                       delay=False,
                                       utc=False)

    handler.setFormatter(formatter)
    app.logger.addHandler(handler)
    app.run(host='0.0.0.0', port=8000)

3 使用gunicorn部署

Gunicorn有自己的日志记录器,它通过本身的机制控制日志级别。我们只能通过配置Gunicorn的日志设定,来实现我们的需求。同时,需要对上面例子应用的日志处理器设置进行调整。

3.1 方式一(gunicorn指定日志文件名)

import logging
from flask import Flask, jsonify
from flask import current_app
from logging.handlers import TimedRotatingFileHandler
from children import task
app = Flask(__name__)

@app.route('/')
def default_route():
    """Default route"""
    app.logger.debug('this is a DEBUG message')
    app.logger.info('this is an INFO message')
    app.logger.warning('this is a WARNING message')
    app.logger.error('this is an ERROR message')
    app.logger.critical('this is a CRITICAL message')
    task()
    return jsonify('hello world')


@app.route('/current_app')
def default_route_current_app():
    current_app.logger.debug('this is a DEBUG message current app')
    task()
    return jsonify('hello world current app')


# make app to use gunicorn logger handler
if __name__ != '__main__':
    gunicorn_logger = logging.getLogger('gunicorn.error')
    app.logger.handlers = gunicorn_logger.handlers
    app.logger.setLevel(gunicorn_logger.level)


if __name__ == '__main__':
    print(app.debug)  # 默认为False
    app.debug = True
    formatter = logging.Formatter(
        "[%(asctime)s][%(filename)s:%(lineno)d][%(levelname)s][%(thread)d] - %(message)s")

    handler = TimedRotatingFileHandler("flask.log",
                                       when="D",
                                       interval=1,
                                       backupCount=30,
                                       encoding="UTF-8",
                                       delay=False,
                                       utc=False)

    handler.setFormatter(formatter)
    app.logger.addHandler(handler)
    app.run(host='0.0.0.0', port=8000)

启动gunicorn

gunicorn -w 2 -b 0.0.0.0:5000 
--log-level debug 
--log-file /home/zb/mydir/gunicorn.log 
main:app

日志会写到文件gunicorn.log中。

3.2 方式二(自定义日志文件名)

nohup gunicorn -w 2 -b 127.0.0.1:8000 main1:app > /root/gunicorn.log 2>&1 &

为了使用自己设置的日志。
修改 app.py,注意我们添加的 if name != ‘main’ 这部分,就是在 Gunicorn 运行时,让Flask使用全局的日志处理器。

import logging
from flask import Flask, jsonify
from flask import current_app
from children import task
from flask.logging import default_handler
app = Flask(__name__)

@app.route('/')
def default_route():
    """Default route"""
    app.logger.debug('this is a DEBUG message')
    app.logger.info('this is an INFO message')
    app.logger.warning('this is a WARNING message')
    app.logger.error('this is an ERROR message')
    app.logger.critical('this is a CRITICAL message')
    task()
    return jsonify('hello world')


@app.route('/current_app')
def default_route_current_app():
    current_app.logger.debug('this is a DEBUG message current app')
    task()
    return jsonify('hello world current app')

if __name__ != "__main__":
    # 设置日志的记录等级
    logging.basicConfig(level=logging.DEBUG)
    # app.logger.removeHandler(default_handler)  # 是否移除默认配置
    # 创建日志记录器
    handler = logging.FileHandler('flask.log')
    # 定义handler的输出格式
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    # 为全局的日志工具对象(flask app使用的)添加日志记录器
    logging.getLogger().addHandler(handler)

if __name__ == '__main__':
    # 设置日志的记录等级
    logging.basicConfig(level=logging.DEBUG)
    # app.logger.removeHandler(default_handler)  # 是否移除默认配置
    # 创建日志记录器
    handler = logging.FileHandler('flask.log')
    # 定义handler的输出格式
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    # 为全局的日志工具对象(flask app使用的)添加日志记录器
    logging.getLogger().addHandler(handler)
    # app.logger.addHandler(handler)
    app.run(host='0.0.0.0', port=8765)

4 执行flask后继续进行处理

可以解决这个报错的问题:python-“requests.exceptions.ConnectionError: (‘连接中止’, 远程断开连接(‘远程端关闭连接而没有响应’,))”。

需求:flask接口文件启动后,即时返回 ‘访问成功’,之后继续执行,文档中的功能函数。
方法:使用flask自带的一个函数即可解决。
flask_executor 模块。

from flask import Flask
from flask_executor import Executor

import time
app = Flask(__name__)
executor = Executor(app)


@app.route('/fast', methods=["POST", "GET"])
def fast_response():
    def test_function():
        # 需要异步执行的代码
        time.sleep(10)
        print('test_functiony执行了')
    executor.submit(test_function)
    return '异步立即返回'


@app.route('/slow', methods=["POST", "GET"])
def slow_response():
    def test_function():
        # 需要异步执行的代码
        time.sleep(10)
        print('test_functiony执行了')
    test_function()
    return '同步缓慢返回'

if __name__=="__main__":
    app.run()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1341277.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java学习——设计模式——创建型模式1

文章目录 创建型模式单例饿汉式懒汉式存在的问题 工厂方法简单工厂模式工厂方法模式抽象工厂模式 创建型模式 关注点是如何创建对象,核心思想是要把对象创建和使用相分离,这样两者能相对独立地变换 包括: 1、工厂方法:Factory Met…

深信服AF防火墙配置SSL VPN

防火墙版本:8.0.85 需提前确认防火墙是是否有SSL VPN的授权,确认授权用户数量 1、确认内外网接口划分 2、网络→SSL VPN,选择内外网接口地址 3、SSL VPN→用户管理→新增一个SSL VPN的用户 4、新增L3VPN资源,类型选择Other&…

在用Vite开发时静态图片放哪里,才能保证显示,不出现找不到资源

在用Vite开发时静态图片放哪里 在用Vite开发时静态图片(资源)放哪里呢 ? 如果你想直接全部显示的那么请你把静态资源放到public目录下面,这样你一打包所有的静态资源都会放到打包根目录下。但是此时你在项目中引用的地址一定要是…

微信小程序登录(生成token,token校验)——后端

写在前面:如果想自己开发微信小程序,需要先到微信小程序官方平台注册账号,地址为:https://mp.weixin.qq.com/wxopen/waregister?actionstep1. 登录流程 其中,开发者服务器就是我们的后端服务器,微信接口服…

编程笔记 GOLANG基础 003 Go语言开发环境搭建

编程笔记 GOLANG基础 003 Go语言开发环境搭建 一、安装VSCODE二、安装GO语言主程序 Golang的学习从开发环境搭建开始。本例记录的是WINDOWS平台下使用VSCODE做为开发工具的搭建过程。网上查到的资料都是以前版本的方法,新版Golang发生了一些变化。各位参数环境搭建时…

【c++】

1.定义自己的命名空间myspace&#xff0c;并在myspace中定义一个字符 #include <iostream> #include <cstring> //<><string.h> #include <cstdio> using namespace std; //3.定义自己的命名空间myspace&#xff0c;并在myspace中定义一个字符…

使用PLC 网关采集西门子PLC,提供远程售后服务

实现工业场景下的万物互联离不开对工业自动化设备的数据采集。其中PLC常用的工业现场总线协议就多达数十种&#xff0c;此外各大PLC厂商基本都有各自的私有总线协议。由于现场总线种类繁多各异&#xff0c;传统的工业PLC数据采集一般通过在设备侧部署边缘网关的方式进行&#x…

Flink Kafka[输入/输出] Connector

本章重点介绍生产环境中最常用到的Flink kafka connector。使用Flink的同学&#xff0c;一定会很熟悉kafka&#xff0c;它是一个分布式的、分区的、多副本的、 支持高吞吐的、发布订阅消息系统。生产环境环境中也经常会跟kafka进行一些数据的交换&#xff0c;比如利用kafka con…

美国化妆品FDA认证被强制要求,出口企业该这么办!!!

化妆品FDA认证是进入美国市场的重要准入条件&#xff0c;具备该认证有助于提升产品的市场竞争力和信誉&#xff1b; 目前FDA注册系统已全面开放&#xff0c;从原来的自愿性认证变更为现在的强制性认证&#xff0c;化妆品企业合规日期为2023年12月29日&#xff0c;但是强制处罚…

便携式小型气象站-科普知识

在当今快节奏的生活中&#xff0c;人们对气象信息的关注度越来越高。为了满足这一需求&#xff0c;便携式小型气象站应运而生&#xff0c;成为气象观测的新宠。这款设备不仅方便携带&#xff0c;而且功能齐全&#xff0c;可以随时随地为您提供准确的气象数据。 WX-BXQX8便携式…

git 学习 之一个规范的 commit 如何写

最好的话做一件完整的事情就提交一次

gin框架使用系列之四——json和protobuf的渲染

系列目录 《gin框架使用系列之一——快速启动和url分组》《gin框架使用系列之二——uri占位符和占位符变量的获取》《gin框架使用系列之三——获取表单数据》 上篇我们介绍了如何获取数据&#xff0c;本篇我们介绍一下如何返回固定格式的数据。 一、返回JSON数据 在web开发中…

【贪心】哈夫曼编码Python实现

文章目录 [toc]哈夫曼编码不同编码方式对比前缀码构造哈夫曼编码哈夫曼算法的正确性贪心选择性质证明 最优子结构性质证明 总结 时间复杂性Python实现 个人主页&#xff1a;丷从心 系列专栏&#xff1a;贪心算法 哈夫曼编码 哈夫曼编码是广泛用于数据文件压缩的十分有效的编码…

gitlab请求合并分支

直接去看原文: 原文链接:Gitlab合并请求相关流程_source branch target branch-CSDN博客 --------------------------------------------------------------------------------------------------------------------------------- 入口&#xff1a; 仓库控制台的这两个地方都…

Oracle database 静默安装 oracle12c 一键安装 12.1.0.2

基于oracle安装包中应答文件实现一键安装 注意此安装脚本基于12.1.0.2 安装包 原始安装包结构为两个压缩包 此脚本使用安装包为原始压缩包解压后、 重新封装为一个.zip压缩包 建议在linux 环境下解压重新压缩后 使用该脚本 支持环境: Linux :centerOS 7 oracle :12.1.0.…

力扣精选题

题目: 写出最大数 回答: let count function(a,b){ let num1 a.toString() let num2 b.toString() return (num2num1)-(num1num2) } let last arr.sort(count) let arr [18,20,33,4,5] let num last.join() console.log(last,last) 最终得出最大数字符串: …

某后台管理系统加密参数逆向分析

前言 在我们日常的渗透中经常会遇到开局一个登录框的情况&#xff0c;弱口令爆破当然是我们的首选。但是有的网站会对账号密码等登录信息进行加密处理&#xff0c;这一步不由得阻碍了很多人的脚步。前端的加解密是比较常见的&#xff0c;无论是 web 后台还是小程序&#xff0c…

TransNeXt:稳健的注视感知ViT学习笔记

论文地址&#xff1a;https://arxiv.org/pdf/2311.17132.pdf 代码地址&#xff1a; GitHub - DaiShiResearch/TransNeXt: Code release for TransNeXt model 可以直接在ImageNet上训练的分类代码&#xff1a;GitHub - athrunsunny/TransNext-classify 代码中读取数据的部分修改…

数据驱动与数据安全,自动驾驶看得见的门槛和看不见的天花板

作者 |田水 编辑 |德新 尽管心理有所准备&#xff0c;2023年智能驾驶赛道的内卷程度还是超出了大多数人的预期。 这一年&#xff0c;汽车价格战突然开打&#xff0c;主机厂将来自销售终端的价格压力&#xff0c;传导到下游智驾供应商&#xff0c;于是&#xff0c;市面上出现…

鸿蒙4.0实战应用(ArkTS)-抽奖转盘

构建主界面 在这个章节中&#xff0c;我们将完成示例主界面的开发&#xff0c;效果如图所示&#xff1a; 功能要求&#xff1a; 通过画布组件Canvas&#xff0c;画出抽奖圆形转盘。通过显式动画启动抽奖功能。通过自定义弹窗弹出抽中的奖品。 在绘制抽奖圆形转盘前&#xff…