符合生产环境的uWSGI配置

» Configuring uWSGI for Production Deployment

uWSGI thing to know

基础配置

The basics
[uwsgi]
strict = true
master = true
enable-threads = true
vacuum = true                          ; Delete sockets during shutdown
single-interpreter = true
die-on-term = true                     ; Shutdown when receiving SIGTERM (default is respawn)
need-app = true

disable-logging = true
log-4xx = true
log-5xx = true

这些选项应该是默认设置, 但是其中一两个可能不适合你的部署

strict = true

如果 uWSGI 没有明确理解配置文件中的任何参数,则此选项告诉 uWSGI 无法启动

最好默认启用此字段

因为在生产环境中输入错误 uWSGI 配置参数的风险比占位符、
自定义选项或应用程序相关配置项提供的实用程序更大

enable-threads = true

uWSGI disables Python threads by default

By default the Python plugin does not initialize the GIL. This means your app-generated threads will not run. 
If you need threads, remember to enable them with enable-threads. Running uWSGI in multithreading mode (with the threads options) 
will automatically enable threading support. This “strange” default behaviour is for performance reasons, no shame in that.

最好将其默认为“开启”,并根据具体情况将其删除

uWSGI 有额外的插件可以与其他异步解决方案集成,例如 eventlet、gevent 和 asyncio(尽管它们不符合 ASGI)

vacuum = true

将指示 uWSGI 清理它创建的任何临时文件UNIX 套接字

例如 HTTP 套接字、pidfiles 或管理 FIFO

这些文件留下可能会在某些情况下构成问题

例如,如果开发人员将UWSGI作为自己的用户运行,并且占据这些文件的所有权。
 如果生产用户没有删除这些文件的权限,则UWSGI可能无法正常运行。

single-interpreter = true

uWSGI 默认以多解释器模式启动,这允许在每个工作进程中托管多个服务

可能的问题

    多个解释器很酷,但是有报道说一些 c 扩展不能很好地配合它们
    
    当启用多个解释器时,uWSGI 将在每次请求时更改整个 ThreadState(一个内部 Python 结构)。
    它不是那么慢,但有一些可能会矫枉过正的应用程序/扩展程序

禁用此功能似乎没有负面影响,同时还降低了可能浪费开发时间或导致生产中断的兼容性问题的几率

die-on-term = true

SIGTERM 关闭 主进程

您应该启用此功能,因为它使 uWSGI 以任何理智的开发人员所期望的方式运行。
如果没有它,kill 或任何发送 SIGTERM 的工具(例如某些系统监控工具)都会尝试杀死 uWSGI,但不会成功,从而使所述工具的操作员感到困惑


Till uWSGI 2.1, by default, sending the SIGTERM signal to uWSGI means “brutally reload the stack” while the convention is to shut an application down on SIGTERM. 
To shutdown uWSGI, use SIGINT or SIGQUIT instead. If you absolutely can not live with uWSGI being so disrespectful towards SIGTERM, by all means, enable the die-on-term option. 
Fortunately, this bad choice has been fixed in uWSGI 2.1

need-app = true

如果 uWSGI 无法找到或加载您的应用程序模块,则此参数会阻止 uWSGI 启动。

如果没有这个选项,uWSGI 将忽略启动时抛出的任何语法和导入错误,并将启动一个空壳,为所有请求返回 500s。 
这尤其成问题,因为监控系统可能会观察到 uWSGI 成功启动并认为该应用程序可用于服务请求,而实际上并非如此。

disable-logging = true

默认情况下,uWSGI 有相当详细的日志记录。

禁用 uWSGI 的标准日志记录是合理的,尤其是当您的应用程序发出简洁而有意义的日志时

log-4xx = true log-5xx = true

如果您确实选择禁用 uWSGI 的标准日志输出

我们建议您使用 log-4xxlog-5xx 参数重新启用 uWSGI 的内置日志记录

以响应 HTTP 状态代码为 4xx 或 5xx 的响应

这将确保始终记录关键错误, 以面对未处理的异常、意外信号和本机代码中的段错误

这对于`应用程序记录器`而言是`非常难以确保的`

进程管理 Woker Management

进程回收 Worker Recycling

进程回收可以防止随着时间的推移变得明显的问题,例如内存泄漏或意外状态。

在某些情况下,它可以提高性能,因为较新的进程具有新的内存空间。

uWSGI 为回收工人提供了多种方法

 假设您的应用程序重新加载相对较快,以下所有三种方法都应该有效无害,并针对不同的故障场景提供保护。

此配置将在以下任何事件发生后重新启动工作进程

1000 requests have been handled
The worker has allocated 2 GB of memory
1 hour has passed
max-requests = 1000                  ; Restart workers after this many requests (1000 requests have been handled)
max-worker-lifetime = 3600           ; Restart workers after this many seconds (The worker has allocated 2 GB of memory)
reload-on-rss = 2048                 ; Restart workers after this much resident memory (1 hour has passed)

worker-reload-mercy = 60             ; How long to wait before forcefully killing workers

动态扩展 Dynamic Worker Scaling(cheaper)

当启用 uWSGI cheaper subsystem, 主进程将在流量增加时产生工作线程,并在流量减少时逐渐关闭工作线程

这里有各种算法可用于确定在任何给定时刻应该有多少进程可用

busyness 算法 
    
    尝试始终有空闲的工作人员可用,这在预测意外的流量激增时很有用
cheaper-algo = busyness              
processes = 500                      ; Maximum number of workers allowed
cheaper = 8                          ; Minimum number of workers allowed
cheaper-initial = 16                 ; Workers created at startup
cheaper-overload = 1                 ; Length of a cycle in seconds
cheaper-step = 16                    ; How many workers to spawn at a time

cheaper-busyness-multiplier = 30     ; How many cycles to wait before killing workers
cheaper-busyness-min = 20            ; Below this threshold, kill workers (if stable for multiplier cycles)
cheaper-busyness-max = 70            ; Above this threshold, spawn new workers
cheaper-busyness-backlog-alert = 16  ; Spawn emergency workers if more than this many requests are waiting in the queue
cheaper-busyness-backlog-step = 2    ; How many emergegency workers to create if there are too many requests in the queue

硬超时 Hard Timeouts (harakiri)

--harakiri 选项将在指定的秒数后 SIGKILL 进程

harakiri = 60                        ; Forcefully kill workers after 60 seconds
如果没有此功能,卡住的进程可能会永远卡住

Harakiri 可以通过 uwsgdecorators 模块在 Python 代码中动态设置,但这是对 –harakiri 选项的补充,而不是替代

两者中的较小者将是有效超时

允许进程接收信号 py-call-osafterfork = true

默认情况下,worker 无法接收操作系统信号

此标志将允许他们接收信号,例如 signal.alarm。 如果您打算在工作进程中使用信号模块,这是必要的

我们倾向于使用 signal.alarm(seconds), 尝试在使用 harakiri 之前优雅地超时请求

进程标签 Process Labeling

默认情况下,uWSGI worker 的进程名称 是用于启动它们的命令产生的

bgreen89 180976 180847  0 17:20 pts/27   00:00:00 uwsgi3.6 --module my_svc:service --http11-socket :29292 --ini etc/my_svc_uwsgi.ini --need-app
bgreen89 180977 180847  0 17:20 pts/27   00:00:00 uwsgi3.6 --module my_svc:service --http11-socket :29292 --ini etc/my_svc_uwsgi.ini --need-app
bgreen89 180978 180847  0 17:20 pts/27   00:00:00 uwsgi3.6 --module my_svc:service --http11-socket :29292 --ini etc/my_svc_uwsgi.ini --need-app

uWSGI 提供了一些可以帮助识别工人的功能:

auto-procname = true

bgreen89 188116 188115  4 17:21 pts/27   00:00:00 uWSGI master
bgreen89 188191 188116  0 17:21 pts/27   00:00:00 uWSGI worker 1
bgreen89 188192 188116  0 17:21 pts/27   00:00:00 uWSGI worker 2
bgreen89 188193 188116  0 17:21 pts/27   00:00:00 uWSGI worker 3

但如果我们在同一台机器上运行多个 uWSGI 实例,我们就会遇到问题

# 可以清楚地识别哪些进程属于哪个服务
procname-prefix = "mysvc "  # note the space

bgreen89  41120 138777 44 17:32 pts/27   00:00:00 mysvc uWSGI master
bgreen89  41172  41120  0 17:32 pts/27   00:00:00 mysvc uWSGI worker 1
bgreen89  41173  41120  0 17:32 pts/27   00:00:00 mysvc uWSGI worker 2
bgreen89  41174  41120  0 17:32 pts/27   00:00:00 mysvc uWSGI worker 3

uWSGI 通过其 Python API 公开了一个 setprocname 函数,允许服务动态设置其进程名称。

这允许添加有关每个工作人员的特定于应用程序的上下文。

  当有人正在快速尝试识别有问题的资源时,这些附加信息在中断中可能是无价的
bgreen89  41120 138777 44 17:32 pts/27   00:00:00 mysvc uWSGI master
bgreen89  41120 138777 44 17:32 pts/27   00:00:00 mysvc username /path/to/url uWSGI worker 1
bgreen89  41172  41120  0 17:32 pts/27   00:00:00 mysvc johndoe /index.html uWSGI worker 2
bgreen89  41173  41120  0 17:32 pts/27   00:00:00 mysvc janedoe /assets/data uWSGI worker 3

完整的配置内容

[uwsgi]
strict = true
master = true
enable-threads = true
vacuum = true                        ; Delete sockets during shutdown
single-interpreter = true
die-on-term = true                   ; Shutdown when receiving SIGTERM (default is respawn)
need-app = true

disable-logging = true               ; Disable built-in logging 
log-4xx = true                       ; but log 4xx's anyway
log-5xx = true                       ; and 5xx's

harakiri = 60                        ; forcefully kill workers after 60 seconds
py-callos-afterfork = true           ; allow workers to trap signals

max-requests = 1000                  ; Restart workers after this many requests
max-worker-lifetime = 3600           ; Restart workers after this many seconds
reload-on-rss = 2048                 ; Restart workers after this much resident memory
worker-reload-mercy = 60             ; How long to wait before forcefully killing workers

cheaper-algo = busyness
processes = 128                      ; Maximum number of workers allowed
cheaper = 8                          ; Minimum number of workers allowed
cheaper-initial = 16                 ; Workers created at startup
cheaper-overload = 1                 ; Length of a cycle in seconds
cheaper-step = 16                    ; How many workers to spawn at a time

cheaper-busyness-multiplier = 30     ; How many cycles to wait before killing workers
cheaper-busyness-min = 20            ; Below this threshold, kill workers (if stable for multiplier cycles)
cheaper-busyness-max = 70            ; Above this threshold, spawn new workers
cheaper-busyness-backlog-alert = 16  ; Spawn emergency workers if more than this many requests are waiting in the queue
cheaper-busyness-backlog-step = 2    ; How many emergency workers to create if there are too many requests in the queue

额外的 uWSGI 特性

Cron/Timer

Locks

Cache system

uWSGI mules

uWSGI mules 是额外的进程,指定用于从服务请求的工作人员异步处理任务

Buy me a 肥仔水!