编辑
2025-08-01
Python
00

目录

Gunicorn 使用及常见工程化配置
1. 什么是 Gunicorn?
2. 安装 Gunicorn
步骤:
3. 基本使用
启动 Gunicorn
指定绑定地址和端口
指定工作进程数
运行后台模式
4. Gunicorn 配置选项
4.1 常用命令行参数
4.2 配置文件
配置项总结表
5. 与 Flask 和 Django 集成
5.1 与 Flask 集成
5.2 与 Django 集成
6. 主要的 Gunicorn 服务器钩子
请求级别的钩子
示例:gunicorn.conf.py 配置文件
如何运行
7. 进阶优化与管理
7.1 选择合适的 Worker 类
7.2 自动重新加载
7.3 进程管理与监控
7.4 日志管理
8. 常见问题及解决方案
8.1 端口被占用
8.2 无法连接到应用
8.3 应用崩溃或重启频繁

Gunicorn 使用及常见工程化配置

1. 什么是 Gunicorn?

Gunicorn 是一个用 Python 编写的轻量级 WSGI 服务器,遵循 UNIX 风格,兼容多种 Web 框架,如 Django、Flask 等。它通过多进程和多线程方式处理 HTTP 请求,具有简单易用、高效稳定的特点。

主要特点:

  • 支持多种工作模式(同步、异步)。
  • 易于配置和扩展。
  • 与许多 Web 框架兼容。
  • 适合在生产环境中部署 Python 应用。

2. 安装 Gunicorn

安装 Gunicorn 非常简单,可以通过 pip 进行安装。建议在虚拟环境中进行安装,以避免与系统包冲突。

步骤:

  1. 创建并激活虚拟环境(可选)

    bash
    python3 -m venv venv source venv/bin/activate
  2. 安装 Gunicorn

    bash
    pip install gunicorn
  3. 验证安装

    bash
    gunicorn --version

    输出示例:

    gunicorn (version 20.1.0)

3. 基本使用

Gunicorn 的基本用法是指定应用的 WSGI 接口。例如,假设你有一个 Flask 应用 app.py

python
# app.py from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello, Gunicorn!"

启动 Gunicorn

在终端中运行以下命令:

bash
gunicorn app:app

解释:

  • 第一个 app 是指 app.py 文件(不需要 .py 后缀)。
  • 第二个 app 是指 app.py 文件中创建的 Flask 应用实例。

指定绑定地址和端口

默认情况下,Gunicorn 绑定到 127.0.0.1:8000。可以通过 -b 参数指定:

bash
gunicorn -b 0.0.0.0:8000 app:app

指定工作进程数

默认使用 1 个工作进程。可以通过 -w 参数指定:

bash
gunicorn -w 4 app:app

这将启动 4 个工作进程。

运行后台模式

使用 -D 参数可在后台运行 Gunicorn:

bash
gunicorn -w 4 -D app:app

4. Gunicorn 配置选项

Gunicorn 提供了丰富的配置选项,可以通过命令行参数或配置文件进行设置。以下是常用的配置选项及其说明。

4.1 常用命令行参数

  • -w / --workers:指定工作进程数。例如 -w 4
  • -b / --bind:绑定的地址和端口。例如 -b 0.0.0.0:8000
  • -k / --worker-class:指定工作类型(同步、异步)。例如 -k gevent
  • --timeout:单个worker超时时间,默认为30s,所有请求无输入输出超过此时间将被强制重启。
  • --graceful_timeout:准备重启时,gunicorn等待服务所有处理完成的最大时间,超过会进行强制关闭worker。
  • --max_requests:单个worker最大请求数,达到后自动重启
  • --max_requests_jitter: max_requests 动态范围,gunicorn会自动取范围内随机值动态调整最终max_requests。
  • --log-level:日志级别(debug, info, warning, error, critical)。
  • --access-logfile:访问日志文件路径。
  • --error-logfile:错误日志文件路径。
  • -D / --daemon:后台运行。
  • --reload:在代码更改时自动重新加载(仅开发环境)。

4.2 配置文件

Gunicorn 支持通过配置文件进行设置,配置文件可以是 Python 脚本或配置文件格式。一般推荐使用 Python 配置文件。

示例:gunicorn_conf.py

python
# gunicorn_conf.py """ gunicorn 配置文件 参考: https://docs.gunicorn.org/en/stable/settings.html """ import os from pathlib import Path import multiprocessing BASE_DIR = Path(__file__).resolve().parents[0] #================================================ # 基础配置 #================================================ # 绑定ip和端口号 bind = '0.0.0.0:8000' # 指定Gunicorn处理请求的队列的最大长度,如果监听队列已满,新的请求将被拒绝或丢弃 backlog = 2048 #================================================ # 工作进程配置 #================================================ # 默认sync模式 # wsgi 使用gevent模式可更好解决处理时长较长的请求 # asgi 应用使用uvicorn worker worker_class = 'gevent' # worker_class = 'uvicorn.workers.UvicornWorker' # 进程数,一般填cpu核心数倍数 + 1 workers = (multiprocessing.cpu_count() * 2) + 1 # 指定每个进程开启的线程数 # !warning: asgi 模式下不支持多线程,请直接注释,不要使用 # threads = 2 #================================================ # 自动重启配置 #================================================ # 超时时间,默认为30s,所有请求无输入输出超过此时间将被强制终止 # 保证任务在空闲时仅导出不会被误判杀死 timeout = 660 # 保证任务在计划重启时能被完整执行 graceful_timeout = 660 # 单个worker最大请求数,达到后自动重启 max_requests = 2000 # max_requests 动态范围 max_requests_jitter = 200 #================================================ # 日志配置 #================================================ # 日志文件目录 log_dir = os.path.join(BASE_DIR, "logs", "gunicorn") os.makedirs(log_dir, exist_ok=True) # 日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置 loglevel = 'info' accesslog = log_dir + "/access.log" errorlog = log_dir + "/error.log" # 访问日志格式 # t: 时间, p: 进程ID, h: 远程地址, r: 请求行, s: 状态码, # L: 请求处理时间(秒), b: 响应长度, f: Referer, a: User-Agent access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s "%(f)s" "%(a)s"'

启动时指定配置文件:

bash
gunicorn -c gunicorn_conf.py app:app

配置项总结表

配置项类型默认值说明
bindString127.0.0.1:8000服务器绑定的地址和端口。
workersInteger1工作进程数,建议为 2 x CPU 核数 + 1
worker_classStringsync工作类型,如 sync, gevent
threadsInteger1每个工作进程的线程数,适用于 gthread
timeoutInteger30请求超时时间(秒)。
keepaliveInteger2HTTP Keep-Alive 超时时间(秒)。
backlogInteger2048连接队列长度。
preload_appBooleanFalse是否在工作进程启动前加载应用。
reloadBooleanFalse是否启用代码更改自动重载(仅开发环境)。
reload_engineStringauto指定重载引擎,如 stat, watchman
reload_extra_filesList[]监控的额外文件列表,文件变动时重载。
daemonBooleanFalse是否以守护进程模式运行。
pidfileStringNone保存主进程 PID 文件路径。
userString当前用户指定工作进程运行的用户。
groupString当前组指定工作进程运行的组。
umaskInteger0文件模式创建掩码。
worker_connectionsInteger1000每个异步工作类型的最大客户端连接数。
limit_request_fieldsInteger327单个请求允许的最大头字段数。
limit_request_field_sizeInteger8190单个头字段的最大字节数。
limit_request_lineInteger4094请求行的最大字节数。
graceful_timeoutInteger30优雅关闭时的超时时间(秒)。
accesslogString-(标准输出)访问日志文件路径。
errorlogStringstderr错误日志文件路径。
loglevelStringinfo日志记录级别,如 debug, info
logger_classStringgunicorn.glogging.Logger自定义日志类。
access_log_formatString'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'访问日志格式。
access_logshow_fieldBooleanTrue是否显示特定日志字段。
spewBooleanFalse开启详细的调试信息和所有模块导入。
disable_redirect_access_to_syslogBooleanFalse禁用将访问日志重定向到系统日志。
syslogString/BooleanFalse启用将日志发送到 syslog。
syslog_prefixStringNone日志消息的前缀。
enable_stdio_inheritanceBooleanTrue是否继承标准输入/输出文件描述符。
graceful_shutdown_timeoutInteger30工作进程优雅关闭时的最大等待时间(秒)。
raw_envList[]设置环境变量,格式为 KEY=VALUE
env_fileStringNone指定包含环境变量的文件路径。
secure_scheme_headersDict{'X-FORWARDED-PROTO': 'https'}指定用于安全连接的协议头。
proxy_protocolBooleanFalse启用 PROXY 协议支持。
pasteStringNone使用 PasteDeploy 的配置文件。
worker_tmp_dirString/dev/shm工作进程的临时目录。
proxy_allow_ipsString127.0.0.1允许通过反向代理的 IP 地址列表,逗号分隔。
ssl_versionStringTLS指定 SSL 协议的版本。
ssl_certfileStringNoneSSL 证书文件路径。
ssl_keyfileStringNoneSSL 密钥文件路径。
ssl_ca_certsStringNoneSSL CA 证书文件路径。
ssl_ciphersString"TLS"指定 SSL/TLS 密码套件。
ssl_pre_postBooleanFalse在 SSL 握手前发送预共享密钥。
ssl_keyfile_passStringNoneSSL 密钥文件的密码。
ssl_ocspStringNoneOCSP 文件路径。
fastcgiBooleanFalse启用 FastCGI 支持。
limit_requestList[]限制特定请求类型的数量。
specStringNone使用 spec 文件加载配置。
statsd_onBooleanFalse启用 StatsD 监控。
statsd_hostString127.0.0.1StatsD 服务器主机地址。
statsd_portInteger8125StatsD 服务器端口号。
statsd_prefixStringgunicorn用于 StatsD 的命名前缀。
on_startingCallableNoneGunicorn 启动时调用的钩子函数。
when_readyCallableNoneGunicorn 准备就绪后调用的钩子函数。
pre_forkCallableNone每个工作进程分叉前调用的钩子函数。
post_forkCallableNone每个工作进程分叉后调用的钩子函数。
pre_execCallableNone在执行 Gunicorn 主程序前调用的钩子函数。
pre_requestCallableNone每个请求前调用的钩子函数。
post_requestCallableNone每个请求后调用的钩子函数。
child_exitCallableNone工作进程退出时调用的钩子函数。
worker_intCallableNone工作进程收到 SIGINT 信号时调用的钩子函数。
worker_abortCallableNone工作进程收到 SIGABRT 信号时调用的钩子函数。
logconfigStringNone指定 Python logging 配置文件路径。
logconfig_dictDictNone通过字典方式配置 logging。
enable_soeBooleanFalse启用 SOE 模式,用于更好的错误处理。
buffer_responseBooleanFalse是否缓冲响应数据。
h11_max_incomplete_event_sizeInteger4096h11 协议中,允许的最大未完成事件大小。
enable_h11_parsingBooleanFalse启用 h11 协议的解析。
default_pidfileStringNone默认 PID 文件路径。
default_accesslogString-(标准输出)默认访问日志路径。

注意: 以上配置项不是全部,但涵盖了大部分常用和关键的选项。对于更详细和最新的配置选项,请参考 Gunicorn 官方文档


5. 与 Flask 和 Django 集成

Gunicorn 能够无缝集成常见的 Python Web 框架,如 Flask 和 Django。

5.1 与 Flask 集成

示例 Flask 应用:

python
# app.py from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello from Flask!"

启动 Gunicorn:

bash
gunicorn -w 4 -b 0.0.0.0:8000 app:app

5.2 与 Django 集成

Django 项目结构示例:

myproject/ manage.py myproject/ __init__.py settings.py urls.py wsgi.py

确保 wsgi.py 存在,通常为默认生成。

启动 Gunicorn:

bash
gunicorn myproject.wsgi:application

常用命令示例:

bash
gunicorn -w 4 -b 0.0.0.0:8000 myproject.wsgi:application

6. 主要的 Gunicorn 服务器钩子

Gunicorn 提供了丰富的生命周期钩子(Lifecycle Hooks),允许你在服务器和工作进程(worker)生命周期的不同阶段执行自定义代码。这对于管理资源(如数据库连接、消息队列客户端)、设置日志、发送通知等非常有用。

这些钩子通常在 Gunicorn 的配置文件(例如 gunicorn.conf.py)中定义为函数。

以下是 Gunicorn 提供的一些关键生命周期钩子,以及它们的触发时机和用途:

钩子名称 (Hook Name)触发时机执行者常用场景
on_starting(server)服务器主进程(Master)启动时,在加载任何应用代码之前。Master设置全局日志、早期配置检查。
when_ready(server)服务器完全启动并准备好接受连接时。Master发送“服务已启动”的通知、执行启动后任务。
pre_fork(server, worker)主进程 fork 出一个新的工作进程之前。Master准备 fork 所需的资源,例如在 fork 前减少文件描述符。
post_fork(server, worker)主进程 fork 出一个新的工作进程之后,在子进程中。Worker非常常用! 为每个工作进程初始化资源,如创建新的数据库连接、Redis 连接池等,避免多进程共享同一个连接。
pre_exec(server)主进程执行一个新的二进制文件之前(例如,在服务升级或重启时)。Master保存状态、关闭旧的监听套接字。
worker_int(worker)工作进程收到 SIGINTSIGQUIT 信号时(通常是优雅地停止)。Worker执行优雅关闭逻辑,例如等待当前请求完成、关闭连接。
worker_abort(worker)工作进程由于超时(timeout)而被主进程杀死时。Worker记录异常信息、发送警报,用于调试僵死的进程。
child_exit(server, worker)任何一个工作进程退出时(无论正常或异常)。Master记录工作进程退出事件、更新监控指标。
worker_exit(server, worker)child_exit的旧称,功能相同。Master同上。
on_exit(server)Gunicorn 完全关闭时。Master最终的清理工作。

请求级别的钩子

除了服务器和进程级别的钩子,还有请求级别的钩子:

钩子名称 (Hook Name)触发时机
pre_request(worker, req)工作进程接收到请求,但在处理请求之前。
post_request(worker, req, environ, resp)工作进程处理完请求之后,在响应发送给客户端之前。

示例:gunicorn.conf.py 配置文件

下面是一个包含多个常用钩子的 Gunicorn 配置文件示例,可以很好地展示它们如何工作。

假设你的项目结构如下:

my_project/ ├── my_app.py └── gunicorn.conf.py

my_app.py (你的 WSGI 应用):

python
def app(environ, start_response): data = b"Hello, World!\n" start_response("200 OK", [ ("Content-Type", "text/plain"), ("Content-Length", str(len(data))) ]) return iter([data])

gunicorn.conf.py (Gunicorn 配置文件):

python
import os # 服务器套接字 bind = "0.0.0.0:8000" # 工作进程数 workers = 4 # Gunicorn 进程的 PID 文件 pidfile = "/tmp/gunicorn.pid" # 日志文件 accesslog = "/tmp/gunicorn_access.log" errorlog = "/tmp/gunicorn_error.log" print("Gunicorn config file loaded.") # --- 生命周期钩子 --- def on_starting(server): print("1. [Master] on_starting: 服务器正在启动...") def when_ready(server): print("2. [Master] when_ready: 服务器已就绪!") # 可以给监控系统发送一个通知 def pre_fork(server, worker): worker_id = worker.pid if worker.pid is not None else "N/A" print(f"3. [Master] pre_fork: 准备 fork worker {worker_id}...") # 注意:此时 worker.pid 可能是 None,因为进程还没创建 def post_fork(server, worker): # 这是在新的工作进程中执行的 print(f"4. [Worker {worker.pid}] post_fork: Worker 已 fork,PID: {worker.pid}") # 在这里为每个 worker 创建数据库连接是最佳实践 # import my_db_lib # worker.db_conn = my_db_lib.connect() print(f"[Worker {worker.pid}] 初始化数据库连接...") def pre_request(worker, req): worker.log.debug("%s: %s", worker.pid, req.path) print(f"[Worker {worker.pid}] pre_request: 收到请求 {req.path}") def worker_int(worker): # 在这个钩子中,你可以进行优雅的关闭操作 print(f"[Worker {worker.pid}] worker_int: 收到 SIGINT/SIGQUIT 信号,准备退出。") # if worker.db_conn: # worker.db_conn.close() # print(f"[Worker {worker.pid}] 数据库连接已关闭。") def child_exit(server, worker): print(f"[Master] child_exit: Worker {worker.pid} 已退出。") def on_exit(server): print("[Master] on_exit: Gunicorn 正在关闭...")

如何运行

使用以下命令来启动 Gunicorn,它会自动加载同目录下的 gunicorn.conf.py 文件:

bash
# 确保你在 my_project 目录下 gunicorn my_app:app

如果你想指定配置文件路径:

bash
gunicorn --config gunicorn.conf.py my_app:app

启动后,你会在控制台看到类似下面的输出,清晰地展示了钩子的执行顺序:

Gunicorn config file loaded. [2023-10-27 11:30:00] [12345] [INFO] Starting gunicorn 21.2.0 [2023-10-27 11:30:00] [12345] [INFO] Listening at: http://0.0.0.0:8000 (12345) [2023-10-27 11:30:00] [12345] [INFO] Using worker: sync 1. [Master] on_starting: 服务器正在启动... [2023-10-27 11:30:00] [12350] [INFO] Booting worker with pid: 12350 [2023-10-27 11:30:00] [12351] [INFO] Booting worker with pid: 12351 ... (其他 workers) ... 3. [Master] pre_fork: 准备 fork worker N/A... 4. [Worker 12350] post_fork: Worker 已 fork,PID: 12350 [Worker 12350] 初始化数据库连接... 3. [Master] pre_fork: 准备 fork worker N/A... 4. [Worker 12351] post_fork: Worker 已 fork,PID: 12351 [Worker 12351] 初始化数据库连接... ... (其他 workers 的 post_fork) ... 2. [Master] when_ready: 服务器已就绪!

7. 进阶优化与管理

为了让 Gunicorn 更高效地运行,以及便于维护,可以采用以下优化和管理措施。

7.1 选择合适的 Worker 类

Gunicorn 支持多种 worker 类,不同的应用场景选择不同的 worker 类可提升性能。

  • Sync(默认):适用于 I/O 较少的任务。
  • Gevent:基于协程,适用于高并发 I/O 密集型应用。
  • Eventlet:类似 Gevent,基于协程。
  • Tornado:基于 Tornado 框架。
  • Gthread:基于线程的工作类型。

示例:使用 Gevent Worker

bash
gunicorn -k gevent -w 4 myproject.wsgi:application

7.2 自动重新加载

在开发环境中,可以启用自动重新加载功能,使代码更新后自动重启 Gunicorn。

bash
gunicorn --reload myproject.wsgi:application

注意: --reload 仅适用于开发环境,不推荐在生产环境中使用。

7.3 进程管理与监控

  • Supervisor:一种进程控制系统,可用于管理 Gunicorn 进程。
  • systemd:已经在前面介绍过,可用于管理 Gunicorn 服务。
  • Gunicorn 自带的进程管理:如父进程监控子进程。

Supervisor 配置示例:

安装 Supervisor:

bash
sudo apt install supervisor

创建 Supervisor 配置文件 /etc/supervisor/conf.d/gunicorn.conf

ini
[program:gunicorn] command=/path/to/your/venv/bin/gunicorn --workers 4 --bind 0.0.0.0:8000 myproject.wsgi:application directory=/path/to/your/myproject user=your_user autostart=true autorestart=true redirect_stderr=true stdout_logfile=/var/log/gunicorn/gunicorn.log

启动 Supervisor:

bash
sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl status gunicorn

7.4 日志管理

  • 集中日志:将 Gunicorn 和 Nginx 的日志集中到一个地方,便于监控和分析。
  • 日志轮转:使用 logrotate 等工具管理日志文件,防止日志文件过大。

logrotate 配置示例 /etc/logrotate.d/gunicorn

ini
/var/log/gunicorn/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 your_user www-data sharedscripts postrotate systemctl reload gunicorn > /dev/null 2>&1 || true endscript }

8. 常见问题及解决方案

8.1 端口被占用

问题: 启动 Gunicorn 时提示端口被占用。

解决:

  • 检查端口占用情况:

    bash
    sudo lsof -i :8000
  • 杀掉占用进程:

    bash
    sudo kill -9 <PID>
  • 或更改 Gunicorn 绑定的端口。

8.2 无法连接到应用

问题: 通过浏览器访问 Nginx 代理的地址,但无法连接到应用。

解决:

  • 检查 Gunicorn 是否在运行:

    bash
    sudo systemctl status gunicorn
  • 检查 Nginx 配置是否正确,尤其是 proxy_pass 地址和端口。

  • 查看防火墙设置,确保所用端口开放。

8.3 应用崩溃或重启频繁

问题: Gunicorn 工作进程频繁崩溃或重启。

解决:

  • 检查 Gunicorn 错误日志,查看具体错误信息。
  • 确保应用代码没有未捕获的异常。
  • 调整 timeout 设置,避免请求处理过长时间导致超时。
  • 检查资源使用情况,如内存不足导致进程被系统杀掉。

本文作者:Silon汐冷

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!