Estou executando o app
gunicorn -w 2 -b ' localhost: 8585 ' --timeout = 200 --certfile = crt.crt --keyfile = key.key service: app
E eu recebo o seguinte, mas nem sempre recebo essa resposta, a maioria das solicitações são tratadas corretamente, mas às vezes ocorre um erro
[2018-05-08 14:53:36 +0500] [11227] [ERROR] Socket error processing request.
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/gunicorn/workers/sync.py", line 134, in handle
req = six.next(parser)
File "/usr/lib/python3/dist-packages/gunicorn/http/parser.py", line 41, in __next__
self.mesg = self.mesg_class(self.cfg, self.unreader, self.req_count)
File "/usr/lib/python3/dist-packages/gunicorn/http/message.py", line 153, in __init__
super(Request, self).__init__(cfg, unreader)
File "/usr/lib/python3/dist-packages/gunicorn/http/message.py", line 53, in __init__
unused = self.parse(self.unreader)
File "/usr/lib/python3/dist-packages/gunicorn/http/message.py", line 165, in parse
self.get_data(unreader, buf, stop=True)
File "/usr/lib/python3/dist-packages/gunicorn/http/message.py", line 156, in get_data
data = unreader.read()
File "/usr/lib/python3/dist-packages/gunicorn/http/unreader.py", line 38, in read
d = self.chunk()
File "/usr/lib/python3/dist-packages/gunicorn/http/unreader.py", line 65, in chunk
return self.sock.recv(self.mxchunk)
File "/usr/lib/python3.5/ssl.py", line 922, in recv
return self.read(buflen)
File "/usr/lib/python3.5/ssl.py", line 799, in read
return self._sslobj.read(len, buffer)
File "/usr/lib/python3.5/ssl.py", line 585, in read
v = self._sslobj.read(len)
OSError: [Errno 0] Error
Na minha memória, esse erro acontece quando um cliente tenta se conectar sem SSL. Isso poderia ser o seu caso?
Vejo sua postagem sobre o outro problema que fechei. Minhas desculpas se meu comentário não é a causa.
Existe um padrão para o qual as solicitações falham dessa maneira?
@usmetanina que tipo de clientes se conectam ao Gunicorn também? Você tem alguma opção SSL usada explicitamente para se conectar a ele?
já está resolvido? @usmetanina , porque tenho exatamente o mesmo problema
@benoitc vejo @usmetanina é erro exata freqüentemente usando python3.6 e gunicorn 19.9.0
.
Eu uso as informações abaixo para iniciar o gunicorn com um aplicativo de frasco em execução em um contêiner do docker.
gunicorn --workers=3 --bind=0.0.0.0:8000 --config=gunicorn_config.py --preload main
O arquivo de configuração tem a seguinte aparência (domain-with-cert.com, claro, é um espaço reservado para o nome de domínio real):
workers = 3
bind = '0.0.0.0:443'
certfile = '/etc/letsencrypt/live/domain-with-cert.com/fullchain.pem'
keyfile = '/etc/letsencrypt/live/domain-with-cert.com/privkey.pem'
Qualquer opinião sobre depuração seria útil. Se precisar de mais informações, é só me avisar.
@willpatera , veja meu comentário:
Na minha memória, esse erro acontece quando um cliente tenta se conectar sem SSL. Isso poderia ser o seu caso?
@tilgovi eu vi o comentário acima. Tenho certeza de que o cliente está se conectando por SSL. Alguma sugestão de depuração?
@willpatera eu diria, ligue os logs de acesso e veja se você pode determinar qual solicitação causa o problema. Se você tiver um proxy reverso na frente do gunicorn, certifique-se de que ele tenha registros de acesso para que você possa ver qual solicitação causa um erro com o gunicorn, mesmo que o gunicorn nunca o registre.
@tilgovi Estou tendo os mesmos problemas. Tive que editar as seguintes informações um pouco, pois estavam incorretas:
O pedido que está sendo feito ao gunicorn é sempre exatamente o mesmo pedido (mas com um corpo diferente). Portanto, não há dúvida de que é https e não http.
O que eu noto é que sempre acontece quando a quantidade de pedidos está aumentando. Quando o servidor está ocupado, parece que há problemas para lidar com as solicitações de maneira adequada.
Talvez isso tenha a ver com os trabalhadores ou algo assim? Se você tiver alguma sugestão de configuração, eu gostaria de testá-la.
Oi pessoal, ainda estou procurando uma maneira de resolver isso. Atualmente, a única opção que temos é fazer o downgrade para HTTP simples, o que não é viável de forma alguma.
Eu testemunhei a mesma coisa. Tinha um servidor de produção executando Gunicorn + Flask (atrás de um balanceador de carga) que funcionou bem por meses, então, de repente, todas as solicitações geraram este erro até que reiniciei o Gunicorn:
[2019-11-21 07:27:36 +0000] [24245] [ERROR] Socket error processing request.
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/gunicorn/workers/sync.py", line 134, in handle
req = six.next(parser)
File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/parser.py", line 41, in __next__
self.mesg = self.mesg_class(self.cfg, self.unreader, self.req_count)
File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/message.py", line 181, in __init__
super(Request, self).__init__(cfg, unreader)
File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/message.py", line 54, in __init__
unused = self.parse(self.unreader)
File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/message.py", line 193, in parse
self.get_data(unreader, buf, stop=True)
File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/message.py", line 184, in get_data
data = unreader.read()
File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/unreader.py", line 38, in read
d = self.chunk()
File "/usr/local/lib/python3.6/dist-packages/gunicorn/http/unreader.py", line 65, in chunk
return self.sock.recv(self.mxchunk)
File "/usr/lib/python3.6/ssl.py", line 997, in recv
return self.read(buflen)
File "/usr/lib/python3.6/ssl.py", line 874, in read
return self._sslobj.read(len, buffer)
File "/usr/lib/python3.6/ssl.py", line 633, in read
v = self._sslobj.read(len)
OSError: [Errno 0] Error
Nada nos registros que precedem esses erros indica qual poderia ter sido o gatilho.
Isso aconteceu com o Gunicorn 19.9.0 em execução com 3 trabalhadores em um servidor de núcleo único.
Como esta é a primeira vez que vejo esse problema, não posso prometer que jamais o reproduzirei. No entanto, se houver qualquer tipo de registro ou outro código de diagnóstico que alguém queira que eu adicione em nosso servidor que possa fornecer algumas informações úteis caso isso aconteça novamente, sou todo ouvidos.
O seu LB chama um ponto de extremidade específico? Como responde ao pedido de LB?
Quando eu disse "Load Balancer", realmente deveria ter dito CDN ou camada de cache. Especificamente: é Amazon Cloudfront. Ele apenas encaminha as solicitações ao nosso servidor Gunicorn (em execução em uma instância EC2) e armazena os resultados em cache por um tempo.
hrm não deve amazon cloudfront encerrar a solicitação SSL para você? @ExplodingCabbage . Por que o gunicorn tem que ouvir no SSL por trás?
@benoitc Então, há duas camadas com SSL envolvidas na arquitetura. Membros do público se conectam ao nosso site por meio de nosso domínio do CloudFront sobre HTTPS e, em seguida, o CloudFront faz uma solicitação para o nosso nó de back-end executando Gunicorn, também usando HTTPS (com um nome de domínio e certificado diferente), armazena em cache o resultado e o veicula para o público.
Acho que talvez você esteja se perguntando qual é o objetivo de usar SSL para essa segunda solicitação interna. É certamente discutível, é inútil (embora possivelmente não - ele impede a Amazon de espionagem em nossas comunicações em sua rede interna, e também há razões regulatórias que não vou entrar em por que, devido ao setor de minha empresa, podemos precisar garantir que temos criptografia em todo o pipeline). Quer seja inútil ou não, nós o fazemos. ¯ \ _ (ツ) _ / ¯
será que o cloudfront está enviando ao seu endpoint uma solicitação HTTP simples? Se você tiver acesso aos logs do cloudfront, deverá ser capaz de vê-los.
@benoitc Não acho que o CloudFront expõe quaisquer logs que seriam úteis, mas tenho certeza de que ele não estava tentando se conectar por HTTP, uma vez que:
@ExplodingCabbage ok, darei uma olhada nele depois que o 20.0.1 for lançado. Uma última coisa, qual versão do Python você está usando?
3.6.8
Percebi que deixei de fora um detalhe da minha história acima: antes de reiniciar o Gunicorn, também atualizei o certificado SSL que o Gunicorn usa com LetsEncrypt. Não pensei em mencionar isso porque havia concluído erroneamente ontem que não havia nenhuma maneira de um certificado expirar no dia em que os erros começaram e que a atualização do certificado não tinha de fato sido relevante para corrigir o problema.
No entanto, ao verificar alguns logs, agora percebo que os erros na verdade começaram no dia em que um certificado anterior estava para expirar.
Ainda há algum mistério aqui e algum espaço potencial para melhorias (o que exatamente significa esse erro, e por que Gunicorn não pode dar uma mensagem mais útil?), Mas a narrativa que dei antes - na qual esse erro começou do nada sem causa aparente - não está certo. Eu acho que o CloudFront estava encerrando a conexão em resposta ao ver um certificado expirado do servidor Gunicorn, e que o Gunicorn, em vez de ser capaz de entender isso e relatá-lo de forma significativa, permite que um OSError sem mensagem borbulhe.
Peço desculpas por não ter meus patos em uma fila antes de reportar. Por outro lado, talvez isso torne mais fácil reproduzir essa exceção à vontade, se você quiser tentar lidar com o cenário de maneira mais elegante.
@ExplodingCabbage oh isso é bastante interessante, deve ser reproduzível em algum ponto então. Obrigado pelos detalhes adicionais!
Acabei de encontrar o mesmo problema de forma reproduzível e estou um tanto confiante de que é a consequência de algum tipo de esgotamento de recursos.
Para mim, foi desencadeado por esquecer um tempo limite em uma chamada de bloqueio e pedidos acumulando.
HTH
Olá! Estou enfrentando exatamente esse problema. Eu tenho um serviço gunicorn / flask em execução em um cluster ECS atrás de um balanceador de carga de rede. Alguns detalhes da versão:
python - 3.7.4
gunicorn - 19.9.0
flask - 1.0.4
O serviço é capaz de responder às solicitações provenientes de um cliente usando TLS sem problemas, no entanto, meus logs estão inundados com OSErrors. Pelo que eu posso dizer, eles são resultantes das solicitações de verificação de integridade vindas do balanceador de carga (TCP).
Consegui reproduzir o erro localmente abrindo e fechando uma conexão TCP manualmente na porta de escuta (8000 neste caso):
$ nc -vz 127.0.0.1 8000
localhost [127.0.0.1] 8000 (irdmi) open
O que resultou no seguinte erro:
Traceback (most recent call last):
File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/workers/sync.py" line 134 in handle
req = six.next(parser)
File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/parser.py" line 41 in __next__
self.mesg = self.mesg_class(self.cfg, self.unreader, self.req_count)
File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/message.py" line 181 in __init__
super(Request, self).__init__(cfg, unreader)
File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/message.py" line 54 in __init__
unused = self.parse(self.unreader)
File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/message.py" line 193 in parse
self.get_data(unreader, buf, stop=True)
File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/message.py" line 184 in get_data
data = unreader.read()
File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/unreader.py" line 38 in read
d = self.chunk()
File "/nix/store/nh3v0c2nipihwblkdn0mh2kqyv3jq9nz-python3-3.7.4-env/lib/python3.7/site-packages/gunicorn/http/unreader.py" line 65 in chunk
return self.sock.recv(self.mxchunk)
File "/nix/store/azwzsm1pkbzjxpkiq88w68p4jdghgasl-python3-3.7.4/lib/python3.7/ssl.py" line 1056 in recv
return self.read(buflen)
File "/nix/store/azwzsm1pkbzjxpkiq88w68p4jdghgasl-python3-3.7.4/lib/python3.7/ssl.py" line 931 in read
return self._sslobj.read(len)
OSError: [Errno 0] Error
Espero que isto ajude!
Hmm, bem depois de alguma pesquisa adicional, parece que isso pode realmente ser um bug na maneira ssl
biblioteca python https://bugs.python.org/issue31122
Conforme mencionado por @shevisjohnson, se você executar "nc -vz hostname port_no", este erro aparecerá.
Podemos suprimir esse erro no arquivo de log usando o mecanismo de log abaixo.
$ cat logging_config.yml
version: 1
formatters:
simple:
format: " %(asctime)s || %(name)s || %(levelname)s || %(message)s"
test_api:
format: "[%(asctime)s] [%(process)s] [%(levelname)s] %(message)s"
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
test_api_file_handler:
class: logging.handlers.RotatingFileHandler
level: DEBUG
formatter: test_api
filename: logs/test.log
maxBytes: 2000000000
backupCount: 1
encoding: utf8
loggers:
test_api:
level: DEBUG
handlers: [test_api_file_handler]
propagate: 0
root:
level: DEBUG
handlers: [console]
Aqui está o arquivo python.
import logging
import yaml
from flask import Flask
app = Flask(__name__)
def logSetter(logger_name:str) -> logging:
with open("logging_config.yml", 'r') as f:
config = yaml.safe_load(f)
logging.config.dictConfig(config)
logger = logging.getLogger(logger_name)
return logger
logger=logSetter(logger_name="test_api")
@app.route("/api/test")
def hello():
app.logger.info("hey from api")
return "Hello from Python!"
Espero que ajude.
Demorou apenas um momento para chegar a uma reprodução confiável: usando hey
para enviar 100 solicitações simultâneas para o Gunicorn mais recente (20.0.4) usando o trabalhador gthread
:
$ hey -n 100 -c 100 https://127.0.0.1:8000
`` `
$ gunicorn app: app -k gthread --certfile = ... --keyfile = ...
...
[2020-07-11 19:10:58 +0000] [3628247] [ERROR] Solicitação de processamento de erro de soquete.
Traceback (última chamada mais recente):
return self._sslobj.read (len)
OSError: [Errno 0] Erro
Using a Debian 9 / Linux 4.14.67 based environment.
The WSGI app to reproduce need not be anything beyond:
```python
# app.py
def app(environ, start_response):
start_response("200 OK", [])
return ""
Caso isso ajude também!
Se a causa raiz for de fato https://bugs.python.org/issue31122 :
Isso está afetando minha organização em produção também.
Percebi que a correção de bug caiu em ramos 3.8 e 3.9, mas eles estão considerando <= 3.7 EOL e ainda estamos presos no 3.6 por enquanto. Existe uma solução alternativa conhecida para esse problema no próprio gunicorn? Há algo planejado?
Estamos investigando o que poderia estar chamando o serviço para acionar isso, mas estou apenas tentando descobrir o que poderia ser feito, pois isso resulta em grandes picos de recursos nos nós afetados.
Além do comentário de jriddy sobre a não intenção de fazer backport antes do 3.8, se alguém mais estiver tendo esse problema, observe também que a correção foi definida para ser incluída no CPython 3.8.6 .
Tendo problemas para dizer exatamente de onde este traceback emana - no meu caso, usando gevent
como servidor de aplicativo WSGI diretamente, então presumindo que é uma chamada de registro em algum lugar dentro de gevent / greenlet, mas não consigo encontrá-la ainda. Para Gunicorn, isso acontece aqui, para trabalhadores síncronos:
No caso do Gunicorn, se você está preocupado apenas com o ruído nas toras, pode ser capaz de fazer algo como:
import logging
class HandshakeFilter(logging.Filter):
# example: https://docs.python.org/3/howto/logging-cookbook.html
# I have not tested this
def filter(self, record):
return "socket error processing request" in record.msg.casefold()
logging.getLogger("gunicorn").addFilter(HandshakeFilter())
Problema de gevent relacionado: https://github.com/gevent/gevent/issues/1671
Comentários muito úteis
Hmm, bem depois de alguma pesquisa adicional, parece que isso pode realmente ser um bug na maneira
ssl
biblioteca python https://bugs.python.org/issue31122