Gunicorn: 运行 Flask 应用程序时的关键工作人员超时

创建于 2018-06-05  ·  82评论  ·  资料来源: benoitc/gunicorn

似乎已经有几个与[CRITICAL] WORKER TIMEOUT错误相关的报告,但它只是不断弹出。 这是我的问题。

我正在运行这个 Flask hello world 应用程序。

from flask import Flask
application = Flask(__name__)

@application.route('/')
def hello_world():
    return 'Hello, World!'

gunicorn 命令是这样的:

gunicorn -b 0.0.0.0:5000 --log-level=debug hello

这是控制台输出:

[2018-06-05 14:56:21 +0200] [11229] [INFO] Starting gunicorn 19.8.1
[2018-06-05 14:56:21 +0200] [11229] [DEBUG] Arbiter booted
[2018-06-05 14:56:21 +0200] [11229] [INFO] Listening at: http://0.0.0.0:5000 (11229)
[2018-06-05 14:56:21 +0200] [11229] [INFO] Using worker: sync
[2018-06-05 14:56:21 +0200] [11232] [INFO] Booting worker with pid: 11232
[2018-06-05 14:56:21 +0200] [11229] [DEBUG] 1 workers
[2018-06-05 14:56:32 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:56:57 +0200] [11232] [DEBUG] Closing connection. 
[2018-06-05 14:57:16 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:57:47 +0200] [11229] [CRITICAL] WORKER TIMEOUT (pid:11232)
[2018-06-05 14:57:47 +0200] [11232] [INFO] Worker exiting (pid: 11232)
[2018-06-05 14:57:47 +0200] [11324] [INFO] Booting worker with pid: 11324

您能否清楚地解释一下为什么我会收到错误以及是否在此示例中出现错误? 我该如何修复它,或者如果它是预期的行为,那么为什么会出现严重错误?

Investigation unconfirmed

最有用的评论

将 gunicorn 与 gevent 一起使用并没有修复该错误。

所有82条评论

该错误不是预期的,但是您的示例中没有任何内容可以说明它为什么会发生。 告诉我们更多有关您的环境的信息。

  • 使用什么客户端连接到 Gunicorn?
  • 使用什么反向代理(如果有)连接到 Gunicorn?

告诉我们更多有关您的环境的信息。

  • 使用什么客户端连接到 Gunicorn?
    => 我只是从 Chromium 发送请求: http://localhost :5000/
  • 使用什么反向代理(如果有)连接到 Gunicorn?
    => 没有代理,只有 Gunicorn + Flask

我刚刚在一个全新的设置上重现了这个问题,以下是步骤:

mkdir gunicorn
cd gunicorn/
pipenv --python 3.6
pipenv install flask
pipenv install gunicorn
vim hello.py
pipenv shell
gunicorn -b 0.0.0.0:5000 --log-level=debug hello

hello.py与我在初始报告中发布的 Flask 应用程序完全相同。
下面是完整的日志。

~$ gunicorn -b 0.0.0.0:5000 --log-level=debug hello
[2018-06-06 09:16:21 +0200] [19829] [DEBUG] Current configuration:
  config: None
  bind: ['0.0.0.0:5000']
  backlog: 2048
  workers: 1
  worker_class: sync
  threads: 1
  worker_connections: 1000
  max_requests: 0
  max_requests_jitter: 0
  timeout: 30
  graceful_timeout: 30
  keepalive: 2
  limit_request_line: 4094
  limit_request_fields: 100
  limit_request_field_size: 8190
  reload: False
  reload_engine: auto
  reload_extra_files: []
  spew: False
  check_config: False
  preload_app: False
  sendfile: None
  reuse_port: False
  chdir: /home/dima/work/gunicorn
  daemon: False
  raw_env: []
  pidfile: None
  worker_tmp_dir: None
  user: 1000
  group: 985
  umask: 0
  initgroups: False
  tmp_upload_dir: None
  secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
  forwarded_allow_ips: ['127.0.0.1']
  accesslog: None
  disable_redirect_access_to_syslog: False
  access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
  errorlog: -
  loglevel: debug
  capture_output: False
  logger_class: gunicorn.glogging.Logger
  logconfig: None
  logconfig_dict: {}
  syslog_addr: udp://localhost:514
  syslog: False
  syslog_prefix: None
  syslog_facility: user
  enable_stdio_inheritance: False
  statsd_host: None
  statsd_prefix: 
  proc_name: None
  default_proc_name: hello
  pythonpath: None
  paste: None
  on_starting: <function OnStarting.on_starting at 0x7f9757112d08>
  on_reload: <function OnReload.on_reload at 0x7f9757112e18>
  when_ready: <function WhenReady.when_ready at 0x7f9757112f28>
  pre_fork: <function Prefork.pre_fork at 0x7f9756c230d0>
  post_fork: <function Postfork.post_fork at 0x7f9756c231e0>
  post_worker_init: <function PostWorkerInit.post_worker_init at 0x7f9756c232f0>
  worker_int: <function WorkerInt.worker_int at 0x7f9756c23400>
  worker_abort: <function WorkerAbort.worker_abort at 0x7f9756c23510>
  pre_exec: <function PreExec.pre_exec at 0x7f9756c23620>
  pre_request: <function PreRequest.pre_request at 0x7f9756c23730>
  post_request: <function PostRequest.post_request at 0x7f9756c237b8>
  child_exit: <function ChildExit.child_exit at 0x7f9756c238c8>
  worker_exit: <function WorkerExit.worker_exit at 0x7f9756c239d8>
  nworkers_changed: <function NumWorkersChanged.nworkers_changed at 0x7f9756c23ae8>
  on_exit: <function OnExit.on_exit at 0x7f9756c23bf8>
  proxy_protocol: False
  proxy_allow_ips: ['127.0.0.1']
  keyfile: None
  certfile: None
  ssl_version: 2
  cert_reqs: 0
  ca_certs: None
  suppress_ragged_eofs: True
  do_handshake_on_connect: False
  ciphers: TLSv1
  raw_paste_global_conf: []
[2018-06-06 09:16:21 +0200] [19829] [INFO] Starting gunicorn 19.8.1
[2018-06-06 09:16:21 +0200] [19829] [DEBUG] Arbiter booted
[2018-06-06 09:16:21 +0200] [19829] [INFO] Listening at: http://0.0.0.0:5000 (19829)
[2018-06-06 09:16:21 +0200] [19829] [INFO] Using worker: sync
[2018-06-06 09:16:21 +0200] [19832] [INFO] Booting worker with pid: 19832
[2018-06-06 09:16:22 +0200] [19829] [DEBUG] 1 workers
[2018-06-06 09:16:48 +0200] [19832] [DEBUG] GET /
[2018-06-06 09:17:19 +0200] [19829] [CRITICAL] WORKER TIMEOUT (pid:19832)
[2018-06-06 09:17:19 +0200] [19832] [INFO] Worker exiting (pid: 19832)
[2018-06-06 09:17:19 +0200] [19872] [INFO] Booting worker with pid: 19872
^C[2018-06-06 09:17:26 +0200] [19829] [INFO] Handling signal: int
[2018-06-06 09:17:26 +0200] [19872] [INFO] Worker exiting (pid: 19872)
[2018-06-06 09:17:26 +0200] [19829] [INFO] Shutting down: Master
~$ pip list
Package      Version
------------ -------
click        6.7    
Flask        1.0.2  
gunicorn     19.8.1 
itsdangerous 0.24   
Jinja2       2.10   
MarkupSafe   1.0    
pip          10.0.1 
setuptools   39.2.0 
Werkzeug     0.14.1 
wheel        0.31.1

@bigunyak我认为这是因为默认超时,您的工作人员已经沉默了 30 秒。 http://docs.gunicorn.org/en/stable/settings.html#timeout

从你的日志中,

[2018-06-05 14:57:16 +0200] [11232] [DEBUG] GET /
[2018-06-05 14:57:47 +0200] [11229] [CRITICAL] WORKER TIMEOUT (pid:11232)
[2018-06-06 09:16:48 +0200] [19832] [DEBUG] GET /
[2018-06-06 09:17:19 +0200] [19829] [CRITICAL] WORKER TIMEOUT (pid:19832)

我看到了同样的事情:即使在没有请求的情况下,工作人员也会超时,使用同步工作人员。
从这个意义上说,临界级别日志相当混乱。

尝试使用 Gevent worker 可以解决这个问题。

从这个意义上说,临界级别日志相当混乱。

没错,那是我最初的问题:如果这是预期的行为,那么为什么会出现严重错误?
获得一些关于为什么需要重新启动工作人员的背景知识也很好,也许这可以添加到设计文档中。

我也看到了这一点(通过使用examples/test.pygunicorn test:app -b localhost:9595 --log-level=debug --timeout=5复制),我同意临界级别有点令人困惑。 我可以将其更改为调试级别。 @benoitc @tilgovi你怎么看?

我认为信息级别可能会好一点。

我在 Win10 上的 MSYS2 也有同样的问题,但最终可以解决。

在...\gunicorn\workers\workertmp.py的notify()中,最初使用的是os.fchmod。 但它在 MSYS 中不起作用。 我没有使用 os.fchmod,而是使用了 os.utime。 代码如下。 我认为它适用于所有平台。

    def notify(self):
        try:
            self.spinner = (self.spinner + 1) % 2
            os.fchmod(self._tmp.fileno(), self.spinner)
            if PLATFORM.startswith('MSYS') :
                os.utime(self._tmp.fileno(), None)
        except AttributeError:
            # python < 2.6
            self._tmp.truncate(0)
            os.write(self._tmp.fileno(), b"X")

@berkerpeksag我不希望工作人员因为没有请求发生而退出。 仅当工作人员忙了一段时间 > 到超时时,才会发生此错误。 所以这个错误很关键。 Imo 我们应该改进文档以提供更多用例和对此类错误的响应。

如果在工作人员不忙时错误仍然发生,那么还有其他事情发生,我们可能有错误。

[编辑]
对我来说同样的错误。
使用 Django 1.10 / gunicorn 19.6.0 / Python 2.7.15 在 Debian 8.8 上的 python2.7-alpine 和股票内核 3.16,一切正常。
更新到 Django 1.11 和 gunicorn 19.8.1 后,工作人员在启动时不断失败,并显示 [CRITICAL WORKER TIMEOUT]。
将 gunicorn 降级到 19.6.0 并不能解决问题。
我们将主机内核更新为 4.9.0(已安排),并且工作程序成功启动且没有错误。
但:

  • 我们使用 4 名工人
  • 在对 Django 应用程序进行 4 次调用后,下一次调用将超时,并在日志中显示 [CRITICAL WORKER TIMEOUT]
  • linux top 命令显示 4 个 gunicorn 进程卡住了相当高的 CPU 消耗。

我们将尝试使用 gunicorn gevent 来查看我们是否能够让我们的应用重新上线。

将 gunicorn 与 gevent 一起使用并没有修复该错误。

关于这个问题的任何更新?

看起来@neocolor在 MSYS 下发现了一个真正的错误。 它可能值得一个单独的问题。

@bigunyak你在什么平台下运行? 我试图用这个简单的例子来重现,但我不能完全按照上面列出的步骤来做。 这与我在多个框架上在生产中运行多个应用程序的经验一致。 据我所知,工人通知系统最近没有改变。 我的平台是 MacOS 10.13.6 上的 Python 3.7,但我在生产中运行 Gunicorn 并在 Python 2.7 和 3.6.5 上为多个应用程序同步工作线程,并且只有在有合法的长请求阻塞工作线程时才会看到工作线程超时。

对于@Tberdy :如果您尝试将--worker-tmp-dir设置

有关 Docker 相关的 tmpfs 问题,另请参阅 #1388。

我有这个问题。

我也有这个问题,直到昨天晚上,gunicorn 同步都运行良好,然后开始报告,使用 gevent 的工人超时 [CRITICAL] 似乎解决了我的问题,但我真的很想知道为什么会这样。

@timoj58 @cjmash你能提供更多关于这个问题的细节吗? 你如何运行 gunicorn(在虚拟机中?,选项......),哪个文件系统,操作系统? 可以帮助复制的东西会非常有帮助:)

@benoitc我正在运行 gunicorn 在 kubernetes 上启动我的 Django 项目我的 gunicorn 参数是 --bind=$port --workers=7 --timeout=1200 --log-level=debug --access-logfile - error-logfile - ”

我从日志中得到的错误

```E [2018-08-09 21:47:56 +0000] [13] [INFO] 使用 pid 启动 worker:13

E [2018-08-09 21:47:56 +0000] [14] [INFO] 使用 pid 启动 worker:14

E [2018-08-09 21:47:56 +0000] [12] [INFO] 使用 pid 启动 worker:12

E [2018-08-09 21:47:56 +0000] [1] [DEBUG] 7 个工人

E [2018-08-09 21:47:56 +0000] [11] [INFO] pid: 11

E [2018-08-09 21:47:55 +0000] [10] [INFO] 使用 pid: 10 的引导工人

E [2018-08-09 21:47:55 +0000] [9] [INFO] 使用 pid 启动 worker:9

E [2018-08-09 21:47:55 +0000] [8] [INFO] 使用 pid 启动 worker:8

E [2018-08-09 21:47:55 +0000] [1] [INFO] 使用工人:同步

E [2018年8月9日21时47分55秒0000] [1] [INFO]听力于: http://0.0.0.0 :4040(1)

E [2018-08-09 21:47:55 +0000] [1] [DEBUG] 仲裁器启动

E [2018-08-09 21:47:55 +0000] [1] [INFO]启动gunicorn 19.7.1

E raw_paste_global_conf: []

E 密码:TLSv1

E do_handshake_on_connect: 假

E suppress_ragged_eofs: 真

E ca_certs:无

E cert_reqs: 0

E ssl_version: 2

E 证书文件:无

E 密钥文件:无

E proxy_allow_ips: ['127.0.0.1']

E proxy_protocol: 假

E on_exit:

Enworkers_changed:

E worker_exit:

E child_exit:

E post_request:

E 预请求:

E pre_exec:

E worker_abort:

E worker_int:

E post_worker_init:

E post_fork:

E pre_fork:

E when_ready:

E on_reload:

E on_starting:

E贴:无

E pythonpath:无

E default_proc_name: art.wsgi

E proc_name: 无

E statsd_prefix:

E statsd_host:无

E enable_stdio_inheritance: 假

E syslog_facility: 用户

E syslog_prefix:无

E 系统日志:错误

E syslog_addr: udp://localhost :514

E 日志配置:无

E logger_class: gunicorn.glogging.Logger

E 捕获输出:假

E 日志级别:调试

E 错误日志:-

E access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(作为”

E 访问日志:-

E forwarded_allow_ips: ['127.0.0.1']

E secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}

E tmp_upload_dir: 无

E initgroups:假

E umask: 0

E组:0

E用户:0

E worker_tmp_dir: 无

E pidfile: 无

E raw_env: []

E 守护进程:错误

E chdir: /usr/src/app

E 发送文件:无

E preload_app: 假

E check_config: 假

E 喷出:错误

E reload_engine: 自动

E 重新加载:错误

E limit_request_field_size: 8190

E limit_request_fields: 100

E limit_request_line: 4094

E保活:2

E 优雅超时:30

E 超时:1200

E max_requests_jitter: 0

E 最大请求数:0

E worker_connections: 1000

E 线程:1

E worker_class:同步

E工:7人

E 积压:2048

E 绑定:['0.0.0.0:4040']

E 配置:无

E [2018-08-09 21:47:55 +0000] [1] [DEBUG] 当前配置:

I 没有可申请的迁移。

I 运行迁移:

我应用所有迁移:admin、auth、contenttypes、core、dashboard、jet、oauth2_provider、sessions

I 执行的操作:

E [2018-08-09 21:47:20 +0000] [13] [INFO] 工人退出 (pid: 13)

E os.path.dirname(os.path.dirname(__file__)), '.env'))

E /usr/src/app/art/wsgi.py:19: UserWarning: Not reading /usr/src/app/.env - 它不存在。

E [2018-08-09 21:47:00 +0000] [21] [INFO] 使用 pid 引导工人:21

E [2018-08-09 21:47:00 +0000] [1] [INFO] 处理信号:术语

E [2018-08-09 21:46:35 +0000] [12] [INFO] 使用 pid 启动 worker:12

E [2018-08-09 21:46:34 +0000] [13] [INFO] 使用 pid 启动 worker:13

E [2018-08-09 21:46:34 +0000] [11] [INFO] 使用 pid: 11 的引导工人

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] 7 个工人

E [2018-08-09 21:46:34 +0000] [10] [INFO] 使用 pid 引导工人:10

E [2018-08-09 21:46:34 +0000] [9] [INFO] 使用 pid 启动 worker:9

E [2018-08-09 21:46:34 +0000] [8] [INFO] 使用 pid 启动 worker:8

E [2018-08-09 21:46:34 +0000] [7] [INFO] 使用 pid 启动 worker:7

E [2018-08-09 21:46:34 +0000] [1] [INFO] 使用工人:同步

E [2018-08-09 21:46:34 +0000] [1] [INFO] 听:http: //0.0.0.0 :4040 (1)

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] 仲裁器启动

E [2018-08-09 21:46:34 +0000] [1] [INFO]启动gunicorn 19.7.1

E raw_paste_global_conf: []

E 密码:TLSv1

E do_handshake_on_connect: 假

E suppress_ragged_eofs: 真

E ca_certs:无

E cert_reqs: 0

E ssl_version: 2

E 证书文件:无

E 密钥文件:无

E proxy_allow_ips: ['127.0.0.1']

E proxy_protocol: 假

E on_exit:

Enworkers_changed:

E worker_exit:

E child_exit:

E post_request:

E 预请求:

E pre_exec:

E worker_abort:

E worker_int:

E post_worker_init:

E post_fork:

E pre_fork:

E when_ready:

E on_reload:

E on_starting:

E贴:无

E pythonpath:无

E default_proc_name: art.wsgi

E proc_name: 无

E statsd_prefix:

E statsd_host:无

E enable_stdio_inheritance: 假

E syslog_facility: 用户

E syslog_prefix:无

E 系统日志:错误

E syslog_addr: udp://localhost :514

E 日志配置:无

E logger_class: gunicorn.glogging.Logger

E 捕获输出:假

E 日志级别:调试

E 错误日志:-

E access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(作为”

E 访问日志:-

E forwarded_allow_ips: ['127.0.0.1']

E secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}

E tmp_upload_dir: 无

E initgroups:假

E umask: 0

E组:0

E用户:0

E worker_tmp_dir: 无

E pidfile: 无

E raw_env: []

E 守护进程:错误

E chdir: /usr/src/app

E 发送文件:无

E preload_app: 假

E check_config: 假

E 喷出:错误

E reload_engine: 自动

E 重新加载:错误

E limit_request_field_size: 8190

E limit_request_fields: 100

E limit_request_line: 4094

E保活:2

E 优雅超时:30

E 超时:1200

E max_requests_jitter: 0

E 最大请求数:0

E worker_connections: 1000

E 线程:1

E worker_class:同步

E工:7人

E 积压:2048

E 绑定:['0.0.0.0:4040']

E 配置:无

E [2018-08-09 21:46:34 +0000] [1] [DEBUG] 当前配置:

``

这次我努力重现这个问题,但它仍然存在于最新的 gunicorn 版本 19.9.0 中。
重现它的步骤与我在这篇文章中描述的完全相同。
我的系统是 Arch Linux x86_64 GNU/Linux(内核 4.17.2-1-ARCH),Python 3.6.5
这是一个新的日志跟踪。

~$ gunicorn -b 0.0.0.0:5000 --log-level=debug hello
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] Current configuration:
  config: None
  bind: ['0.0.0.0:5000']
  backlog: 2048
  workers: 1
  worker_class: sync
  threads: 1
  worker_connections: 1000
  max_requests: 0
  max_requests_jitter: 0
  timeout: 30
  graceful_timeout: 30
  keepalive: 2
  limit_request_line: 4094
  limit_request_fields: 100
  limit_request_field_size: 8190
  reload: False
  reload_engine: auto
  reload_extra_files: []
  spew: False
  check_config: False
  preload_app: False
  sendfile: None
  reuse_port: False
  chdir: /home/dima/lerning/python/modules/gunicorn
  daemon: False
  raw_env: []
  pidfile: None
  worker_tmp_dir: None
  user: 1000
  group: 985
  umask: 0
  initgroups: False
  tmp_upload_dir: None
  secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
  forwarded_allow_ips: ['127.0.0.1']
  accesslog: None
  disable_redirect_access_to_syslog: False
  access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
  errorlog: -
  loglevel: debug
  capture_output: False
  logger_class: gunicorn.glogging.Logger
  logconfig: None
  logconfig_dict: {}
  syslog_addr: udp://localhost:514
  syslog: False
  syslog_prefix: None
  syslog_facility: user
  enable_stdio_inheritance: False
  statsd_host: None
  statsd_prefix: 
  proc_name: None
  default_proc_name: hello
  pythonpath: None
  paste: None
  on_starting: <function OnStarting.on_starting at 0x7f5f8b9dad08>
  on_reload: <function OnReload.on_reload at 0x7f5f8b9dae18>
  when_ready: <function WhenReady.when_ready at 0x7f5f8b9daf28>
  pre_fork: <function Prefork.pre_fork at 0x7f5f8b4ec0d0>
  post_fork: <function Postfork.post_fork at 0x7f5f8b4ec1e0>
  post_worker_init: <function PostWorkerInit.post_worker_init at 0x7f5f8b4ec2f0>
  worker_int: <function WorkerInt.worker_int at 0x7f5f8b4ec400>
  worker_abort: <function WorkerAbort.worker_abort at 0x7f5f8b4ec510>
  pre_exec: <function PreExec.pre_exec at 0x7f5f8b4ec620>
  pre_request: <function PreRequest.pre_request at 0x7f5f8b4ec730>
  post_request: <function PostRequest.post_request at 0x7f5f8b4ec7b8>
  child_exit: <function ChildExit.child_exit at 0x7f5f8b4ec8c8>
  worker_exit: <function WorkerExit.worker_exit at 0x7f5f8b4ec9d8>
  nworkers_changed: <function NumWorkersChanged.nworkers_changed at 0x7f5f8b4ecae8>
  on_exit: <function OnExit.on_exit at 0x7f5f8b4ecbf8>
  proxy_protocol: False
  proxy_allow_ips: ['127.0.0.1']
  keyfile: None
  certfile: None
  ssl_version: 2
  cert_reqs: 0
  ca_certs: None
  suppress_ragged_eofs: True
  do_handshake_on_connect: False
  ciphers: TLSv1
  raw_paste_global_conf: []
[2018-08-10 09:48:40 +0200] [23114] [INFO] Starting gunicorn 19.9.0
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] Arbiter booted
[2018-08-10 09:48:40 +0200] [23114] [INFO] Listening at: http://0.0.0.0:5000 (23114)
[2018-08-10 09:48:40 +0200] [23114] [INFO] Using worker: sync
[2018-08-10 09:48:40 +0200] [23117] [INFO] Booting worker with pid: 23117
[2018-08-10 09:48:40 +0200] [23114] [DEBUG] 1 workers
[2018-08-10 09:48:45 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:48:54 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:00 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:18 +0200] [23117] [DEBUG] Closing connection. 
[2018-08-10 09:49:18 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:23 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:37 +0200] [23117] [DEBUG] Closing connection. 
[2018-08-10 09:49:37 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:49:50 +0200] [23117] [DEBUG] Closing connection. 
[2018-08-10 09:51:11 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:51:13 +0200] [23117] [DEBUG] GET /
[2018-08-10 09:51:43 +0200] [23114] [CRITICAL] WORKER TIMEOUT (pid:23117)
[2018-08-10 09:51:43 +0200] [23117] [INFO] Worker exiting (pid: 23117)
[2018-08-10 09:51:44 +0200] [23229] [INFO] Booting worker with pid: 23229

和之前一样,我只是在 Chromium 中点击了http://0.0.0.0 :5000/ 来测试它。
下面是 Pipfile 和 Pipfile.lock 的内容,供大家查看具体环境。

  • 文件
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
flask = "*"
gunicorn = "*"

[dev-packages]

[requires]
python_version = "3.6"
  • pipfile.lock
{
    "_meta": {
        "hash": {
            "sha256": "81cb5d5f0b11719d8d9c5ec9cc683fdcf959c652fda256d5552a82d0f459a99c"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.6"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "click": {
            "hashes": [
                "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
                "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
            ],
            "version": "==6.7"
        },
        "flask": {
            "hashes": [
                "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
                "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
            ],
            "index": "pypi",
            "version": "==1.0.2"
        },
        "gunicorn": {
            "hashes": [
                "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471",
                "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3"
            ],
            "index": "pypi",
            "version": "==19.9.0"
        },
        "itsdangerous": {
            "hashes": [
                "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
            ],
            "version": "==0.24"
        },
        "jinja2": {
            "hashes": [
                "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
                "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
            ],
            "version": "==2.10"
        },
        "markupsafe": {
            "hashes": [
                "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
            ],
            "version": "==1.0"
        },
        "werkzeug": {
            "hashes": [
                "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
                "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
            ],
            "version": "==0.14.1"
        }
    },
    "develop": {}
}

仅供参考,我也经常看到这种失败:

nohup gunicorn -w 8 --access-logfile=- --bind 127.0.0.1:5000 wsgi &

我只有一个 wsgi.py

from chart_api import application
if __name__ == "__main__":
    application.run()

如果您希望我尝试/实验任何内容,或者您​​希望我检查日志中的具体内容,请告诉我。 我在 GCP VM 上运行 Flask。

抱歉回复晚了。 我正在运行它

gunicorn --log-file=/home/ubuntu/log/gunicorn.log predictor_ api:app -b localhost:5000 &

我确实使用了 gevent 设置等,但是为了解决问题,我已经改变了我需要它的设计,因此上面的基本设置(也失败了,但如果没有 gevent,这是可以预料的)

Python 3.6 版
环境:aws tensorflow_p36 优化(ubuntu)
nginx 坐在 gunicorn 前面,它正在执行一个烧瓶应用程序。

烧瓶版本 1.0.2
nginx 版本 1.10.3
gunicorn 版本 19.9.0

我确实更改了 nginx 超时,以防万一这可能导致它。

gunicorn服务器面临同样的问题

# gunicorn Applicat ionServer:app -b 0.0.0.0:6001 -w 8 --threads 4 --backlog 2048 \
# --timeout 120 --graceful-timeout 60 --access-logfile logs/access.log \

--error-logfile 日志/error.log --log-level=info

烧瓶==0.12.1
枪炮==19.7.1

当我使用上述命令启动服务器时,我的系统冻结了一段时间并且工作进程 pid 继续启动,尽管我保持超时 120 秒,并且服务器不接受单个请求。

关于这个问题的任何更新? 我有同样的问题

[关键] 工人超时

想知道是否有人在 Docker 镜像中成功复制了这个?

在以 gunicorn -k gevent --threads 4 开头的现有应用程序上尝试实现 datadog 的 ddtrace-run worker 时也会看到这一点。

我以前从未见过的 SystemExit 的有趣痕迹......
[2018-11-07 11:11:50 +0000] [15987] [INFO] Booting worker with pid: 15987 [2018-11-07 11:11:50 +0000] [15977] [DEBUG] 1 workers [2018-11-07 11:12:20 +0000] [15977] [CRITICAL] WORKER TIMEOUT (pid:15987) Exception SystemExit: 1 in <bound method LibevLoop._loop_will_run of <cassandra.io.libevreactor.LibevLoop object at 0x7f3cb66d4a50>> ignored

我可以通过匹配工作线程数和线程数来解决这个问题。

我已经设置了workers = (2 * cpu_count) + 1并且没有设置线程。

一旦我改变了threads = workers ,一切就开始正常了。 以防万一,如果这对某人有帮助。

这是现在的样子

def run(host='0.0.0.0', port=8080, workers=1 + (multiprocessing.cpu_count() * 2)):
    """Run the app with Gunicorn."""

    if app.debug:
        app.run(host, int(port), use_reloader=False)
    else:
        gunicorn = WSGIApplication()
        gunicorn.load_wsgiapp = lambda: app
        gunicorn.cfg.set('bind', '%s:%s' % (host, port))
        gunicorn.cfg.set('workers', workers)
        gunicorn.cfg.set('threads', workers)
        gunicorn.cfg.set('pidfile', None)
        gunicorn.cfg.set('worker_class', 'sync')
        gunicorn.cfg.set('keepalive', 10)
        gunicorn.cfg.set('accesslog', '-')
        gunicorn.cfg.set('errorlog', '-')
        gunicorn.cfg.set('reload', True)
        gunicorn.chdir()
        gunicorn.run()

我在 AWS Elastic Beanstalk 上使用单个 Docker 容器运行 Django 时遇到了这个问题。 我通过修复我的安全组解决了这个问题,以确保我的 EC2 实例可以与我的 RDS 实例通信。 我意识到这可能不是 99% 的人在这个问题上的解决方案,但我留下这个笔记是为了帮助其他人避免在这个兔子洞中浪费时间。

在我的情况下,问题是通过执行systemctl daemon-reload
长话短说,我知道默认超时为 30 秒,但无法更改它,直到我认为我当然必须重新加载 systemd 守护程序才能将更改应用于服务。

@bigunyak @benoitc @tilgovi
经过长时间的 google goose 追逐和一些实验,我相信这个问题的根本原因是 chrome 的“预连接/预测服务”(Chrome 和 Chromium 中默认启用)。

@jeiting对这个问题写了一篇很好的文章
https://hackernoon.com/chrome-preconnect-breaks-singly-threaded-servers-95944be16400
一些补充阅读:
https://github.com/corydolphin/flask-cors/issues/147
https://github.com/pallets/flask/issues/2169

TLDR
在某些情况下,Chrome/Chromium 会打开并保持一个“空”的 TCP 连接(即它预测它将很快获取另一个资源)。 如果“空”TCP 连接首先访问您的 gunicorn 服务器,则来自 chrome 的任何后续“真实”请求都可能卡在“空”请求后面,直到处理“空”请求的工作人员超时为止。 如果您只在 gunicorn 中运行单个同步工作线程,则更有可能发生这种情况。 但是正如我的实验发现的那样,即使您正在运行多个同步工作器,它也可能发生。

我的环境

  • 我的原生操作系统是 Ubuntu 17
  • 我有一个在本地 docker 容器中运行的 rest API。 来自 Dockefile 的相关行
FROM ubuntu:18.04
...
RUN pip3 install Flask==1.0.2
RUN pip3 install gunicorn==19.9.0
RUN pip3 install flask-cors==3.0.6
......
  • 我安装了 3 个浏览器:Firefox 61.0.1、Chromium 67.0.3396.99、Chrome 70.0.3538.102
  • 我有一个反应应用程序,它由不同端口上的不同 docker 容器提供
  • react 应用程序向我的 API 发出 CORS AJAX 请求(它们是 CORS 请求,因为 javascript 在一个本地主机端口上提供服务,同时将 API 调用发送到另一个本地主机端口)
  • 在我的实验中总是被“阻止”的请求是 CORS OPTIONS 请求(由浏览器触发以请求许可然后执行 POST 请求)。 浏览器尝试与 OPTIONS 调用建立预测连接似乎是合乎逻辑的,因为它可能会跟进 POST 调用。

实验一
Gunicorn 配置:1 个同步工作器(默认 30 秒超时)

Firefox:几乎在每次反应页面加载时,CORS OPTIONS 请求都会被阻止 5 秒,然后成功。
Chromium:在每次响应页面加载时,CORS OPTIONS 请求都会被阻止 1.5 分钟!!! 然后成功。
Chromium(预测服务已禁用):一切正常
Chrome:一切正常

实验二
Gunicorn 配置:4 个同步工作者(默认 30 秒超时)

Firefox:一切正常
Chromium:在每 3 次反应页面加载时,CORS OPTIONS 请求被阻止 30 秒然后成功。
Chromium(预测服务已禁用):一切正常
Chrome:一切正常

实验三
Gunicorn 配置:8 个同步工作者(默认 30 秒超时)

Firefox:一切正常
Chromium:一切正常
Chrome:一切正常

实验四
使用threaded=True运行 Flask 开发服务器

Firefox:一切正常
Chromium:一切正常
Chrome:一切正常

实验总结

  • Firefox 似乎也有预测服务,但看起来更优雅。 (实验一)
  • Chromium 在创建“预测”连接方面似乎是最积极的。 它似乎在 OPTIONS 请求期间最多启动 3-4 个“预测”连接(实验 1 和 2)
  • 令人惊讶的是,即使 Chrome 也启用了预测服务,它在任何实验中都没有引起任何问题(可能“预测”连接的顺序或数量与 Chromium 不同)

解决方案
在生产中:最简单的解决方法是将 nginx 放在 gunicorn 前面。 如果您想了解 nginx 解决此问题的原因,这里有一篇很好的文章解释了它: https :

在开发中:最简单的解决方法是使用threaded=True运行 Flask 开发服务器。 或者您可以在 Chrome/Chromium 中禁用预测服务。

gunicorn 调试改进
为了在将来帮助调试此类问题,我认为最好在同步工作线程中的select()accept()调用旁边添加调试日志语句。
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L26
https://github.com/benoitc/gunicorn/blob/e974f30517261b2bc95cfb2017a8688f367c8bf3/gunicorn/workers/sync.py#L34
这将表明工作人员已接受新的 TCP 连接,但未接收任何数据。

@asnisarenko超级写,谢谢。 #1929 是另一个不寻常的慢客户端案例,它在单线程服务器中产生类似的症状 - 在这种情况下,TLS 与非 TLS 端口的握手看起来像一个写入缓慢的客户端,因为它无法快速发送合理的标头.

它可能是 Gunicorn,因为单线程同步工作者将需要一些新的可调参数,对于在合理时间内无法发送至少第一个请求标头行(如果不是所有标头)的客户端的积极客户端丢弃。

如果您的应用发生这种情况,您可以添加一些临时诊断代码:

def trace_on_abort():
    import signal
    import traceback

    def print_trace(sig, frame):
        print(''.join(traceback.format_stack(frame)))

    signal.signal(signal.SIGABRT, print_trace)

希望这应该揭示您的应用程序挂在哪里。

例如,我总算import flask之前gevent.monkey.patch_all()所以我的瓶的app._before_request_lock结束了非GEVENT锁(即普通未打补丁的threading.Lock )。 在这种情况下,在应用程序启动时连续两次请求将导致它挂起(第二个请求将锁定整个线程)。 但这是我的错误,您的错误可能有所不同。

@asnisarenko我不知道你为什么会挂起。 您绝对_不需要_每个连接都需要一个工作线程,因为每个工作线程都可以协同处理数千个连接(只要处理代码不独占 CPU / 锁定整个线程)。 具体来说,如果浏览器停止请求,它只是意味着当 gunicorn read()来自套接字时,它会阻止一个 greenlet,但是由于read应该是猴子补丁,它会屈服于其他小绿叶。

@ikonst
这个问题是在谈论使用默认配置运行 gunicorn。 默认工人类是sync http://docs.gunicorn.org/en/stable/settings.html#worker -class

sync worker 使用 pre-fork 模型,每个 worker 一次处理一个 TCP 连接/请求。

我不知道是什么导致了这个问题,但是从默认的sync工人类型切换到eventlet解决了这个问题:

CMD pipenv run gunicorn webapp -b 0.0.0.0:8080 -k eventlet

祝你好运。

也许这只会对我有帮助,但由于我花了 7 小时来调试这个问题(一个在 EC2 上的 Docker 中运行的 Flask/Gunicorn 应用程序),如果我能把这个麻烦留给少数人,那就是一个小小的胜利。

容器内存限制过低。

如果我将来有内存泄漏,我会尝试设置更高的内存限制,但现在,没有限制。

谢谢

def trace_on_abort():
    import signal
    import traceback

    def print_trace(sig, frame):
        print(''.join(traceback.format_stack(frame)))

    signal.signal(signal.SIGABRT, print_trace)

你太帮我了。 EHU )))

这个trace_on_abort()方法去哪里了? 在应用程序代码文件中? 它需要注释吗?

@mattg-vbt 在需要调试时将其添加到应用程序的开头,并在完成调试后将其删除

@ikonst我将此添加到我的应用程序中,但我没有看到它受到影响。 我得到了工人超时,但这个方法没有被命中。

@mattg-vbt 你能试试做kill -ABRT $pid来查看调用的print_trace函数吗? (这个想法是当你的工人超时时你会从 werkzeug 获得 SIGABRT,但让我们首先检查它是否被调用)

@asnisarenko对于我们中不太精明的人,我将如何更新 procfile?

web gunicorn app:app -k gevent --worker-connections 1000 ?

@SumNeuron
如果您正在使用 gevent 工作人员(而不是同步工作人员),那么您不应该遇到这个问题。 所以你发布的命令看起来不错。

我只有在初始化时才会遇到 gevent 工作人员的这个问题,这有点烦人,因为我在启动我的应用程序之前正在处理一些任务。 但我现在设置了一个很高的超时时间。
我在这里发布了一个可重现的测试仓库:https://github.com/zamponotiropita/test-gunicorn-worker-timeout -> test_0 失败,test_1 和 test_2 通过

@zamponotiropita您是否尝试在分叉之前按每个工人或每个应用程序执行此操作?

@ikonst请检查运行文件run.sh ,它是每个工人的。 问题不是与预加载有关,但是我在预加载时连接到数据库时遇到问题,因为应用对象(以及与数据库连接一起)在分叉时被复制并通过了进程 -> 我的数据库无法处理主人和工人的相同连接,我找不到解决方法

我有一个类似的问题。 我正在尝试使用 Flask 即时生成大量数据
方法失败,因为在--timeout设置的任何内容过期后工作人员超时。 重现的最小示例:

test_gunicorn_timeout.py

import flask
from time import sleep


app = flask.Flask(__name__)


@app.route('/')
def gunicorn_timeout():
    def generator():
        for _ in range(10):
            yield b'Yet another line...'
            sleep(2)
    return flask.Response(generator(), mimetype='text/plain')

然后运行gunicorn --timeout 10 test_gunicorn_timeout:app并在 10 秒后请求localhost:8000 ,您会得到
[CRITICAL] WORKER TIMEOUT

我还尝试使用-k gevent-k eventlet ,但没有任何改变。

我在 Windows 10 专业版上。 使用 docker 撰写
gunicorn app -b 0.0.0.0:8000 -k gevent
通过在我的 python 容器中安装 gevent 为我工作
如何安装 gevent

然后运行gunicorn --timeout 10 test_gunicorn_timeout:app并在 10 秒后请求localhost:8000 ,您会得到一个
[CRITICAL] WORKER TIMEOUT

我还尝试使用-k gevent-k eventlet ,但没有任何改变。

@ltskv

您找到 [CRITICAL] WORKER TIMEOUT 问题的解决方案了吗?

我试图在 heroku(使用 gunicorn)上部署的烧瓶流端点也有类似的问题。 在那里,只要在 30 秒内发送了一些数据,代理前端就应该保持连接处于活动状态,但是如果它在 30 秒内没有完成,即使它仍在运行并生成数据,似乎 gunicorn 只是终止了该进程。

在这一点上,gunicorn 文档对我来说并不完全清楚。 对于 --timeout 它说Workers silent for more than this many seconds are killed and restarted.但似乎工人在 30 秒后被杀死,即使他们仍然产生数据?

在这一点上,gunicorn 文档对我来说并不完全清楚。 对于 --timeout 它说工人沉默超过这么多秒被杀死并重新启动。 但似乎工人在 30 秒后被杀死,即使他们仍然产生数据?

@kurt-hectic 应该改进文档。 静默,我们的意思是从仲裁进程的角度来看静默,它通过一个临时文件与工人通信。 如果工作人员正忙于发送数据,则不会更新该文件。 从仲裁者的角度来看,工人正在丢失心跳。

另见#1974。

使用除默认值之外的任何工作器,同步工作器应该减轻流式传输大型主体的问题,因为其他工作器即使在处理请求时也会心跳临时文件。

@kurt-hectic 我再次重新检查了-k gevent选项并在生成器迭代之间插入了sleep(0)并且它确实对我有用(我不确定为什么它当时不起作用我发布了这个问题)。

--超时=5

这是导致此问题的最常见原因。

我希望我的解决方案可以帮助你。 几天前我遇到了这个关键的工人超时问题并尝试了一些解决方案。 它现在运作良好。

以下是我的理解和解决方案:

  1. 在 gunicorn 中尝试预加载

它无法启动工作程序,因为它需要更多时间来加载包,例如 tensorflow 后端,以启动服务。 因此,当您遇到应用程序启动时间缓慢时,请尝试在 gunicorn 中启用预加载选项(请参阅 https://devcenter.heroku.com/articles/python-gunicorn#advanced-configuration)。

gunicorn hello:app --preload

  1. 尝试增加 gunicorn 的超时时间

默认超时时间为 30 秒。 如果您的应用程序确实需要很多时间来完成 api,请增加超时。

gunicorn hello:app --timeout 10

但是,从我的角度来看,如果 api 需要超过 1 分钟才能完成是没有意义的。 如果是这样,请尝试在您的代码中取得一些进展。

  1. 如果您使用的是 k8s,您还可以在 yaml 中为您的容器/图像设置 timeoutSeconds。

我今天遇到了同样的问题。 在我的情况下,api 需要大约一分钟来计算数据并返回到客户端,这导致了 CRITICAL WORKER TIMEOUT 错误。 我通过将 gunicorn 的超时标志增加到一分钟以上来解决它 - 它有效,没有看到问题再次出现。 希望这可以帮助。 我正在使用 uvicorn.workers.UvicornWorker。

我通过向 gnuicorn 添加额外的工人来解决这个问题:

web: gunicorn --workers=3 BlocAPI:app --log-file -

不知道为什么。

也许你陷入了僵局? 您的应用程序是否向自身发出请求?

在 2020 年 1 月 5 日星期日 10:52 alpinechicken, notifications @github.com 写道:

我通过向 gnuicorn 添加额外的工人来解决这个问题:

网络:gunicorn --workers=3 BlocAPI:app --log-file -

不知道为什么。


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJVQRCW3C63EZJWIN5DQ4G3WTA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63KLODNTX5200000000000000000000000000000000001
或取消订阅
https://github.com/notifications/unsubscribe-auth/AAAEQJXZM4NLK56DZMFSZALQ4G3WTANCNFSM4FDLD5PA
.

是的,一条路线呼叫另一条路线 - 那很糟糕吗?

这意味着您至少需要两名工作人员,否则您的服务器将
僵局。 请求将等待服务器响应第二个
请求(将排队)。

每个工作人员都会收到一个并发请求。

在 2020 年 1 月 6 日星期一 02:45 alpinechicken, notifications @github.com 写道:

是的,一条路线呼叫另一条路线 - 那很糟糕吗?


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXZHJC8000000000000引
或取消订阅
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA
.

啊,有道理。 谢谢!

2020 年 1 月 7 日,星期二,上午 6:23, bobf [email protected]写道:

这意味着您至少需要两名工作人员,否则您的服务器将
僵局。 请求将等待服务器响应第二个
请求(将排队)。

每个工作人员都会收到一个并发请求。

在 2020 年 1 月 6 日星期一 02:45 alpinechicken, notifications @github.com 写道:

是的,一条路线呼叫另一条路线 - 那很糟糕吗?


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
<
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAAEQJSFEFBBI6AMZJCM4C3Q4KLOJA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXWZHJK8000000000000000000000
,
或取消订阅
<
https://github.com/notifications/unsubscribe-auth/AAAEQJXTCPOFIZJU5PUPOODQ4KLOJANCNFSM4FDLD5PA

.


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/benoitc/gunicorn/issues/1801?email_source=notifications&email_token=AAH2WRPVPVO2EJ53BKQW5B3Q4OHLRA5CNFSM4FDLD5PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW6ZKIGDNV7000G43VMVBW6ZKIGDNV700000000007
或取消订阅
https://github.com/notifications/unsubscribe-auth/AAH2WRM2LLIB4O6OHCU5UG3Q4OHLRANCNFSM4FDLD5PA
.

worker_class', '同步')

我可以通过匹配工作线程数和线程数来解决这个问题。

我已经设置了workers = (2 * cpu_count) + 1并且没有设置线程。

一旦我改变了threads = workers ,一切就开始正常了。 以防万一,如果这对某人有帮助。

这是现在的样子

def run(host='0.0.0.0', port=8080, workers=1 + (multiprocessing.cpu_count() * 2)):
    """Run the app with Gunicorn."""

    if app.debug:
        app.run(host, int(port), use_reloader=False)
    else:
        gunicorn = WSGIApplication()
        gunicorn.load_wsgiapp = lambda: app
        gunicorn.cfg.set('bind', '%s:%s' % (host, port))
        gunicorn.cfg.set('workers', workers)
        gunicorn.cfg.set('threads', workers)
        gunicorn.cfg.set('pidfile', None)
        gunicorn.cfg.set('worker_class', 'sync')
        gunicorn.cfg.set('keepalive', 10)
        gunicorn.cfg.set('accesslog', '-')
        gunicorn.cfg.set('errorlog', '-')
        gunicorn.cfg.set('reload', True)
        gunicorn.chdir()
        gunicorn.run()

根据 gunicorn 文档,如果提到多个线程,它会将工作类从同步更改为 gthread。
PS:-
如果您尝试使用同步工作线程类型并将线程设置设置为大于 1,则将使用 gthread 工作线程类型。

我的情况:

环境:Ubuntu18.04+ gunicorn+ nginx +flask

pip install gunicorn[gevent] 在我的虚拟环境中

gunicorn -b localhost:8000 -w 4 web:app更改gunicorn -b localhost:8000 -k gevent web:app

有用。

感谢这里的每一个人,他们为帮助彼此解决问题做了大量工作。 如果觉得合适,请继续发布到这个问题。

但是,我正在关闭这个问题,因为我认为 Gunicorn 中没有任何错误,我认为没有任何措施可以采取,尽管我很乐意帮助审查试图以某种方式为此添加文档或改进的 PR记录消息。

请不要误解我的意图。 如果您怀疑 Gunicorn 中存在错误并想继续讨论,请这样做。 最好使用重现您的问题的示例应用程序打开新票证。 然而,在这一点上,这个问题有太多不同的问题、解决方案和对话,以致于它是非常易读的。

如果您在没有缓冲反向代理的情况下运行 Gunicorn,您_将_获得默认超时,出于多种原因同步工作程序。 常见的有:

  • 慢速客户端
  • 浏览器和代理保持打开状态的预连接/预取连接
  • 由于调用外部 API 或执行大量 CPU 密集型工作而导致的响应时间过长

您可以切换到异步或线程工作者类型,或者您可以将 Gunicorn 置于缓冲反向代理之后。 如果您知道超时是由于您自己的代码对外部 API 的调用缓慢或执行了您期望的重要工作,您可以增加--timeout选项。

这意味着您至少需要两名工作人员,否则您的服务器将陷入僵局。 该请求将一直等到服务器响应第二个请求(将排队)。 每个工作人员都会收到一个并发请求。

在 2020 年 1 月 6 日星期一,02:45 alpinechicken, @* > 写道:是的,一条路线调用另一条路线 - 是不是很糟糕?

调用“重定向”函数作为路由的返回值时是否会出现这种情况?

调用“重定向”函数作为路由的返回值时是否会出现这种情况?

不可以。flask 重定向以 HTTP 重定向响应,然后工作人员可以自由地接受新请求。 客户端在看到此响应时发出另一个请求,并且每当工作人员准备好时都会收到此请求。

我通过向 gnuicorn 添加额外的工人来解决这个问题:

web: gunicorn --workers=3 BlocAPI:app --log-file -

不知道为什么。

这与@anilpai之前在他设置workers=1 + (multiprocessing.cpu_count() * 2) .. 的评论中有关吗?

我有一个类似的问题。 原来我的应用程序入口点有错误。 从调试来看,我基本上是从 gunicorn 启动一个烧瓶应用程序,其工作人员随后进入一个无限连接循环,每 30 秒超时一次。

我确信这不会影响上述所有用户,但可能会影响某些用户。

在我用gunicorn module.wsgi运行的module/wsgi.py文件中,我有 -

application = my_create_app_function()
application.run(host="0.0.0.0")

而我应该有 -

application = my_create_app_function()
if __name__ == "__main__":
     application.run(host="0.0.0.0")

本质上,您不想在使用 gunicorn 时调用application.run() 。 gunicorn 下的__name__不会是"__main__" ,但在 Flask 中会,所以你仍然可以在本地调试。

我在 gunicorn 文档中找不到对此的引用,但可以想象这是一个常见的错误案例,所以也许需要一些警告。

这种情况仍在发生。 在 Gunicorn 调用中添加--preload为我解决了这个问题。

这个bug还没有修复吗? 我正在观察这种确切的行为。

Gunicorn 在 systemd 中是这样启动的:

[Service]
PIDFile = /run/gunicorn.pid
WorkingDirectory = /home/pi/pyTest
ExecStart=/usr/local/bin/gunicorn  app:app  -b 0.0.0.0:80 --pid /run/gunicorn.pid
RuntimeDirectory=/home/pi/pyTest
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
User=root
Group=root
ExecReload = /bin/kill -s HUP $MAINPID
ExecStop = /bin/kill -s TERM $MAINPID
ExecStopPost = /bin/rm -rf /run/gunicorn
PrivateTmp = true

工作进程不断超时并重新启动:

Jul 10 15:19:20 raspberryVM gunicorn[10941]: [2020-07-10 15:19:20 -0700] [10941] [CRITICAL] WORKER TIMEOUT (pid:10944)
Jul 10 15:19:20 raspberryVM gunicorn[10941]: [2020-07-10 15:19:20 -0700] [10944] [INFO] Worker exiting (pid: 10944)
Jul 10 15:20:15 raspberryVM gunicorn[10941]: [2020-07-10 15:20:15 -0700] [10985] [INFO] Booting worker with pid: 10985

app.py 是一个简单的 Flask 应用程序。

这个问题是否因为不修复而关闭?

我也遇到了同样的问题

但是在调试之后,我发现当 gunicorn 启动 Django App 时,其中一个依赖项花费的时间比预期的要长,(在我的情况下是外部数据库连接),这使得gunicron工人超时

当我解决了连接问题时,超时问题也解决了......

这不是我的情况。 我使用“Hello, World”类型的应用程序进行了测试,没有依赖项。 所以我仍然对此感到困惑,但似乎不可能让 Gunicorn 具有长时间运行的线程。 工作进程重新启动并因此终止长时间运行的线程。

@leonbrag
这可能不是 gunicorn 错误。 在线程中查看我上面的推荐。 这是浏览器发送空的“预测的”TCP 连接,并在没有空 TCP 连接保护的情况下仅使用少数同步工作线程运行 gunicorn 的副作用。

是否有参考架构/设计显示了使用长(永久)工作线程设置 Gunicorn 烧瓶应用程序的正确方法?

如果这不是错误,那么它似乎是 Gunicorn 架构/设计的人工制品或限制。

为什么不同步工作者永远运行并接受客户端连接。 这样的工作者会根据需要关闭套接字,但继续运行而不退出(因此工作线程继续运行)。

@leonbrag
您应该更具体地说明您要解决的问题。

此线程中讨论的问题发生在开发环境中,最简单的解决方案是添加更多同步工作线程或使用线程工作线程。

如果你想在生产设置中避免这个问题,你可以使用 gevent worker,或者你可以在 gunicorn 前面放置一个 nginx。
一些PaaS已经在你的docker容器前面放了一个nginx,所以你不必担心。 同样,解决方案取决于上下文和细节。

这是一个很好的阅读。
https://www.brianstorti.com/the-role-of-a-reverse-proxy-to-protect-your-application-against-slow-clients/

您可以从文档中查看设计页面。 异步工作者是其中之一
运行长任务的方法。

在星期六2020年8月8日18:00 leonbrag [email protected]写道:

是否有参考架构/设计显示了正确的设置方式
具有长(永久)工作线程的 Gunicorn 烧瓶应用程序?

如果这不是错误,那么它似乎是工件或限制
Gunicorn 架构/设计。

为什么不同步工作者永远运行并接受客户端连接。 这样的
worker 会根据需要关闭套接字,但继续运行而不退出
(因此工作线程继续运行)。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-670944797
或取消订阅
https://github.com/notifications/unsubscribe-auth/AAADRIWRQGIP3R5PMVJ5ENTR7VZA3ANCNFSM4FDLD5PA
.

>

从我的手机发送

网络:gunicorn --workers=3 app:app --timeout 200 --log-file -

我通过增加 --timeout 解决了我的问题

有关 Docker 相关的 tmpfs 问题,另请参阅 #1388。

哦,非常感谢 Randall,我在 Docker 中运行 gunicorn 时忘记将--worker-tmp-dir /dev/shm到 gunicorn 参数中。

顺便说一句,64 Mb 是否足以用于 gunicorn 缓存?

gunicorn app:app --timeout 1000
或者
gunicorn应用程序:应用程序--preload

为我工作......我更喜欢超时之一。

奇怪的是,我添加了--worker-tmp-dir /dev/shm但仍然收到:

[2020-11-27 21:01:42 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:17)

为了确保/dev/shm是 ramfs,我对其进行了基准测试:

image

参数是下一个:

    command: /bin/bash -c "cd /code/ && pipenv run gunicorn --worker-tmp-dir /dev/shm conf.wsgi:application --bind 0.0.0.0:8022 --workers 5 --worker-connections=1000"

PS:我正在使用 PyPy

@attajutt超时很好,但是您冒着风险,gunicorn 主进程只会在 1000 秒后检测到您的工作进程中的挂断,并且您将错过很多请求。 如果只有几个工人中的一个挂断电话,也很难检测到它。 我至少不会做 1000。

@ivictbor感谢

我也遇到了这个错误问题,几次后,我发现问题可能是由以下原因引起的:

  1. nginx配置
  2. Gunicorn/Uwsgi

如果您像 GAE 一样在云中部署您的应用程序,则不会出现任何提示错误。
您可以尝试使用此案例解决方案来显示错误: https :

如果提出502坏网关;
大概有两种可能:

  1. gunicorn 没有运行
  2. gunicorn 超时

在这里解释了完整的问题: https ://www.datadoghq.com/blog/nginx-502-bad-gateway-errors-gunicorn/

希望可以解决任何人在 [CRITICAL] WORKER TIMEOUT 中出错的问题

为找到此线程的人添加另一种可能性...

这也可能是由于 docker 强加的资源限制对于您的 Web 应用程序来说太低了。 例如,我有以下限制:

services:
  web_app:
    image: blah-blah
    deploy:
      resources:
        limits:
          cpus: "0.25"
          memory: 128M

这些对于gunicorn显然太低[CRITICAL] WORKER TIMEOUT错误,直到我删除了约束。

对于 gunicorn 来说,这个资源非常好。 但你确实需要
飞机的工人数量和您所需的资源
应用。 128M 和 0.25cpu 对于 Web 应用程序来说似乎真的很低
用 Python 编写.... 一般来说,您至少需要 1 个核心 /vcpu 和
至少 512MB 的 RAM。

2021 年 3 月 26 日星期五 02:14,科尔顿·希克斯@* > 写道:

为找到此线程的人添加另一种可能性...

这也可能是由于 docker 强加了资源限制导致的
对您的 Web 应用程序来说太低了。 例如我有以下内容
约束:

服务:
网络应用程序:
图片:胡说八道
部署:
资源:
限制:
处理器:“0.25”
内存:128M

这些对于 gunicorn 来说显然太低了所以我不断得到 [CRITICAL]
WORKER TIMEOUT 错误,直到我删除了约束。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/benoitc/gunicorn/issues/1801#issuecomment-807855647
或取消订阅
https://github.com/notifications/unsubscribe-auth/AAADRITPZB7BMA6QW7LFNVLTFPNV3ANCNFSM4FDLD5PA
.

>

从我的手机发送

--timeout=1000 对我有用。 问题是低 CPU 资源的 GCP 机器。 它在我的本地机器上运行良好,默认超时。

此页面是否有帮助?
0 / 5 - 0 等级