分享案例:在生产docker部署flask接口的运行出错以及Gunicorn的使用

前言

        使用 python + 运行脚本 的方式在生产运行会有大问题!!!   

        我写了一个flask的接口,然后把接口放在docker中运行,在测试环境部署测试的时候什么问题都没有,测试完后部署在堡垒机生产中,会产生这样的问题:

        问题一:接口可以正产运行,查看日志没有问题, 但是访问没有数据返回,接口无反应,捣鼓了半天也没查出什么,于是重启接口后,居然可以正常访问了!!!

        问题二:接口运行一段时间,自己就挂了,毫无征兆,日志毛问题也没有!! 

        所以,如果你在生产中使用 python 的命令运行脚本的时候,会出现不稳定、有一定概率请求无反应等问题,不建议在生产中操作!!!

        目前我找到解决方案的之一:

        使用 Gunicorn + Gevent 结合,Gunicorn封装flask运行接口,Gevent提供协程非阻塞式处理多个IO操作,目前没有问题。

使用 Gunicorn + Gevent 实现高性能并发

简单描述:

        Gunicorn是一个的WSGI服务器,可以通过多进程的方式来处理多个请求并发
        配合使用Gevent时,可以将阻塞式的I/O操作转化为非阻塞式,从而提高应用程序的响应速度

简单配置Gunicorn 和 flask :

(一)创建 Gunicorn 的文件配置 - gunicorn_config.py

        在这是使用文件的方式运行,方便维护

import multiprocessing
from gevent import monkey
monkey.patch_all()

bind = '0.0.0.0:8081' # 暴露端口
chdir = '/Users/dealmon3w/PycharmProjects/cab_api_work' # 工作目录
timeout = 60 # 超时时间,默认30
worker_class = 'gevent' # 使用gevent模式,默认的是sync模式
workers = multiprocessing.cpu_count() # 启动的进程数
loglevel = "info" # 日志等级
access_log_format = '%(t)s <%(h)s> "%(a)s" -- "%(r)s" %(s)s -' # gunicorn访问日志格式
pidfile = "gunicorn.pid" # 运行主进程号,kill -9 可以杀死进程
accesslog = "cab_api_main.log" # 正常日志 可以是一个地址文件 - /root/cab_api_main.log
errorlog = "/root/cab_api_error.log" # 错误日志
# daemon = True # 调试模式

        如果不配置 accesslog 、 errorlog 日志文件,Gunicorn默认输出到控制台;

        如果配置 accesslog 、 errorlog 之后,就会把日志写进文件,但是不再输出到控制台;

gunicorn访问日志格式:
    %(h)s:远程地址(即客户端IP地址)
    %(l)s:一般是一个短横线 - 
    %(u)s:用户名称(如果服务器支持身份验证,则显示;否则是短横线 - )
    %(t)s:请求的时间戳  格式:[14/Jan/2011:04:48:59 +0000]
    "%(r)s":请求行(如"POST / HTTP/1.1")
    %(s)s:HTTP响应状态码
    %(b)s:响应的大小(以字节为单位)
    "%(f)s":引用的文件名
    "%(a)s":用户代理字符串(即HTTP头中的User-Agent)

(二)flask接口的编写文件 - cab_api_worktest.py

        配置flask自定义输出日志,和gunicorn访问正常日志也一同写进一个文件中,这样方便输出排查问题

        这样,控制台只输出我们自定义的flask日志,如果配置在docker中,可以使用 docker logs 查看日志,是与控制台同一个日志输出

import re, os, datetime, json, pymysql, logging
from uuid import uuid4
from flask import Flask, jsonify, request
from dbutils.pooled_db import PooledDB
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine, text, QueuePool, exc, update
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, String, Text, DateTime
from flask_cors import CORS, cross_origin

"""
配置sqlalchemy的日志,如果出现ERROR以上的日志会输出
"""
# 配置日志记录器,日志级别为DEBUG
flask_logger = logging.getLogger(__name__)
flask_logger.setLevel(logging.DEBUG)

# 配置文件日志处理器
file_handler = logging.FileHandler('cab_api_main.log')
file_handler.setLevel(logging.DEBUG)

# 配置控制台输出日志处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)

# 配置日志格式化器
formatter = logging.Formatter('%(asctime)s [%(filename)s %(lineno)d] %(levelname)s:%(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# 添加日志处理器到日志记录器
flask_logger.addHandler(console_handler)


app = Flask(__name__)
app.debug = True  # 调试使用,并默认使用日志输出,完全控制自定义日志记录,生产下删掉

# 将日志处理器添加到 Flask 应用的日志记录器
app.logger.setLevel(logging.INFO)
app.logger.addHandler(file_handler)  # 将日志输出写入文件


@app.route('/', methods=['GET', ])
def index():
    flask_logger.debug("请求调试") 
    flask_logger.info("请求成功") 
    flask_logger.warning("警告") 
    flask_logger.error("发生错误!") 
    flask_logger.critical("系统发生严重错误") 
    return 'Hello, World!'
    

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8081)

运行命令:

gunicorn  -c gunicorn_config.py cab_api_worktest:app

运行命令时要注意:

        1. 如果你有多个版本的python,可能会运行出错,因为用指定python版本安装,和默认安装的gunicorn是有区别的;在当前的python版本中使用,可能会使用其他版本的gunicorn;

        2. 预防报错,可以使用命令 whereis gunicorn 查看命令在哪里,即使是虚拟环境也可以这样操作

例如:

        我创建了一个python虚拟环境,查看命令所在

(.venv) [dealmon3w@xiaoguodong~/PycharmProjects/cab_api_work ]% whereis gunicorn
gunicorn: /Users/dealmon3w/PycharmProjects/cab_api_work/.venv/bin/gunicorn
 

        然后再用绝对路径运行接口

(.venv) [dealmon3w@xiaoguodong~/PycharmProjects/cab_api_work ]% /Users/dealmon3w/PycharmProjects/cab_api_work/.venv/bin/gunicorn  
-c gunicorn_config.py cab_api_worktest:app 

到此,分享就到这,主要是分享问题和解决的方案:

        1. 用python命令在生产环境中运行项目可能会出问题, 建议使用Gunicorn封装flask部署

        2. 使用 Gunicorn + flask 的日志配置,正常日志写进同一个文件中,flask自定义日志输出到控制台中,同时   Gunicorn 不再输出到控制台中     

希望能够帮助到大家,谢谢!!!

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值