关于django中几个重要的gunicorn worker的配置
关于django中几个重要的gunicorn worker的配置 一、worker_class worker_class 是 Gunicorn 的配置参数之一,它指定了工作进程(worker)的类型。不同的 worker_class 提供了不同的并发模型,适合不同类型的应用场景。sync 和 gevent 是两种常见的 worker_class,它们的作用和区别如下: 1. sync(同步 wor
关于django中几个重要的gunicorn worker的配置
一、worker_class
worker_class
是 Gunicorn 的配置参数之一,它指定了工作进程(worker)的类型。不同的 worker_class
提供了不同的并发模型,适合不同类型的应用场景。sync
和 gevent
是两种常见的 worker_class
,它们的作用和区别如下:
1. sync
(同步 worker)
- 默认值:如果没有指定
worker_class
,Gunicorn 默认为sync
。 - 工作方式:每个 worker 同时只能处理一个请求。这种模式是同步的,意味着每个请求会阻塞 worker,直到请求处理完成。
- 适用场景:
- CPU 密集型应用:适用于需要进行大量计算且对 I/O 操作要求不高的应用。这类应用通常不需要高并发处理,因而同步 worker 足够。
- 简单、低并发的应用:适合负载不高,或并发请求较少的简单应用。
- 优点:
- 实现简单,容易理解。
- 在 CPU 密集型应用中,
sync
worker 可以充分利用 CPU 资源,因为它不需要在大量 I/O 等待上浪费 CPU 时间。
- 缺点:
- I/O 密集型场景表现不佳:如果应用需要频繁的 I/O 操作(如数据库查询、外部 API 调用等),
sync
worker 在处理这些操作时会阻塞,导致不能充分利用 CPU。 - 并发处理能力较差:在高并发场景下,
sync
worker 由于单个 worker 只能处理一个请求,因此并发性能有限。
- I/O 密集型场景表现不佳:如果应用需要频繁的 I/O 操作(如数据库查询、外部 API 调用等),
2. gevent
(异步 worker,基于 gevent
库)
- 工作方式:
gevent
使用协程来管理并发请求。每个 worker 可以在同一时间处理多个请求。这种模式是异步的,使用gevent
库的轻量级协程来管理 I/O 任务。 - 适用场景:
- I/O 密集型应用:非常适合需要处理大量 I/O 操作的应用,如高并发的 Web 服务、实时消息应用等。因为
gevent
的协程模型允许在 I/O 等待时切换到其他任务,从而提高资源利用率。 - 高并发场景:当需要处理大量并发请求时,
gevent
worker 可以在不增加物理线程或进程的情况下通过异步 I/O 来提高并发处理能力。
- I/O 密集型应用:非常适合需要处理大量 I/O 操作的应用,如高并发的 Web 服务、实时消息应用等。因为
- 优点:
- 高效的并发处理:
gevent
的异步 I/O 模型使其能够处理大量并发请求,同时在 I/O 等待期间高效切换。 - 节省资源:与多进程或多线程模型相比,
gevent
协程的内存和 CPU 开销更小,允许更高的并发量。
- 高效的并发处理:
- 缺点:
- 需要支持异步 I/O:使用
gevent
需要确保所有 I/O 操作(如数据库驱动、HTTP 客户端等)支持异步 I/O,否则会阻塞整个协程。 - 复杂性增加:异步编程通常比同步编程更复杂,可能需要开发者对异步 I/O 和协程有更多了解。
- 需要支持异步 I/O:使用
如何选择 worker_class
?
- CPU 密集型应用(如数据处理、图像处理):选择
sync
worker 或者基于线程的 worker(如gthread
)。 - I/O 密集型应用(如 Web 服务、需要频繁进行数据库查询或 API 调用的应用):选择
gevent
或async
worker,以充分利用异步 I/O 的优势,提高并发性能。
示例配置
-
sync
worker 示例:worker_class = 'sync'
-
gevent
worker 示例:worker_class = 'gevent'
根据应用的特性和需求,选择合适的 worker_class
可以显著提高服务器的性能和并发处理能力。
二、worker_connections
worker_connections
参数在 Gunicorn 中用于设置每个 worker 允许的最大并发连接数。这个参数主要适用于异步 worker 类型,例如 gevent
和 eventlet
。
worker_connections
参数的作用
- 最大并发连接数:
worker_connections
决定了每个异步 worker(如gevent
)可以同时处理的最大连接数量。这些连接可以是客户端请求的连接,也可以是后台与其他服务(如数据库、缓存服务等)的连接。 - 适用对象:
worker_connections
只对异步 worker 有效,比如gevent
或eventlet
。对于同步 worker(sync
)或线程 worker(gthread
),这个参数没有意义。
使用 worker_connections
的场景
- 高并发 I/O 应用:如果你的应用是 I/O 密集型,并且需要处理大量并发连接,比如 WebSocket 服务、实时消息推送服务、需要与多个外部服务频繁交互的 API 服务器等,设置较高的
worker_connections
可以提升并发性能。 - 限制资源消耗:在某些情况下,你可能想限制单个 worker 的最大连接数,以防止某个 worker 消耗过多资源,影响其他 worker 的运行。
配置建议
- 合理的设置:默认情况下,
worker_connections
的值为 1000,这对于大多数应用来说已经足够了。根据你的应用特性(主要是 I/O 密集型应用)和服务器硬件资源,你可以调整这个值。 - 服务器性能:在设置
worker_connections
时,需要考虑服务器的性能(如 CPU、内存等)。较高的worker_connections
值意味着每个 worker 可以处理更多的并发连接,但也会占用更多的内存和 CPU 资源。
示例配置
在使用 gevent
时,如果你预计有非常高的并发连接量,可以这样配置:
import multiprocessing
# 绑定的 IP 和端口
bind = '0.0.0.0:8000'
# 使用 gevent 异步 worker
worker_class = 'gevent'
# 设置每个 worker 的最大并发连接数
worker_connections = 10000
# 根据 CPU 核心数设置合适的 worker 数量
workers = multiprocessing.cpu_count() * 2 + 1
注意事项
- 适度配置:虽然设置
worker_connections = 10000
能够处理更多的并发请求,但请确保你的应用和服务器可以承受这样的负载。过高的并发连接数会导致内存和 CPU 使用激增,可能会影响到服务器的整体性能。 - 监控和优化:部署后,应持续监控应用的性能和资源使用情况,根据实际情况调整
worker_connections
和其他相关参数,确保服务器稳定运行。
在选择合适的 worker_connections
值时,建议从默认值开始,并根据应用的实际需求和服务器性能逐步调整。
max_requests_jitter
和 keepalive
是 Gunicorn 配置文件中的两个参数,用于控制 worker 进程的生命周期和连接的保持策略。让我们分别了解这两个参数的作用和如何配置。
三、max_requests与keepalive
1. max_requests_jitter
-
作用:
max_requests_jitter
参数用于设置在max_requests
的基础上增加一个随机的抖动值。max_requests
是指每个 worker 在处理一定数量的请求后将会重启,以防止内存泄漏或其他资源问题。max_requests_jitter
的引入是为了避免所有 worker 同时重启,从而平滑系统的负载波动。 -
用法:
max_requests_jitter
的值是一个整数,它会被随机添加到max_requests
上。例如,如果max_requests
设置为 1000,而max_requests_jitter
设置为 2,那么每个 worker 在处理了 1000 到 1002(1000 + 随机[0, 2])之间的请求后将会重启。 -
示例:
max_requests = 1000 max_requests_jitter = 2
在这个配置中,每个 worker 将会在处理 1000 到 1002 个请求后重启。这种方式可以避免多个 worker 同时重启而带来的短暂服务不可用。
2. keepalive
-
作用:
keepalive
参数用于设置在连接空闲时,HTTP Keep-Alive 连接保持打开的秒数。这对于减少客户端和服务器之间的连接建立开销(如握手、SSL/TLS 协商等)非常有用,特别是在客户端会频繁发起多个请求的情况下。 -
用法:
keepalive
的值是一个整数,表示空闲连接保持打开的秒数。如果设置为 0,则表示关闭 HTTP Keep-Alive 功能,即每个请求结束后立即关闭连接。 -
配置建议:
- 适中值: 对于大多数应用程序,设置
keepalive
为 30 到 60 秒是一个合理的范围。这允许连接在短时间内被复用,从而减少握手开销和延迟。 - 长时间保持: 如果你的应用有较长时间的操作,或者希望减少连接重建开销,可以设置更长的保持时间,例如 120 秒。
- 短时间保持: 如果你希望服务器能够更快地释放连接资源,以便处理更多的客户端连接,可以设置一个较短的时间,例如 5 到 10 秒。
- 适中值: 对于大多数应用程序,设置
-
示例:
keepalive = 60
在这个配置中,每个空闲连接在 60 秒后会被关闭。如果客户端在这段时间内发起另一个请求,连接可以复用。
总结
max_requests_jitter
: 为了避免所有 worker 同时重启,平滑负载波动。keepalive
: 用于优化连接复用,减少连接建立开销。
在实际配置中,建议根据应用的负载特征、请求频率、网络环境等因素来调整这两个参数,以达到最佳的性能和稳定性。
四、我的项目中gunicorn_config示例
from imp import reload
import os
from distutils.util import strtobool
BASE_PATH = os.path.abspath(os.path.dirname(__file__))
# 指定应用
wsgi_app ='app:app'
# 是否让进入后台运行, docker内肯定设置False, 因为必须有一直前台运行的进程
daemon = False
#################debugging############
reload = False
#################logging############
# 设置进程文件目录
# pidfile = '/var/run/gunicorn.pid'
pidfile = os.path.join(BASE_PATH, 'gunicorn.pid')
# 设置访问日志输出文件地址, -表示输出到标准输出
accesslog = '-'
# 禁用将访问日志转发到syslog
disable_redirect_access_to_syslog = True
# 日志访问格式
access_log_format = '%(h)s %(l)s %(t)s %(p)s "%(r)s" %(U)s %(s)s %(l)s %(b)s %(l)s %(L)s'
# 设置错误日志访问地址, -表示输出到标准错误
errorlog = '-'
# 设置日志记录水平
loglevel = 'info'
# 是否重定向标准输出和标准错误到errorlog去, 默认是False
# capture_output = False
# 处理日志的日志类,下面是default的值
# logger_class = 'gunicorn.glogging.Logger'
# 配置logger的设置, 是不是这里可以设置日志旋转
# logconfig = None
# 通过字典配置logger,优先级高于logconfig
# logconfig_dict = {}
# 系统日志syslog地址
# syslog_addr = 'udp://localhost:514'
# 是否启动将gunicorn日志发送到syslog,默认False
# syslog = False
# statsd是一款数据采集程序, StatsD系统包括三部分:客户端(client)、服务器(server)和后端(backend)
# 如果设置了,就是把一些数据上送上去, 后面好分析
# statsd_host = None
# 也是关于statsd的设置
# dogstatsd_tags = ''
# 发出statsd度量时使用的前缀
# statsd_prefix = ''
#################server socket############
# 监听内网端口
bind = '0.0.0.0:8888'
# 最大等待连接的客户端数量
backlog = 2048
#################worker processes############
# worker数量. 实际就是进程数量
if os.environ.get('ENV', 'local') == 'local':
workers = int(os.environ.get('WORKERS', 2))
else:
workers = int(os.environ.get('WORKERS', 8))
# 工作模式协程
# worker_class = 'sync'
worker_class = 'gevent'
# 设置线程数量,这个参数只在worker类型是Gthread时有效
# 如果使用了sync类型worker,又设置threads大于1,则会使用gthread替代sync
# threads = 1
# 最大并发客户端数量, 这个设置仅影响Eventlet and Gevent worker类型
worker_connections = 10000
# 一个worker在处理一定数量的request后可以让他自动重启, 这是一种帮助限制内存泄漏损害的简单方法. 默认是0, 禁用这个功能
# max_requests = 0
# 这是为了错开worker重启以避免所有worker同时重启,导致服务不可用
max_requests_jitter = 2
# gunicorn 给子进程的执行时间,如果超过这个限制就会被父进程kill掉,然后重启一个新的。
# 比如处理一个请求30秒内worker不能进行返回结果,gunicorn就认定这个request超时,终止worker继续执行,向客户端返回出错的信息,
# 用于避免系统出现异常时,所有worker都被占住,无法处理更多的正常request,导致整个系统无法访问
# 所以可以检查一下为什么这个request会耗那么久的时间(超过30秒),如果是正常的话,可以适当调高gunicorn的超时限制或者使用异步的worker,
# 如果是系统处理速度遇到瓶颈,那可能要从数据库,缓存,算法等各个方面来提升速度。
timeout = 200 #这个参数只对woker是sync方式起作用
# 优雅关闭,指接收到重启信号, 工作进程不是立马被杀死重启,而是等待一定时间处理可能正在处理的任务,然后才重启
# graceful_timeout = 150
keepalive = 60
#################server Hooks############
# def on_starting(server):
# '''
# 这个是主进程启动时会被调用
# '''
# pass
# def on_reload(server):
# '''
# Called to recycle workers during a reload via SIGHUP.
# '''
# pass
# def when_ready(sever):
# '''
# 当gunicorn准备就绪, 坐等请求过来时调用
# '''
# pass
# def pre_fork(sever, worker):
# '''
# 创建子进程之前调用, 有几个子进程就应该被调用几次
# '''
# pass
# def post_fork(sever, worker):
# '''
# 子进程创建成功了被调用,有几个成功就被调用几次
# '''
# pass
# def post_worker_init(worker):
# '''
# worker进程初始化完成application
# '''
# pass
# def worker_int(worker):
# '''
# 接收到SIGINT or SIGQUIT信号时,工作进程退出调用
# '''
# pass
# def worker_abort(worker):
# '''
# 接收到SIGABRT信号时被调用,通常发生timeout时,处理请求耗费时间超过了设置的timeout值,
# 这里应该主动上报错误,定位为什么处理那么长时间
# '''
# pass
# def pre_exec(server):
# '''
# 一个新的master进程forked时调用
# '''
# pass
# def pre_request(worker, req):
# '''
# 在worker开始处理请求前调用
# '''
# pass
# def post_request(worker, req, environ, resp):
# '''
# 处理完成请求时调用
# '''
# pass
# def child_exit(sever, worker):
# '''
# Called just after a worker has been exited, in the master process.
# '''
# pass
# def worker_exit(server, worker):
# '''
# 工作进程退出时调用
# '''
# pass
# def nworkers_changed(server, new_value, old_value):
# '''
# workers的数量发生改变时被调用
# '''
# pass
# def on_exit(server):
# '''
# gunicorn退出时调用
# '''
# pass
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)