<p>gunicorn CRITICAL WORKER TIMEOUT</p>

Criado em 21 jan. 2017  ·  18Comentários  ·  Fonte: benoitc/gunicorn

Estou executando um gunicorn com as seguintes configurações:
gunicorn --worker-class gevent --timeout 30 --graceful-timeout 20 --max-requests-jitter 2000 --max-requests 1500 -w 50 --log-level DEBUG --capture-output --bind 0.0.0.0:5000 run:app e estou vendo em todos, exceto 3 trabalhadores, o [CRITICAL] WORKER TIMEOUT . Depois de um certo tempo, o gunicorn não pode gerar mais trabalhadores ou pelo menos é muito lento para gerá-los. Isso faz com que ele não torne o servidor alcançável e qualquer solicitação inacessível.

Reduzi o número de trabalhadores para 3 e dei a cada trabalhador 2 threads e agora não estou mais vendo esse problema.

Não consigo obter um rastreamento de pilha dos tempos limite, mas parece que depois de um certo número de trabalhadores, ele não consegue lidar com eles?

( unconfirmed - Bugs -

Comentários muito úteis

Quem ainda tiver esse problema, verifique a disponibilidade de recursos para o aplicativo além de aumentar o tempo limite e alterar o tipo de classe de trabalho

Eu estava tendo esse problema quando tentei implantar meu aplicativo usando Docker Swarm e percebi que estava limitando o recurso muito baixo para o aplicativo. Aumentar o recurso resolve o problema para mim

deploy:
  replicas: 5
  resources:
    limits:
      cpus: "0.1"
      memory: 50M
  restart_policy:
    condition: on-failure

Acho que isso não é um bug, apenas a forma como configuramos nossos aplicativos

Todos 18 comentários

quando um trabalhador atinge o tempo limite, significa que ele não notificou o árbitro a tempo de que estava vivo. Você tem alguma tarefa executada durante uma solicitação que pode demorar mais do que o tempo limite?

@jseaidou bump.

Desculpe pela resposta tardia @benoitc. O problema que estou vendo é, na verdade, os threads não ativos fazendo isso. Meus encadeamentos ativos não expiram, meus não ativos sob menos carga fornecem erros de tempo limite mais críticos do que apenas um tempo limite normal. Eu mudei de gevent para tornado e isso parece ter corrigido o problema de travamento, mas ainda estou vendo 3 workers fornecendo o tempo limite crítico a cada 30 segundos. Se for um tempo limite normal, não deve ser um erro crítico.

Estou enfrentando exatamente o mesmo problema.
Gunicorn 19.7.1
gevent 1.2.1
Python 3.5.3
Executando no Docker, imagem baseada em oficial " python: 3.5 "

@jseaidou é um intervalo normal no sentido em que o árbitro reage a ele. É fundamental porque normalmente não deveria acontecer.

Provavelmente, um de seus trabalhadores está fazendo uma operação de bloqueio, impedindo que o trabalhador gunicorn notifique o árbitro. Se você tiver uma operação longa, certifique-se de acionar o agendador geven de vez em quando dormindo ou algo parecido. ou qualquer coisa que chame o agendador de tornado de volta também.

Como posso reproduzir o problema?

@saabeilin mesmo ^^

Estou vendo a mesma coisa: os funcionários estão expirando, mesmo quando não atendem a solicitações. Tudo o que fiz foi lançar meu contêiner no AWS ECS.

[2017-06-27 20:41:56 +0000] [1] [DEBUG] Current configuration:
proxy_protocol: False
worker_connections: 1000
statsd_host: None
max_requests_jitter: 0
post_fork: <function post_fork at 0x7f6bbc3f1938>
errorlog: -
enable_stdio_inheritance: False
worker_class: sync
ssl_version: 2
suppress_ragged_eofs: True
syslog: False
syslog_facility: user
when_ready: <function when_ready at 0x7f6bbc3f1668>
pre_fork: <function pre_fork at 0x7f6bbc3f17d0>
cert_reqs: 0
preload_app: False
keepalive: 2
accesslog: -
group: 0
graceful_timeout: 30
do_handshake_on_connect: False
spew: False
workers: 4
proc_name: None
sendfile: None
pidfile: None
umask: 0
on_reload: <function on_reload at 0x7f6bbc3f1500>
pre_exec: <function pre_exec at 0x7f6bbc3f1ed8>
worker_tmp_dir: None
limit_request_fields: 100
pythonpath: None
on_exit: <function on_exit at 0x7f6bbc3f7758>
config: None
logconfig: None
check_config: False
statsd_prefix:
secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
reload_engine: auto
proxy_allow_ips: ['127.0.0.1']
pre_request: <function pre_request at 0x7f6bbc3f70c8>
post_request: <function post_request at 0x7f6bbc3f71b8>
forwarded_allow_ips: ['127.0.0.1']
worker_int: <function worker_int at 0x7f6bbc3f1c08>
raw_paste_global_conf: []
threads: 1
max_requests: 0
chdir: /opt/app
daemon: False
user: 0
limit_request_line: 4094
access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
certfile: None
on_starting: <function on_starting at 0x7f6bbc3f1398>
post_worker_init: <function post_worker_init at 0x7f6bbc3f1aa0>
child_exit: <function child_exit at 0x7f6bbc3f7320>
worker_exit: <function worker_exit at 0x7f6bbc3f7488>
paste: None
default_proc_name: app:app
syslog_addr: udp://localhost:514
syslog_prefix: None
ciphers: TLSv1
worker_abort: <function worker_abort at 0x7f6bbc3f1d70>
loglevel: DEBUG
bind: ['0.0.0.0:5005']
raw_env: []
initgroups: False
capture_output: False
reload: False
limit_request_field_size: 8190
nworkers_changed: <function nworkers_changed at 0x7f6bbc3f75f0>
timeout: 30
keyfile: None
ca_certs: None
tmp_upload_dir: None
backlog: 2048
logger_class: gunicorn.glogging.Logger
[2017-06-27 20:41:56 +0000] [1] [INFO] Starting gunicorn 19.7.1
[2017-06-27 20:41:56 +0000] [1] [DEBUG] Arbiter booted
[2017-06-27 20:41:56 +0000] [1] [INFO] Listening at: http://0.0.0.0:5005 (1)
[2017-06-27 20:41:56 +0000] [1] [INFO] Using worker: sync
[2017-06-27 20:41:56 +0000] [8] [INFO] Booting worker with pid: 8
[2017-06-27 20:41:57 +0000] [9] [INFO] Booting worker with pid: 9
[2017-06-27 20:41:57 +0000] [10] [INFO] Booting worker with pid: 10
[2017-06-27 20:41:57 +0000] [12] [INFO] Booting worker with pid: 12
[2017-06-27 20:41:57 +0000] [1] [DEBUG] 4 workers
[2017-06-27 20:42:15 +0000] [10] [DEBUG] Closing connection.
[2017-06-27 20:42:15 +0000] [8] [DEBUG] Closing connection.
[2017-06-27 20:42:45 +0000] [8] [DEBUG] Closing connection.
[2017-06-27 20:42:45 +0000] [10] [DEBUG] Closing connection.
[2017-06-27 20:42:46 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:9)
[2017-06-27 20:42:46 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:12)
[2017-06-27 20:42:46 +0000] [9] [INFO] Worker exiting (pid: 9)
[2017-06-27 20:42:46 +0000] [12] [INFO] Worker exiting (pid: 12)
[2017-06-27 20:42:46 +0000] [1] [DEBUG] 3 workers
[2017-06-27 20:42:46 +0000] [24] [INFO] Booting worker with pid: 24
[2017-06-27 20:42:46 +0000] [25] [INFO] Booting worker with pid: 25
[2017-06-27 20:42:46 +0000] [1] [DEBUG] 4 workers

Isso não ocorre durante a execução local. : - /

Parece que mudar para gevent workers resolveu isso para mim. ¯ \ _ (ツ) _ / ¯

Duplicado de # 1194, eu acho.

Tenho visto isso acontecer várias vezes recentemente e, para mim, parece estar relacionado a colocar o laptop para hibernar. Quando abro a tampa, várias dessas mensagens aparecem. Não tenho certeza se isso ajuda, mas pensei em mencionar ...

gunicorn --daemon --workers 2 --timeout 120 --bind 127.0.0.1:4000 --pid /var/run/mshc_admin.pid --user danilovskoe --group danilovskoe --chdir / home / danilovskoe / mshc2 / src / flask / --env MSHC_PRODUCTION = / etc / monit / mshc.config.py admin_ gunicorn: app

tempo limite de 30 segundos
GET pedido

ubuntu 16.04
frasco 0.12.2
Python 3.6.3 (padrão, 4 de outubro de 2017, 02:55:45)
[GCC 5.4.0 20160609] no Linux
gunicorn (versão 19.7.1)

Eu encontrei o problema.

Depois de iniciar o aplicativo, ele funciona. Mas apenas se houver uma solicitação, [CRITICAL] WORKER TIMEOUT será acionado. Por exemplo,

[2018-01-02 16:38:03 +0800] [24355] [INFO] Starting gunicorn 19.7.1
[2018-01-02 16:38:03 +0800] [24355] [DEBUG] Arbiter booted
[2018-01-02 16:38:03 +0800] [24355] [INFO] Listening at: http://0.0.0.0:8080 (24355)
[2018-01-02 16:38:03 +0800] [24355] [INFO] Using worker: gevent
[2018-01-02 16:38:03 +0800] [24358] [INFO] Booting worker with pid: 24358
[2018-01-02 16:38:03 +0800] [24355] [DEBUG] 1 workers

[2018-01-02 16:38:10 +0800] [24358] [DEBUG] GET /v1/bj2/CC/uuid
[2018-01-02 16:38:10 +0800] [24358] [DEBUG] Closing connection. 
[2018-01-02 16:38:41 +0800] [24355] [CRITICAL] WORKER TIMEOUT (pid:24358)
[2018-01-02 16:38:41 +0800] [24358] [INFO] Worker exiting (pid: 24358)
[2018-01-02 16:38:41 +0800] [24381] [INFO] Booting worker with pid: 24381

[2018-01-02 16:48:51 +0800] [24355] [CRITICAL] WORKER TIMEOUT (pid:24381)
[2018-01-02 16:48:51 +0800] [24381] [INFO] Worker exiting (pid: 24381)
[2018-01-02 16:48:51 +0800] [24703] [INFO] Booting worker with pid: 24703
[2018-01-02 16:48:51 +0800] [24703] [INFO] worker pid 24703 notify
[2018-01-02 16:48:51 +0800] [24703] [DEBUG] GET /v1/bj2/CC/uuid
[2018-01-02 16:48:51 +0800] [24703] [DEBUG] Closing connection. 
CentOS: 6.7
Python: 3.6.3
Gevent: 1.2.2
Greenlet: 0.4.9
Gunicorn: 19.7.1

RUN CMD: gunicorn --worker-class gevent --log-level debug --bind 0.0.0.0:8080 app

Quando eu mudei a classe de trabalho para eventlet , isso é,
gunicorn --worker-class eventlet --log-level debug --bind 0.0.0.0:8080 app ,
tudo bem.

Aviso: Meu aplicativo é executado no host físico, nem no host virtual nem no host em nuvem.


Atualizar:

Então eu acho que é a questão do gevent ou do gevent trabalhador.

Existem relatórios sobre este assunto de gevent resolvendo o problema e gevent causando o problema. Não consigo identificar uma causa raiz aqui. Alguns dos relatórios podem ser iguais ao # 1194, mas outros talvez não.

Se alguém puder compartilhar um caso mínimo para reproduzir, isso ajudaria.

Não tenho certeza se é definitivamente o mesmo problema, mas posso reproduzir isso 100% do tempo usando o Virtualbox com a seguinte configuração:

Host: Windows 10
Convidado: Ubuntu 16.04
Gunicorn: 19.7.1

Encaminho o TCP: 8000 entre o host e o convidado pela conexão NAT padrão. Usando um trabalhador sync , quaisquer solicitações no host para localhost:8000 fazem com que esses erros apareçam no log, mas se eu fizer as mesmas solicitações no convidado , o log será limpo. Mudar para --worker-class eventlet remove o traço.

Eu aprecio o Virtualbox é uma dimensão completamente diferente, mas soa muito semelhante ao que está sendo descrito acima e é reproduzível de forma consistente (pelo menos para mim).

Estou vendo isso acontecer com uploads lentos. Durante um upload (para um site Django), se o tempo limite do trabalhador for atingido, o upload será interrompido.

@lordmauve se você estiver usando o trabalhador de sincronização esperado. Solicitações longas bloquearão o trabalhador e, eventualmente, o árbitro o matará. Você pode usar um tipo de trabalhador diferente se espera que solicitações longas sejam bem-sucedidas.

Para quem está lendo este tópico, por favor, abra novamente com uma caixa mínima para reproduzir. Não consigo ver nenhuma investigação limpa para prosseguir aqui. Para o caso do AWS / ECS, ainda estou deixando # 1194 aberto até que possa testar as configurações que listei (https://github.com/benoitc/gunicorn/issues/1194#issuecomment-371250650).

Quem ainda tiver esse problema, verifique a disponibilidade de recursos para o aplicativo além de aumentar o tempo limite e alterar o tipo de classe de trabalho

Eu estava tendo esse problema quando tentei implantar meu aplicativo usando Docker Swarm e percebi que estava limitando o recurso muito baixo para o aplicativo. Aumentar o recurso resolve o problema para mim

deploy:
  replicas: 5
  resources:
    limits:
      cpus: "0.1"
      memory: 50M
  restart_policy:
    condition: on-failure

Acho que isso não é um bug, apenas a forma como configuramos nossos aplicativos

@jseaidou é um intervalo normal no sentido em que o árbitro reage a ele. É fundamental porque normalmente não deveria acontecer.

Provavelmente, um de seus trabalhadores está fazendo uma operação de bloqueio, impedindo que o trabalhador gunicorn notifique o árbitro. Se você tiver uma operação longa, certifique-se de acionar o agendador geven de vez em quando dormindo ou algo parecido. ou qualquer coisa que chame o agendador de tornado de volta também.

Como posso reproduzir o problema?

@saabeilin mesmo ^^

Obrigado, isso faz sentido.
Para mim, isso está acontecendo ao servir um grande arquivo que foi baixado anteriormente do armazenamento em nuvem.
Mediante solicitação, o arquivo é recuperado para o disco local do armazenamento em nuvem e, em seguida, é descriptografado em fluxo para o cliente. O download do armazenamento em nuvem funciona bem, mesmo que demore 10 minutos ou mais.
Depois que o trabalhador começa a descriptografar o arquivo do disco para o cliente, ele morre após algumas centenas de MB, provavelmente porque atinge o tempo limite enquanto está ocupado com essa operação de bloqueio.

Esta página foi útil?
0 / 5 - 0 avaliações