Gunicorn: OSError: [Errno 0] Error

Creado en 8 may. 2018  ·  30Comentarios  ·  Fuente: benoitc/gunicorn

Estoy ejecutando la aplicación
gunicorn -w 2 -b ' localhost: 8585 ' --timeout = 200 --certfile = crt.crt --keyfile = key.key service: app

Y obtengo lo siguiente, pero no siempre obtengo esa respuesta, la mayoría de las solicitudes se manejan correctamente, pero a veces ocurre un error

[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
( FeaturSSL

Comentario más útil

Hmm, después de algunas investigaciones adicionales, parece que esto puede ser un error en la forma en que la biblioteca Python ssl maneja los EOF irregulares en Linux: https://bugs.python.org/issue31122

Todos 30 comentarios

Desde mi memoria, este error ocurre cuando un cliente intenta conectarse sin SSL. ¿Podría ser ese el caso para ti?

Veo tu publicación sobre el otro tema que cerré. Mis disculpas si mi comentario no es la causa.

¿Existe un patrón en el que las solicitudes fallan de esta manera?

@usmetanina ¿qué tipo de clientes también se conectan con Gunicorn? ¿Tiene alguna opción de SSL utilizada explícitamente para conectarse?

¿Esto ya está resuelto? @usmetanina , porque tengo exactamente el mismo problema

@benoitc veo @usmetanina Es exacto de error con frecuencia usando python3.6 y gunicorn 19.9.0 .

Utilizo la siguiente información para iniciar gunicorn con una aplicación de matraz que se ejecuta dentro de un contenedor acoplable.

gunicorn --workers=3 --bind=0.0.0.0:8000 --config=gunicorn_config.py --preload main

El archivo de configuración se ve así (dominio-con-cert.com, por supuesto, es un marcador de posición para el nombre de dominio 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'

Cualquier idea sobre la depuración de esto sería útil. Si necesita más información, hágamelo saber.

@willpatera , mira mi comentario:

Desde mi memoria, este error ocurre cuando un cliente intenta conectarse sin SSL. ¿Podría ser ese el caso para ti?

@tilgovi Vi el comentario anterior. Estoy bastante seguro de que el cliente se conecta a través de SSL. ¿Alguna sugerencia de depuración?

@willpatera Diría que active los registros de acceso y vea si puede determinar qué solicitud causa el problema. Si tiene un proxy inverso frente a gunicorn, asegúrese de que tenga registros de acceso para que pueda ver qué solicitud causa un error con gunicorn incluso si gunicorn nunca lo registra.

@tilgovi Tengo los mismos problemas. Tuve que editar un poco la siguiente información porque era incorrecta:
La solicitud que se realiza a gunicorn es siempre exactamente la misma solicitud (pero con un cuerpo diferente). Entonces, no hay duda de que es https y no http.
Lo que sí noto es que siempre sucede cuando aumenta la cantidad de solicitudes. Cuando el servidor está ocupado, parece tener problemas para manejar las solicitudes correctamente.

¿Quizás esto tenga que ver con los trabajadores o algo así? Si tiene alguna sugerencia de configuración, con mucho gusto me gustaría probarla.

Hola chicos, todavía estoy buscando una forma de resolver esto. Actualmente, la única opción que tenemos es degradar a HTTP simple, lo cual no es factible en absoluto.

He sido testigo de lo mismo. Tenía un servidor de producción ejecutando Gunicorn + Flask (detrás de un equilibrador de carga) que funcionó bien durante meses, luego, de repente, cada solicitud arrojó este error hasta que reinicié 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 en los registros que preceden a estos errores sugiere cuál podría haber sido el desencadenante.

Esto fue con Gunicorn 19.9.0 ejecutándose con 3 trabajadores en un servidor de un solo núcleo.

Dado que es la primera vez que veo este problema, no puedo prometer que lo reproduciré. Sin embargo, si hay algún tipo de registro u otro código de diagnóstico que alguien quiera que agregue en nuestro servidor que pueda proporcionar información útil en caso de que esto vuelva a suceder, soy todo oídos.

¿Su LB llama a un punto final específico? ¿Cómo responde a la solicitud de LB?

Cuando dije "Load Balancer", debería haber dicho CDN o capa de almacenamiento en caché. Específicamente: es Amazon Cloudfront. Simplemente reenvía las solicitudes a nuestro servidor Gunicorn (que se ejecuta en una instancia EC2) y almacena en caché los resultados durante un tiempo.

hrm, ¿no debería amazon cloudfront finalizar la solicitud ssl por usted? @ExplodingCabbage . ¿Por qué Gunicorn tiene que escuchar detrás de SSL?

@benoitc Entonces, hay dos capas con SSL involucradas en la arquitectura. Los miembros del público se conectan a nuestro sitio web a través de nuestro dominio de CloudFront a través de HTTPS, y luego CloudFront realiza una solicitud a nuestro nodo de backend que ejecuta Gunicorn, también usando HTTPS (con un nombre de dominio y certificado diferente), almacena en caché el resultado y lo envía al público.

Supongo que tal vez se esté preguntando cuál es el punto de usar SSL para esa segunda solicitud interna. Ciertamente es discutible que no tenga sentido (aunque posiblemente no lo sea; evita que Amazon espíe nuestras comunicaciones en su red interna, y también hay razones regulatorias por las que no entraré en por qué, dada la industria de mi empresa, es posible que debamos asegurarnos de que tenemos cifrado a lo largo de la tubería). Sea inútil o no, lo hacemos. ¯ \ _ (ツ) _ / ¯

Sin embargo, ¿podría ser que Cloudfront esté enviando a su punto final una solicitud HTTP simple? Si tiene acceso a los registros de Cloudfront, debería poder verlos.

@benoitc No creo que CloudFront exponga ningún registro que sea útil, pero estoy seguro de que no intentaba conectarse a través de HTTP, ya que:

  • Nuestra distribución está configurada en la consola de CloudFront para conectarse al origen Gunicorn a través de "solo HTTPS".
  • Gunicorn no está escuchando en el puerto 80
  • Si intento conectar a nuestro servidor de fondo a través de HTTP (incluyendo forzar HTTP en el puerto 443) que no reproduce el OSError citado anteriormente
  • Cuando recibí el error OSError citado anteriormente, reiniciar Gunicorn en el servidor backend solucionó instantáneamente el problema, lo que apunta a algo mal en el extremo Gunicorn, no en el extremo Cloudfront.

@ExplodingCabbage ok Lo

3.6.8

Me doy cuenta de que omití un detalle de mi historia anterior: antes de reiniciar Gunicorn, también actualicé el certificado SSL que Gunicorn usa con LetsEncrypt. No había pensado en mencionar esto porque ayer había concluido erróneamente que no había forma de que un certificado hubiera caducado el día en que comenzaron los errores y que la actualización del certificado no había sido relevante para solucionar el problema.

Sin embargo, al revisar algunos registros, ahora me doy cuenta de que los errores de hecho comenzaron el día en que un certificado anterior vencía.

Todavía hay algo de misterio aquí, y un margen potencial de mejora (¿qué significa exactamente este error y por qué Gunicorn no puede dar un mensaje más útil?), Pero la narrativa que di antes, en la que este error comenzó de la nada. sin causa aparente, no es correcto. Supongo que CloudFront estaba terminando la conexión en respuesta a ver un certificado vencido del servidor de Gunicorn, y que Gunicorn, en lugar de poder entenderlo e informarlo de manera significativa, deja que surja un error OSError sin mensajes.

Pido disculpas por no tener mis patos en fila antes de informar. Por otro lado, tal vez esto facilite la reproducción de esta excepción a voluntad si desea intentar manejar el escenario de manera más elegante.

@ExplodingCabbage oh eso es bastante interesante, entonces debería ser reproducible en algún momento. ¡Gracias por los detalles adicionales!

Acabo de encontrarme reproducible con el mismo problema y estoy algo seguro de que es la consecuencia de algún tipo de agotamiento de recursos.

Para mí, se activó al olvidar un tiempo de espera en una llamada de bloqueo y las solicitudes se acumularon.

HTH

¡Hola! Estoy experimentando este problema exacto. Tengo un servicio gunicorn / flask ejecutándose en un clúster ECS detrás de un equilibrador de carga de red. Algunos detalles de la versión:

python    - 3.7.4
gunicorn  - 19.9.0
flask     - 1.0.4

El servicio puede responder a solicitudes provenientes de un cliente que usa TLS sin problemas, sin embargo, mis registros están inundados de OSErrors. Por lo que puedo decir, estos son el resultado de las solicitudes de verificación de estado que provienen del equilibrador de carga (TCP).

Pude reproducir el error localmente abriendo y cerrando una conexión TCP manualmente en el puerto de escucha (8000 en este caso):

$ nc -vz 127.0.0.1 8000
localhost [127.0.0.1] 8000 (irdmi) open

Lo que resultó en el siguiente error:

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 esto ayude!

Hmm, después de algunas investigaciones adicionales, parece que esto puede ser un error en la forma en que la biblioteca Python ssl maneja los EOF irregulares en Linux: https://bugs.python.org/issue31122

Como lo menciona @shevisjohnson, si ejecuta "nc -vz hostname port_no", aparece este error.
Podemos suprimir este error en el archivo de registro mediante el siguiente mecanismo de registro.

$ gato 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]

Aquí está el archivo de 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 eso ayude.

De forma intermitente, hemos observado que varias aplicaciones de Gunicorn fallan con este error en producción mientras se encuentran bajo carga simultánea.

Solo tomó un momento encontrar una reproducción confiable: usando hey para enviar 100 solicitudes simultáneas al último Gunicorn (20.0.4) usando el trabajador gthread :

$ hey -n 100 -c 100 https://127.0.0.1:8000

''
$ aplicación gunicorn
...
[2020-07-11 19:10:58 +0000] [3628247] [ERROR] Solicitud de procesamiento de error de socket.
Rastreo (llamadas recientes más última):
return self._sslobj.read (len)
OSError: [Errno 0] Error


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 ""

¡En caso de que esto también ayude!

Si la causa raíz es https://bugs.python.org/issue31122 :

  • Hubo una corrección enviada el 4 de marzo (python / cpython # 18772), pero aún no ha sido reconocida por un desarrollador central. ¿Quizás un mantenedor de Gunicorn que deje un comentario allí o en BPO-31122 diciendo que está afectando a los usuarios de Gunicorn ayudaría?
  • Gunicorn aún tendría que solucionar esto para las versiones compatibles de Python que son anteriores a la publicación de la corrección. ¿Vale la pena preguntar también si hay una solución alternativa en ese mismo comentario?

Esto también está afectando a mi organización en la producción.

Noté que la corrección de errores aterrizó en las ramas 3.8 y 3.9, pero están considerando <= 3.7 EOL y todavía estamos un poco atascados en 3.6 por el momento. ¿Existe una solución conocida para este problema en este momento en el propio gunicorn? ¿Hay algo planeado?

Estamos investigando qué podría estar llamando tanto al servicio para desencadenar esto, pero solo estoy tratando de averiguar qué se podría hacer, ya que esto da como resultado enormes picos de recursos en los nodos afectados.

Además del comentario de jriddy con respecto a la no intención de backport antes de 3.8, si alguien más tiene este problema, también tenga en cuenta que la solución está configurada para incluirse en CPython 3.8.6 .

Tengo problemas para decir exactamente de dónde emana este rastreo; en mi caso, usando gevent como servidor de aplicaciones WSGI directamente, suponiendo que sea una llamada de registro en algún lugar dentro de gevent / greenlet, pero no puedo encontrarla todavía. Para Gunicorn, sucede aquí, para los trabajadores sincrónicos:

https://github.com/benoitc/gunicorn/blob/e636bf81989bb833d2b99104feb11e86c3f2c43a/gunicorn/workers/sync.py#L150

En el caso de Gunicorn, si solo le preocupa el ruido en los registros, es posible que pueda hacer 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 relacionado con gevent: https://github.com/gevent/gevent/issues/1671

¿Fue útil esta página
0 / 5 - 0 calificaciones